blob: 7fe8cbd237acd5dad83cc5e1754639bd8acbb2a2 [file] [log] [blame]
/* ------------------------------------------------------------------
* Copyright (C) 2008 PacketVideo
* Copyright (C) 2008 HTC Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#ifndef PVMF_OMX_VIDEOENC_PORT_H_INCLUDED
#include "pvmf_omx_videoenc_port.h"
#endif
#ifndef OSCL_PRIQUEUE_H_INCLUDED
#include "oscl_priqueue.h"
#endif
#ifndef OSCL_MIME_STRING_UTILS_H
#include "pv_mime_string_utils.h"
#endif
#ifndef PVMF_OMX_VIDEOENC_NODE_TYPES_H_INCLUDED
#include "pvmf_omx_videoenc_node_types.h"
#endif
#ifndef PVMF_OMX_VIDEOENC_NODE_H_INCLUDED
#include "pvmf_omx_videoenc_node.h"
#endif
#define LOG_STACK_TRACE(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, m);
#define LOG_DEBUG(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, m);
#define LOG_ERR(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_REL,iLogger,PVLOGMSG_ERR,m);
////////////////////////////////////////////////////////////////////////////
PVMFVideoEncPort::PVMFVideoEncPort(int32 aTag, PVMFOMXVideoEncNode* aNode, int32 aPriority, const char* name)
: PvmfPortBaseImpl(aTag, this,
PVMF_OMX_VIDEOENC_PORT_CAPACITY, PVMF_OMX_VIDEOENC_PORT_RESERVE, PVMF_OMX_VIDEOENC_PORT_THRESHOLD,
PVMF_OMX_VIDEOENC_PORT_CAPACITY, PVMF_OMX_VIDEOENC_PORT_RESERVE, PVMF_OMX_VIDEOENC_PORT_THRESHOLD, name),
OsclActiveObject(aPriority, "PVMFVideoEncPort"),
iFormat(PVMF_FORMAT_UNKNOWN),
iNode(aNode)
{
AddToScheduler();
iLogger = PVLogger::GetLoggerObject("PVMFVideoEncPort");
#if PVMF_PORT_BASE_IMPL_STATS
oscl_memset((OsclAny*)&(PvmfPortBaseImpl::iStats), 0, sizeof(PvmfPortBaseImplStats));
#endif
}
////////////////////////////////////////////////////////////////////////////
PVMFVideoEncPort::~PVMFVideoEncPort()
{
Disconnect();
ClearMsgQueues();
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PVMFVideoEncPort::QueryInterface(const PVUuid& aUuid, OsclAny*& aPtr)
{
if(aUuid == PVMI_CAPABILITY_AND_CONFIG_PVUUID)
aPtr = (PvmiCapabilityAndConfig*)this;
else
aPtr = NULL;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMFVideoEncPort::Connect(PVMFPortInterface* aPort)
{
LOG_STACK_TRACE((0,"PVMFVideoEncPort::Connect: aPort=0x%x", aPort));
if(!aPort)
{
LOG_ERR((0,"PVMFVideoEncPort::Connect: Error - Connecting to invalid port"));
return PVMFErrArgument;
}
if(iConnectedPort)
{
LOG_ERR((0,"PVMFVideoEncPort::Connect: Error - Already connected"));
return PVMFFailure;
}
PvmiCapabilityAndConfig* config = NULL;
aPort->QueryInterface(PVMI_CAPABILITY_AND_CONFIG_PVUUID, (OsclAny*&)config);
if(!config)
{
LOG_ERR((0,"PVMFVideoEncPort::Connect: Error - Peer port does not support capability interface"));
return PVMFFailure;
}
PVMFStatus status = PVMFSuccess;
switch(iTag)
{
case PVMF_OMX_VIDEOENC_NODE_PORT_TYPE_INPUT:
status = NegotiateInputSettings(config);
break;
case PVMF_OMX_VIDEOENC_NODE_PORT_TYPE_OUTPUT:
status = NegotiateOutputSettings(config);
break;
default:
LOG_ERR((0,"PVMFVideoEncPort::Connect: Error - Invalid port tag"));
status = PVMFFailure;
}
if(status != PVMFSuccess)
{
LOG_ERR((0,"PVMFVideoEncPort::Connect: Error - Settings negotiation failed. status=%d",status));
return status;
}
//Automatically connect the peer.
if (aPort->PeerConnect(this)!=PVMFSuccess)
{
LOG_ERR((0,"PVMFVideoEncPort::Connect: Error - Peer Connect failed"));
return PVMFFailure;
}
iConnectedPort = aPort;
#if PVMF_PORT_BASE_IMPL_STATS
// Reset statistics
oscl_memset((OsclAny*)&(PvmfPortBaseImpl::iStats), 0, sizeof(PvmfPortBaseImplStats));
#endif
PortActivity(PVMF_PORT_ACTIVITY_CONNECT);
return PVMFSuccess;
}
////////////////////////////////////////////////////////////////////////////
// PvmiCapabilityAndConfig
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PVMFVideoEncPort::setObserver(PvmiConfigAndCapabilityCmdObserver* aObserver)
{
// Not supported
OSCL_UNUSED_ARG(aObserver);
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMFVideoEncPort::getParametersSync(PvmiMIOSession session,
PvmiKeyType identifier,
PvmiKvp*& parameters,
int& num_parameter_elements,
PvmiCapabilityContext context)
{
LOG_STACK_TRACE((0,"PVMFVideoEncPort::getParametersSync"));
OSCL_UNUSED_ARG(session);
OSCL_UNUSED_ARG(context);
parameters = NULL;
num_parameter_elements = 0;
PVMFStatus status = PVMFFailure;
switch(iTag)
{
case PVMF_OMX_VIDEOENC_NODE_PORT_TYPE_INPUT:
return GetInputParametersSync(identifier, parameters, num_parameter_elements);
case PVMF_OMX_VIDEOENC_NODE_PORT_TYPE_OUTPUT:
return GetOutputParametersSync(identifier, parameters, num_parameter_elements);
default:
LOG_ERR((0,"PVMFVideoEncPort::getParametersSync: Error - Invalid port tag"));
break;
}
return status;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMFVideoEncPort::releaseParameters(PvmiMIOSession session,
PvmiKvp* parameters,
int num_elements)
{
OSCL_UNUSED_ARG(session);
OSCL_UNUSED_ARG(num_elements);
if(parameters)
{
iAlloc.deallocate((OsclAny*)parameters);
return PVMFSuccess;
}
else
{
return PVMFFailure;
}
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PVMFVideoEncPort::createContext(PvmiMIOSession session, PvmiCapabilityContext& context)
{
OSCL_UNUSED_ARG(session);
OSCL_UNUSED_ARG(context);
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PVMFVideoEncPort::setContextParameters(PvmiMIOSession session,
PvmiCapabilityContext& context,
PvmiKvp* parameters, int num_parameter_elements)
{
OSCL_UNUSED_ARG(session);
OSCL_UNUSED_ARG(context);
OSCL_UNUSED_ARG(parameters);
OSCL_UNUSED_ARG(num_parameter_elements);
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PVMFVideoEncPort::DeleteContext(PvmiMIOSession session, PvmiCapabilityContext& context)
{
OSCL_UNUSED_ARG(session);
OSCL_UNUSED_ARG(context);
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PVMFVideoEncPort::setParametersSync(PvmiMIOSession session, PvmiKvp* parameters,
int num_elements, PvmiKvp*& ret_kvp)
{
OSCL_UNUSED_ARG(session);
PVMFStatus status = PVMFSuccess;
ret_kvp = NULL;
for(int32 i = 0; i < num_elements; i++)
{
status = VerifyAndSetParameter(&(parameters[i]), true);
if(status != PVMFSuccess)
{
LOG_ERR((0,"PVMFVideoEncPort::setParametersSync: Error - VerifiyAndSetParameter failed on parameter #%d", i));
ret_kvp = &(parameters[i]);
OSCL_LEAVE(OsclErrArgument);
}
}
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMFVideoEncPort::setParametersAsync(PvmiMIOSession session,
PvmiKvp* parameters,
int num_elements,
PvmiKvp*& ret_kvp,
OsclAny* context)
{
OSCL_UNUSED_ARG(session);
OSCL_UNUSED_ARG(parameters);
OSCL_UNUSED_ARG(num_elements);
OSCL_UNUSED_ARG(ret_kvp);
OSCL_UNUSED_ARG(context);
return -1;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF uint32 PVMFVideoEncPort::getCapabilityMetric (PvmiMIOSession session)
{
OSCL_UNUSED_ARG(session);
return 0;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMFVideoEncPort::verifyParametersSync(PvmiMIOSession session,
PvmiKvp* parameters, int num_elements)
{
OSCL_UNUSED_ARG(session);
PVMFStatus status = PVMFSuccess;
for(int32 i = 0; (i < num_elements) && (status == PVMFSuccess); i++)
status = VerifyAndSetParameter(&(parameters[i]));
return status;
}
////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFVideoEncPort::SetFormat(PVMFFormatType aFormat)
{
LOG_STACK_TRACE((0,"PVMFVideoEncPort::SetFormat: aFormat=%d", aFormat));
if(!IsFormatSupported(aFormat))
return PVMFFailure;
iFormat = aFormat;
return PVMFSuccess;
}
////////////////////////////////////////////////////////////////////////////
void PVMFVideoEncPort::ProcessIncomingMsgReady()
{
if(IncomingMsgQueueSize() > 0)
RunIfNotReady();
}
////////////////////////////////////////////////////////////////////////////
void PVMFVideoEncPort::ProcessOutgoingMsgReady()
{
if(OutgoingMsgQueueSize() > 0)
RunIfNotReady();
}
////////////////////////////////////////////////////////////////////////////
// Pure virtuals from PVMFPortActivityHandler
////////////////////////////////////////////////////////////////////////////
void PVMFVideoEncPort::HandlePortActivity(const PVMFPortActivity& aActivity)
{
LOG_STACK_TRACE((0,"PVMFVideoEncPort::HandlePortActivity: type=%d", aActivity.iType));
if(aActivity.iPort != this)
{
LOG_ERR((0,"PVMFVideoEncPort::HandlePortActivity: Error - Activity is not on this port"));
return;
}
switch(aActivity.iType)
{
case PVMF_PORT_ACTIVITY_CREATED:
//Report port created info event to the node.
iNode->ReportInfoEvent(PVMFInfoPortCreated,
(OsclAny*)aActivity.iPort);
break;
case PVMF_PORT_ACTIVITY_DELETED:
//Report port deleted info event to the node.
iNode->ReportInfoEvent(PVMFInfoPortDeleted,
(OsclAny*)aActivity.iPort);
break;
case PVMF_PORT_ACTIVITY_OUTGOING_MSG:
// Wakeup the AO on the first message only. After that it re-schedules itself as needed.
if( OutgoingMsgQueueSize() == 1 &&
!IsConnectedPortBusy())
{
RunIfNotReady();
}
break;
case PVMF_PORT_ACTIVITY_INCOMING_MSG:
//Wakeup the AO on the first message only. After that it re-schedules itself as needed.
if(IncomingMsgQueueSize() == 1 &&
iNode->IsProcessIncomingMsgReady())
{
RunIfNotReady();
}
break;
case PVMF_PORT_ACTIVITY_OUTGOING_QUEUE_BUSY:
// This is handled in the input port side when IsProcessIncomingMsgReady call failed
break;
case PVMF_PORT_ACTIVITY_OUTGOING_QUEUE_READY:
// Notifies the node that the output queue is ready, and the node would
// resume encoding incoming data
iNode->HandlePortActivity(aActivity);
break;
case PVMF_PORT_ACTIVITY_CONNECTED_PORT_READY:
if(OutgoingMsgQueueSize() > 0)
RunIfNotReady();
break;
case PVMF_PORT_ACTIVITY_CONNECTED_PORT_BUSY:
// This is handled when iNode->ProcessOutgoingMsg failed with busy
break;
case PVMF_PORT_ACTIVITY_CONNECT:
case PVMF_PORT_ACTIVITY_DISCONNECT:
default:
break;
}
//Holmes add
iNode->HandlePortActivity(aActivity);
}
////////////////////////////////////////////////////////////////////////////
// Pure virtuals from OsclActiveObject
////////////////////////////////////////////////////////////////////////////
void PVMFVideoEncPort::Run()
{
LOG_STACK_TRACE((0,"PVMFVideoEncPort::Run"));
PVMFStatus status = PVMFSuccess;
// Process incoming messages
if(iTag == PVMF_OMX_VIDEOENC_NODE_PORT_TYPE_INPUT)
{
if(IncomingMsgQueueSize() > 0)
{
//dispatch the incoming data.
status = iNode->ProcessIncomingMsg(this);
switch(status)
{
case PVMFSuccess:
// Reschedule if there is more data and the node did not become busy
// after processing the current msg
if(IncomingMsgQueueSize() > 0 && iNode->IsProcessIncomingMsgReady())
{
RunIfNotReady();
}
break;
case PVMFErrBusy:
// Node busy. Don't schedule next data
break;
default:
LOG_ERR((0,"PVMFVideoEncPort::Run: Error - ProcessIncomingMsg failed. status=%d", status));
break;
}
}
if(iNode->IsFlushPending())
{
if(IncomingMsgQueueSize() == 0 && OutgoingMsgQueueSize() == 0)
iNode->FlushComplete();
}
}
//Process outgoing messages
if(iTag == PVMF_OMX_VIDEOENC_NODE_PORT_TYPE_OUTPUT)
{
if(OutgoingMsgQueueSize() > 0)
{
if(iNode->IsProcessOutgoingMsgReady())
{
//Send data to connected port
status = Send();
switch(status)
{
case PVMFSuccess:
// Reschedule if there's more data to process and connected port did not become busy
// after receiving the last msg
if(OutgoingMsgQueueSize() > 0 && iNode->IsProcessOutgoingMsgReady())
{
RunIfNotReady();
}
break;
case PVMFErrBusy:
// Connected port busy. Don't schedule next data
break;
default:
LOG_ERR((0, "PVMFVideoEncPort::Run: Error - Send() failed. status=%d", status));
iNode->ReportErrorEvent(PVMF_OMX_VIDEOENC_NODE_ERROR_ENCODE_ERROR, (OsclAny*)this);
break;
}
if(iNode->IsFlushPending())
{
if(IncomingMsgQueueSize() == 0 && OutgoingMsgQueueSize() == 0)
iNode->FlushComplete();
}
}
}
if(iNode->IsFlushPending())
{
if(IncomingMsgQueueSize() == 0 && OutgoingMsgQueueSize() == 0)
iNode->FlushComplete();
}
}
}
////////////////////////////////////////////////////////////////////////////
// Capabilities exchange handling routines
////////////////////////////////////////////////////////////////////////////
bool PVMFVideoEncPort::IsFormatSupported(PVMFFormatType aFormat)
{
if(iTag == PVMF_OMX_VIDEOENC_NODE_PORT_TYPE_INPUT)
{
switch(aFormat)
{
case PVMF_YUV420:
case PVMF_YUV422:
case PVMF_RGB12:
case PVMF_RGB24:
return true;
default:
break;
}
}
else if(iTag == PVMF_OMX_VIDEOENC_NODE_PORT_TYPE_OUTPUT)
{
switch(aFormat)
{
case PVMF_H263:
case PVMF_M4V:
return true;
default:
break;
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFVideoEncPort::GetInputParametersSync(PvmiKeyType identifier, PvmiKvp*& parameters,
int& num_parameter_elements)
{
if(iTag != PVMF_OMX_VIDEOENC_NODE_PORT_TYPE_INPUT)
return PVMFFailure;
PVMFStatus status = PVMFSuccess;
if(pv_mime_strcmp(identifier, INPUT_FORMATS_CAP_QUERY) == 0)
{
num_parameter_elements = 4;
status = AllocateKvp(parameters, INPUT_FORMATS_VALTYPE, num_parameter_elements);
if(status != PVMFSuccess)
{
LOG_ERR((0,"PVMFVideoEncPort::GetInputParametersSync: Error - AllocateKvp failed. status=%d",status));
return status;
}
parameters[0].value.uint32_value = PVMF_YUV420;
parameters[1].value.uint32_value = PVMF_YUV422;
parameters[2].value.uint32_value = PVMF_RGB12;
parameters[3].value.uint32_value = PVMF_RGB24;
}
return status;
}
////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFVideoEncPort::GetOutputParametersSync(PvmiKeyType identifier, PvmiKvp*& parameters,
int& num_parameter_elements)
{
if(iTag != PVMF_OMX_VIDEOENC_NODE_PORT_TYPE_OUTPUT)
return PVMFFailure;
PVMFStatus status = PVMFSuccess;
if(pv_mime_strcmp(identifier, OUTPUT_FORMATS_CAP_QUERY) == 0)
{
num_parameter_elements = 2;
status = AllocateKvp(parameters, OUTPUT_FORMATS_VALTYPE, num_parameter_elements);
if(status != PVMFSuccess)
{
LOG_ERR((0,"PVMFVideoEncPort::GetOutputParametersSync: Error - AllocateKvp failed. status=%d",status));
}
else
{
parameters[0].value.uint32_value = PVMF_H263;
parameters[1].value.uint32_value = PVMF_M4V;
}
}
else if(pv_mime_strcmp(identifier, OUTPUT_FORMATS_CUR_QUERY) == 0)
{
num_parameter_elements = 1;
status = AllocateKvp(parameters, OUTPUT_FORMATS_VALTYPE, num_parameter_elements);
if(status != PVMFSuccess)
{
LOG_ERR((0,"PVMFVideoEncPort::GetOutputParametersSync: Error - AllocateKvp failed. status=%d",status));
}
else
{
parameters[0].value.uint32_value = iNode->GetCodecType();
}
}
else if(pv_mime_strcmp(identifier, VIDEO_OUTPUT_WIDTH_CUR_QUERY) == 0)
{
num_parameter_elements = 1;
status = AllocateKvp(parameters, VIDEO_OUTPUT_WIDTH_CUR_VALUE, num_parameter_elements);
if(status != PVMFSuccess)
{
LOG_ERR((0,"PVMFVideoEncPort::GetOutputParametersSync: Error - AllocateKvp failed. status=%d",status));
return status;
}
uint32 width, height;
status = iNode->GetOutputFrameSize(0, width, height);
if(status != PVMFSuccess)
{
LOG_ERR((0,"PVMFVideoEncPort::GetOutputParametersSync: Error -iNode->GetOutputFrameSize failed. status=%d",status));
}
else
{
parameters[0].value.uint32_value = width;
}
}
else if(pv_mime_strcmp(identifier, VIDEO_OUTPUT_HEIGHT_CUR_QUERY) == 0)
{
num_parameter_elements = 1;
status = AllocateKvp(parameters, VIDEO_OUTPUT_HEIGHT_CUR_VALUE, num_parameter_elements);
if(status != PVMFSuccess)
{
LOG_ERR((0,"PVMFVideoEncPort::GetOutputParametersSync: Error - AllocateKvp failed. status=%d",status));
return status;
}
else
{
uint32 width, height;
status = iNode->GetOutputFrameSize(0, width, height);
if(status != PVMFSuccess)
{
LOG_ERR((0,"PVMFVideoEncPort::GetOutputParametersSync: Error - iNode->GetOutputFrameSize failed. status=%d",status));
}
else
{
parameters[0].value.uint32_value = height;
}
}
}
else if(pv_mime_strcmp(identifier, VIDEO_OUTPUT_FRAME_RATE_CUR_QUERY) == 0)
{
num_parameter_elements = 1;
status = AllocateKvp(parameters, VIDEO_OUTPUT_FRAME_RATE_CUR_VALUE, num_parameter_elements);
if(status != PVMFSuccess)
{
LOG_ERR((0,"PVMFVideoEncPort::GetOutputParametersSync: Error - AllocateKvp failed. status=%d",status));
return status;
}
else
{
parameters[0].value.float_value = iNode->GetOutputFrameRate(0);
}
}
else if(pv_mime_strcmp(identifier, OUTPUT_BITRATE_CUR_QUERY) == 0)
{
num_parameter_elements = 1;
status = AllocateKvp(parameters, OUTPUT_BITRATE_CUR_VALUE, num_parameter_elements);
if(status != PVMFSuccess)
{
LOG_ERR((0,"PVMFVideoEncPort::GetOutputParametersSync: Error - AllocateKvp failed. status=%d",status));
return status;
}
else
{
parameters[0].value.uint32_value = iNode->GetOutputBitRate(0);
}
}
else if(pv_mime_strcmp(identifier, VIDEO_OUTPUT_IFRAME_INTERVAL_CUR_QUERY) == 0)
{
num_parameter_elements = 1;
status = AllocateKvp(parameters, VIDEO_OUTPUT_IFRAME_INTERVAL_CUR_VALUE, num_parameter_elements);
if(status != PVMFSuccess)
{
LOG_ERR((0,"PVMFVideoEncPort::GetOutputParametersSync: Error - AllocateKvp failed. status=%d",status));
return status;
}
else
{
parameters[0].value.uint32_value = iNode->GetIFrameInterval();
}
}
return status;
}
////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFVideoEncPort::AllocateKvp(PvmiKvp*& aKvp, PvmiKeyType aKey, int32 aNumParams)
{
LOG_STACK_TRACE((0, "PVMFVideoEncPort::AllocateKvp"));
uint8* buf = NULL;
uint32 keyLen = oscl_strlen(aKey) + 1;
int32 err = 0;
OSCL_TRY(err,
buf = (uint8*)iAlloc.allocate(aNumParams * (sizeof(PvmiKvp) + keyLen));
if(!buf)
OSCL_LEAVE(OsclErrNoMemory);
);
OSCL_FIRST_CATCH_ANY(err,
LOG_ERR((0,"PVMFVideoEncPort::AllocateKvp: Error - kvp allocation failed"));
return PVMFErrNoMemory;
);
int32 i = 0;
PvmiKvp* curKvp = aKvp = new (buf) PvmiKvp;
buf += sizeof(PvmiKvp);
for(i = 1; i < aNumParams; i++)
{
curKvp += i;
curKvp = new (buf) PvmiKvp;
buf += sizeof(PvmiKvp);
}
for(i = 0; i < aNumParams; i++)
{
aKvp[i].key = (char*)buf;
oscl_strncpy(aKvp[i].key, aKey, keyLen);
buf += keyLen;
}
return PVMFSuccess;
}
////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFVideoEncPort::VerifyAndSetParameter(PvmiKvp* aKvp, bool aSetParam)
{
LOG_STACK_TRACE((0,"PVMFVideoEncPort::VerifyAndSetParameter: aKvp=0x%x, aSetParam=%d", aKvp, aSetParam));
if(!aKvp)
{
LOG_ERR((0, "PVMFVideoEncPort::VerifyAndSetParameter: Error - Invalid key-value pair"));
return PVMFFailure;
}
if( pv_mime_strcmp(aKvp->key, INPUT_FORMATS_VALTYPE) == 0 &&
iTag == PVMF_OMX_VIDEOENC_NODE_PORT_TYPE_INPUT)
{
switch(aKvp->value.uint32_value)
{
case PVMF_YUV420:
case PVMF_YUV422:
case PVMF_RGB12:
case PVMF_RGB24:
if(aSetParam)
{
iFormat = aKvp->value.uint32_value;
iNode->SetInputFormat(iFormat);
}
return PVMFSuccess;
default:
LOG_ERR((0, "PVMFVideoEncPort::VerifyAndSetParameter: Error - Input format %d not supported",
aKvp->value.uint32_value));
return PVMFFailure;
}
}
else if(pv_mime_strcmp(aKvp->key, OUTPUT_FORMATS_VALTYPE) == 0 &&
iTag == PVMF_OMX_VIDEOENC_NODE_PORT_TYPE_OUTPUT)
{
switch(aKvp->value.uint32_value)
{
case PVMF_H263:
case PVMF_M4V:
if(aSetParam)
{
iFormat = aKvp->value.uint32_value;
iNode->SetCodecType(iFormat);
}
return PVMFSuccess;
default:
LOG_ERR((0, "PVMFVideoEncPort::VerifyAndSetParameter: Error - Output format %d not supported",
aKvp->value.uint32_value));
return PVMFFailure;
}
}
LOG_ERR((0,"PVMFVideoEncPort::VerifyAndSetParameter: Error - Unsupported parameter"));
return PVMFFailure;
}
////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFVideoEncPort::NegotiateInputSettings(PvmiCapabilityAndConfig* aConfig)
{
LOG_STACK_TRACE((0,"PVMFVideoEncPort::NegotiateInputSettings: aConfig=0x%x", aConfig));
if(!aConfig)
{
LOG_ERR((0,"PVMFVideoEncPort::NegotiateInputSettings: Error - Invalid config object"));
return PVMFFailure;
}
PvmiKvp* kvp = NULL;
int numParams = 0;
int32 err = 0;
uint32 videoFormat;
// Get supported output formats from peer
PVMFStatus status = aConfig->getParametersSync(NULL, OUTPUT_FORMATS_CAP_QUERY, kvp, numParams, NULL);
if(status != PVMFSuccess || numParams == 0)
{
LOG_ERR((0,"PVMFVideoEncPort::NegotiateInputSettings: Error - config->getParametersSync(output_formats) failed"));
return status;
}
OsclPriorityQueue<PvmiKvp*,OsclMemAllocator,
Oscl_Vector<PvmiKvp*,OsclMemAllocator>,
PVMFVideoEncInputFormatCompareLess> sortedKvp;
// Using a priority queue, sort the kvp's returned from aConfig->getParametersSync
// according to the preference of this port. Formats that are not supported are
// not pushed to the priority queue and hence dropped from consideration.
for(int32 i = 0; i < numParams; i++)
{
switch(kvp[i].value.uint32_value)
{
case PVMF_YUV420:
case PVMF_YUV422:
case PVMF_RGB12:
case PVMF_RGB24:
{
videoFormat = kvp[i].value.uint32_value;
OSCL_TRY(err, sortedKvp.push(&(kvp[i])););
OSCL_FIRST_CATCH_ANY(err,
LOG_ERR((0, "PVMFVideoEncPort::NegotiateInputSettings: Error - sortedKvp.push failed"));
return PVMFErrNoMemory;
);
}
break;
default:
break;
}
}
if(sortedKvp.size() == 0)
{
LOG_ERR((0, "PVMFVideoEncPort::NegotiateInputSettings: Error - No matching supported input format"));
// Release parameters back to peer
aConfig->releaseParameters(NULL, kvp, numParams);
kvp = NULL;
numParams = 0;
return PVMFFailure;
}
PvmiKvp* selectedKvp = sortedKvp.top();
PvmiKvp* retKvp = NULL;
// Set format of this port, peer port and container node
iFormat = selectedKvp->value.uint32_value;
iNode->SetInputFormat(iFormat);
OSCL_TRY(err, aConfig->setParametersSync(NULL, selectedKvp, 1, retKvp););
OSCL_FIRST_CATCH_ANY(err,
LOG_ERR((0,"PVMFVideoEncPort::NegotiateInputSettings: Error - aConfig->setParametersSync failed. err=%d", err));
return PVMFFailure;
);
// Release parameters back to peer and reset for the next query
aConfig->releaseParameters(NULL, kvp, numParams);
kvp = NULL;
numParams = 0;
// Get size (in pixels) of video data from peer
uint32 width = 0;
uint32 height = 0;
uint8 orientation = 0;
status = aConfig->getParametersSync(NULL, VIDEO_OUTPUT_WIDTH_CUR_QUERY, kvp, numParams, NULL);
if(status != PVMFSuccess || numParams != 1)
{
LOG_ERR((0,"PVMFVideoEncPort::Connect: Error - config->getParametersSync(current width) failed"));
return status;
}
width = kvp[0].value.uint32_value;
aConfig->releaseParameters(NULL, kvp, numParams);
kvp = NULL;
numParams = 0;
status = aConfig->getParametersSync(NULL, VIDEO_OUTPUT_HEIGHT_CUR_QUERY, kvp, numParams, NULL);
if(status != PVMFSuccess || numParams != 1)
{
LOG_ERR((0,"PVMFVideoEncPort::Connect: Error - config->getParametersSync(current height) failed"));
return status;
}
height = kvp[0].value.uint32_value;
aConfig->releaseParameters(NULL, kvp, numParams);
kvp = NULL;
numParams = 0;
if ((PVMF_RGB12 == videoFormat) || (PVMF_RGB24 == videoFormat))
{
status = aConfig->getParametersSync(NULL, VIDEO_FRAME_ORIENTATION_CUR_QUERY, kvp, numParams, NULL);
if(status != PVMFSuccess || numParams != 1)
{
LOG_ERR((0,"PVMFVideoEncPort::Connect: Error - config->getParametersSync(current height) failed"));
return status;
}
orientation = kvp[0].value.uint8_value;
aConfig->releaseParameters(NULL, kvp, numParams);
kvp = NULL;
numParams = 0;
}
// Set input frame size of container node
iNode->SetInputFrameSize(width, height, orientation);
// Get video frame rate from peer
status = aConfig->getParametersSync(NULL, VIDEO_OUTPUT_FRAME_RATE_CUR_QUERY, kvp, numParams, NULL);
if(status != PVMFSuccess || numParams != 1)
{
LOG_ERR((0,"PVMFVideoEncPort::Connect: Error - config->getParametersSync(current frame rate) failed"));
return status;
}
// Set input frame rate of container node
iNode->SetInputFrameRate(kvp[0].value.float_value);
aConfig->releaseParameters(NULL, kvp, numParams);
kvp = NULL;
numParams = 0;
return status;
}
////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFVideoEncPort::NegotiateOutputSettings(PvmiCapabilityAndConfig* aConfig)
{
LOG_STACK_TRACE((0,"PVMFVideoEncPort::NegotiateOutputSettings: aConfig=0x%x", aConfig));
if(!aConfig)
{
LOG_ERR((0,"PVMFVideoEncPort::NegotiateOutputSettings: Error - Invalid config object"));
return PVMFFailure;
}
PvmiKvp* kvp = NULL;
int numParams = 0;
int32 i = 0;
int32 err = 0;
// Get supported input formats from peer
PVMFStatus status = aConfig->getParametersSync(NULL, INPUT_FORMATS_CAP_QUERY, kvp, numParams, NULL);
if(status != PVMFSuccess || numParams == 0)
{
LOG_ERR((0,"PVMFVideoEncPort::NegotiateOutputSettings: Error - config->getParametersSync(input_formats) failed"));
return status;
}
PvmiKvp* selectedKvp = NULL;
PvmiKvp* retKvp = NULL;
for(i = 0; i < numParams && !selectedKvp; i++)
{
if(kvp[i].value.uint32_value == iFormat)
selectedKvp = &(kvp[i]);
}
if(!selectedKvp)
{
LOG_ERR((0,"PVMFVideoEncPort::NegotiateOutputSettings: Error - Output format not supported by peer"));
return PVMFFailure;
}
OSCL_TRY(err, aConfig->setParametersSync(NULL, selectedKvp, 1, retKvp););
OSCL_FIRST_CATCH_ANY(err,
LOG_ERR((0,"PVMFVideoEncPort::NegotiateOutputSettings: Error - aConfig->setParametersSync failed. err=%d", err));
return PVMFFailure;
);
aConfig->releaseParameters(NULL, kvp, numParams);
kvp = NULL;
numParams = 0;
return PVMFSuccess;
}