blob: 61aa7b082fb5476b17fafe50ab78b6776582a82b [file] [log] [blame]
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* 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.
* -------------------------------------------------------------------
*/
#include "pvmf_omx_enc_node.h"
#include "pvlogger.h"
#include "oscl_error_codes.h"
#include "pvmf_omx_enc_port.h"
#include "pv_mime_string_utils.h"
#include "oscl_snprintf.h"
#include "pvmf_media_cmd.h"
#include "pvmf_media_msg_format_ids.h"
#include "pvmi_kvp_util.h"
#ifdef _DEBUG
#include <stdio.h>
#endif
#include "OMX_Core.h"
#include "pvmf_omx_enc_callbacks.h" //used for thin AO in encoder's callbacks
#include "pv_omxcore.h"
#define CONFIG_SIZE_AND_VERSION(param) \
param.nSize=sizeof(param); \
param.nVersion.s.nVersionMajor = SPECVERSIONMAJOR; \
param.nVersion.s.nVersionMinor = SPECVERSIONMINOR; \
param.nVersion.s.nRevision = SPECREVISION; \
param.nVersion.s.nStep = SPECSTEP;
#define CHECK_OMX_ERR_AND_RETURN(Err, str) \
if (Err != OMX_ErrorNone) \
{ \
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, str)); \
}
#define PVOMXENC_EXTRA_YUVBUFFER_POOLNUM 3
#define PVOMXENC_MEDIADATA_POOLNUM (PVOMXENCMAXNUMDPBFRAMESPLUS1 + PVOMXENC_EXTRA_YUVBUFFER_POOLNUM)
#define PVOMXENC_MEDIADATA_CHUNKSIZE 128
#include "utils/Log.h"
#undef LOG_TAG
#define LOG_TAG "PVOMXEncNode"
const uint32 DEFAULT_VOL_HEADER_LENGTH = 28;
const uint8 DEFAULT_VOL_HEADER[DEFAULT_VOL_HEADER_LENGTH] =
{
0x00, 0x00, 0x01, 0xB0, 0x08, 0x00, 0x00, 0x01,
0xB5, 0x09, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x20, 0x00, 0x84, 0x40, 0xFA, 0x28, 0x2C,
0x20, 0x90, 0xA2, 0x1F
};
#ifdef _TEST_AE_ERROR_HANDLING
const uint32 FAIL_NODE_CMD_START = 2;
const uint32 FAIL_NODE_CMD_STOP = 3;
const uint32 FAIL_NODE_CMD_FLUSH = 4;
const uint32 FAIL_NODE_CMD_PAUSE = 5;
const uint32 FAIL_NODE_CMD_RELEASE_PORT = 7;
#endif
#define PVMF_OMXENC_NUM_METADATA_VALUES 6
// Constant character strings for metadata keys
static const char PVOMXENCMETADATA_CODECINFO_VIDEO_FORMAT_KEY[] = "codec-info/video/format";
static const char PVOMXENCMETADATA_CODECINFO_VIDEO_WIDTH_KEY[] = "codec-info/video/width";
static const char PVOMXENCMETADATA_CODECINFO_VIDEO_HEIGHT_KEY[] = "codec-info/video/height";
static const char PVOMXENCMETADATA_CODECINFO_VIDEO_PROFILE_KEY[] = "codec-info/video/profile";
static const char PVOMXENCMETADATA_CODECINFO_VIDEO_LEVEL_KEY[] = "codec-info/video/level";
static const char PVOMXENCMETADATA_CODECINFO_VIDEO_AVGBITRATE_KEY[] = "codec-info/video/avgbitrate";//(bits per sec)
static const char PVOMXENCMETADATA_SEMICOLON[] = ";";
static const char LOG_ID_AUDIO_AMRNB[] = "Audio_AMRNB";
static const char LOG_ID_AUDIO_AMRWB[] = "Audio_AMRWB";
static const char LOG_ID_AUDIO_AAC[] = "Audio_AAC";
static const char LOG_ID_VIDEO_H263[] = "Video_H263";
static const char LOG_ID_VIDEO_M4V[] = "Video_M4V";
static const char LOG_ID_VIDEO_AVC[] = "Video_AVC";
static const char LOG_ID_UNKNOWN[] = "TypeNotSetYet";
// OMX CALLBACKS
// 1) AO OMX component running in the same thread as the OMX node
// In this case, the callbacks can be called directly from the component
// The callback: OMX Component->CallbackEventHandler->EventHandlerProcessing
// The callback can perform do RunIfNotReady
// 2) Multithreaded component
// In this case, the callback is made using the threadsafe callback (TSCB) AO
// Component thread : OMX Component->CallbackEventHandler->TSCB(ReceiveEvent) => event is queued
// Node thread : dequeue event => TSCB(ProcessEvent)->ProcessCallbackEventHandler->EventHandlerProcessing
// callback for Event Handler - in multithreaded case, event is queued to be processed later
// in AO case, event is processed immediately by calling EventHandlerProcessing
OMX_ERRORTYPE CallbackEventHandlerEnc(OMX_OUT OMX_HANDLETYPE aComponent,
OMX_OUT OMX_PTR aAppData,
OMX_OUT OMX_EVENTTYPE aEvent,
OMX_OUT OMX_U32 aData1,
OMX_OUT OMX_U32 aData2,
OMX_OUT OMX_PTR aEventData)
{
PVMFOMXEncNode *Node = (PVMFOMXEncNode *) aAppData;
if (Node->IsComponentMultiThreaded())
{
// allocate the memory for the callback event specific data
//EventHandlerSpecificData* ED = (EventHandlerSpecificData*) oscl_malloc(sizeof (EventHandlerSpecificData));
EventHandlerSpecificData* ED = (EventHandlerSpecificData*) Node->iThreadSafeHandlerEventHandler->iMemoryPool->allocate(sizeof(EventHandlerSpecificData));
// pack the relevant data into the structure
ED->hComponent = aComponent;
ED->pAppData = aAppData;
ED->eEvent = aEvent;
ED->nData1 = aData1;
ED->nData2 = aData2;
ED->pEventData = aEventData;
// convert the pointer into OsclAny ptr
OsclAny* P = (OsclAny*) ED;
// CALL the generic callback AO API:
Node->iThreadSafeHandlerEventHandler->ReceiveEvent(P);
return OMX_ErrorNone;
}
else
{
OMX_ERRORTYPE status;
status = Node->EventHandlerProcessing(aComponent, aAppData, aEvent, aData1, aData2, aEventData);
return status;
}
}
// callback for EmptyBufferDone - in multithreaded case, event is queued to be processed later
// in AO case, event is processed immediately by calling EmptyBufferDoneProcessing
OMX_ERRORTYPE CallbackEmptyBufferDoneEnc(OMX_OUT OMX_HANDLETYPE aComponent,
OMX_OUT OMX_PTR aAppData,
OMX_OUT OMX_BUFFERHEADERTYPE* aBuffer)
{
PVMFOMXEncNode *Node = (PVMFOMXEncNode *) aAppData;
if (Node->IsComponentMultiThreaded())
{
// allocate the memory for the callback event specific data
//EmptyBufferDoneSpecificData* ED = (EmptyBufferDoneSpecificData*) oscl_malloc(sizeof (EmptyBufferDoneSpecificData));
EmptyBufferDoneSpecificData* ED = (EmptyBufferDoneSpecificData*) Node->iThreadSafeHandlerEmptyBufferDone->iMemoryPool->allocate(sizeof(EmptyBufferDoneSpecificData));
// pack the relevant data into the structure
ED->hComponent = aComponent;
ED->pAppData = aAppData;
ED->pBuffer = aBuffer;
// convert the pointer into OsclAny ptr
OsclAny* P = (OsclAny*) ED;
// CALL the generic callback AO API:
Node->iThreadSafeHandlerEmptyBufferDone->ReceiveEvent(P);
return OMX_ErrorNone;
}
else
{
OMX_ERRORTYPE status;
status = Node->EmptyBufferDoneProcessing(aComponent, aAppData, aBuffer);
return status;
}
}
// callback for FillBufferDone - in multithreaded case, event is queued to be processed later
// in AO case, event is processed immediately by calling FillBufferDoneProcessing
OMX_ERRORTYPE CallbackFillBufferDoneEnc(OMX_OUT OMX_HANDLETYPE aComponent,
OMX_OUT OMX_PTR aAppData,
OMX_OUT OMX_BUFFERHEADERTYPE* aBuffer)
{
PVMFOMXEncNode *Node = (PVMFOMXEncNode *) aAppData;
if (Node->IsComponentMultiThreaded())
{
// allocate the memory for the callback event specific data
//FillBufferDoneSpecificData* ED = (FillBufferDoneSpecificData*) oscl_malloc(sizeof (FillBufferDoneSpecificData));
FillBufferDoneSpecificData* ED = (FillBufferDoneSpecificData*) Node->iThreadSafeHandlerFillBufferDone->iMemoryPool->allocate(sizeof(FillBufferDoneSpecificData));
// pack the relevant data into the structure
ED->hComponent = aComponent;
ED->pAppData = aAppData;
ED->pBuffer = aBuffer;
// convert the pointer into OsclAny ptr
OsclAny* P = (OsclAny*) ED;
// CALL the generic callback AO API:
Node->iThreadSafeHandlerFillBufferDone->ReceiveEvent(P);
return OMX_ErrorNone;
}
else
{
OMX_ERRORTYPE status;
status = Node->FillBufferDoneProcessing(aComponent, aAppData, aBuffer);
return status;
}
}
// Callback processing in multithreaded case - dequeued event - call EventHandlerProcessing
OsclReturnCode PVMFOMXEncNode::ProcessCallbackEventHandler_MultiThreaded(OsclAny* P)
{
// re-cast the pointer
EventHandlerSpecificData* ED = (EventHandlerSpecificData*) P;
OMX_HANDLETYPE aComponent = ED->hComponent;
OMX_PTR aAppData = ED->pAppData;
OMX_EVENTTYPE aEvent = ED->eEvent;
OMX_U32 aData1 = ED->nData1;
OMX_U32 aData2 = ED->nData2;
OMX_PTR aEventData = ED->pEventData;
EventHandlerProcessing(aComponent, aAppData, aEvent, aData1, aData2, aEventData);
// release the allocated memory when no longer needed
iThreadSafeHandlerEventHandler->iMemoryPool->deallocate(ED);
ED = NULL;
return OsclSuccess;
}
// Callback processing in multithreaded case - dequeued event - call EmptyBufferDoneProcessing
OsclReturnCode PVMFOMXEncNode::ProcessCallbackEmptyBufferDone_MultiThreaded(OsclAny* P)
{
// re-cast the pointer
EmptyBufferDoneSpecificData* ED = (EmptyBufferDoneSpecificData*) P;
OMX_HANDLETYPE aComponent = ED->hComponent;
OMX_PTR aAppData = ED->pAppData;
OMX_BUFFERHEADERTYPE* aBuffer = ED->pBuffer;
EmptyBufferDoneProcessing(aComponent, aAppData, aBuffer);
// release the allocated memory when no longer needed
iThreadSafeHandlerEmptyBufferDone->iMemoryPool->deallocate(ED);
ED = NULL;
return OsclSuccess;
}
// Callback processing in multithreaded case - dequeued event - call FillBufferDoneProcessing
OsclReturnCode PVMFOMXEncNode::ProcessCallbackFillBufferDone_MultiThreaded(OsclAny* P)
{
// re-cast the pointer
FillBufferDoneSpecificData* ED = (FillBufferDoneSpecificData*) P;
OMX_HANDLETYPE aComponent = ED->hComponent;
OMX_PTR aAppData = ED->pAppData;
OMX_BUFFERHEADERTYPE* aBuffer = ED->pBuffer;
FillBufferDoneProcessing(aComponent, aAppData, aBuffer);
// release the allocated memory when no longer needed
iThreadSafeHandlerFillBufferDone->iMemoryPool->deallocate(ED);
ED = NULL;
return OsclSuccess;
}
/////////////////////////////////////////////////////////////////////////////
// Class Destructor
/////////////////////////////////////////////////////////////////////////////
PVMFOMXEncNode::~PVMFOMXEncNode()
{
LogDiagnostics();
//Clearup encoder
DeleteOMXEncoder();
// Cleanup callback AOs and Mempools
if (iThreadSafeHandlerEventHandler)
{
OSCL_DELETE(iThreadSafeHandlerEventHandler);
iThreadSafeHandlerEventHandler = NULL;
}
if (iThreadSafeHandlerEmptyBufferDone)
{
OSCL_DELETE(iThreadSafeHandlerEmptyBufferDone);
iThreadSafeHandlerEmptyBufferDone = NULL;
}
if (iThreadSafeHandlerFillBufferDone)
{
OSCL_DELETE(iThreadSafeHandlerFillBufferDone);
iThreadSafeHandlerFillBufferDone = NULL;
}
if (iMediaDataMemPool)
{
iMediaDataMemPool->removeRef();
iMediaDataMemPool = NULL;
}
if (iOutBufMemoryPool)
{
iOutBufMemoryPool->removeRef();
iOutBufMemoryPool = NULL;
}
ipFixedSizeBufferAlloc = NULL;
if(ipExternalInputBufferAllocatorInterface)
{
ipExternalInputBufferAllocatorInterface->removeRef();
ipExternalInputBufferAllocatorInterface = NULL;
}
if (iInBufMemoryPool)
{
iInBufMemoryPool->removeRef();
iInBufMemoryPool = NULL;
}
if (in_ctrl_struct_ptr)
{
oscl_free(in_ctrl_struct_ptr);
in_ctrl_struct_ptr = NULL;
}
if (in_buff_hdr_ptr)
{
oscl_free(in_buff_hdr_ptr);
in_buff_hdr_ptr = NULL;
}
if (out_ctrl_struct_ptr)
{
oscl_free(out_ctrl_struct_ptr);
out_ctrl_struct_ptr = NULL;
}
if (out_buff_hdr_ptr)
{
oscl_free(out_buff_hdr_ptr);
out_buff_hdr_ptr = NULL;
}
//Thread logoff
if (IsAdded())
{
RemoveFromScheduler();
iIsAdded = false;
}
//Cleanup allocated interfaces
//Cleanup allocated ports
ReleaseAllPorts();
//Cleanup commands
//The command queues are self-deleting, but we want to
//notify the observer of unprocessed commands.
while (!iCurrentCommand.empty())
{
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFFailure);
}
while (!iInputCommands.empty())
{
CommandComplete(iInputCommands, iInputCommands.front(), PVMFFailure);
}
if (iNALSizeArray != NULL)
{
oscl_free(iNALSizeArray);
}
if (iNALPtrArray != NULL)
{
oscl_free(iNALPtrArray);
}
//Release Input buffer
iDataIn.Unbind();
}
/////////////////////////////////////////////////////////////////////////////
// Add AO to the scheduler
/////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFOMXEncNode::ThreadLogon()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iLogger, PVLOGMSG_INFO, (0, "PVMFOMXEncNode:ThreadLogon"));
switch (iInterfaceState)
{
case EPVMFNodeCreated:
if (!IsAdded())
{
AddToScheduler();
iIsAdded = true;
}
SetState(EPVMFNodeIdle);
return PVMFSuccess;
// break; This break statement was removed to avoid compiler warning for Unreachable Code
default:
return PVMFErrInvalidState;
// break; This break statement was removed to avoid compiler warning for Unreachable Code
}
}
/////////////////////////////////////////////////////////////////////////////
// Remove AO from the scheduler
/////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFOMXEncNode::ThreadLogoff()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iLogger, PVLOGMSG_INFO, (0, "PVMFOMXEncNode-%s::ThreadLogoff", iNodeTypeId));
switch (iInterfaceState)
{
case EPVMFNodeIdle:
if (IsAdded())
{
RemoveFromScheduler();
iIsAdded = false;
}
iLogger = NULL;
SetState(EPVMFNodeCreated);
return PVMFSuccess;
// break; This break statement was removed to avoid compiler warning for Unreachable Code
default:
return PVMFErrInvalidState;
// break; This break statement was removed to avoid compiler warning for Unreachable Code
}
}
/////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFOMXEncNode::GetCapability(PVMFNodeCapability& aNodeCapability)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::GetCapability() called", iNodeTypeId));
aNodeCapability = iCapability;
return PVMFSuccess;
}
/////////////////////////////////////////////////////////////////////////////
PVMFPortIter* PVMFOMXEncNode::GetPorts(const PVMFPortFilter* aFilter)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::GetPorts() %s called", iNodeTypeId));
OSCL_UNUSED_ARG(aFilter);
return NULL;
}
/////////////////////////////////////////////////////////////////////////////
PVMFCommandId PVMFOMXEncNode::QueueCommandL(PVMFOMXEncNodeCommand& aCmd)
{
PVMFCommandId id;
id = iInputCommands.AddL(aCmd);
if (iInputCommands.size() == 1)
{
//wakeup the AO all the rest of input commands will reschedule the AO in Run
RunIfNotReady();
}
return id;
}
/////////////////////////////////////////////////////////////////////////////
PVMFCommandId PVMFOMXEncNode::QueryUUID(PVMFSessionId s, const PvmfMimeString& aMimeType,
Oscl_Vector<PVUuid, PVMFOMXEncNodeAllocator>& aUuids,
bool aExactUuidsOnly,
const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::QueryUUID() called", iNodeTypeId));
PVMFOMXEncNodeCommand cmd;
cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_QUERYUUID, aMimeType, aUuids, aExactUuidsOnly, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
PVMFCommandId PVMFOMXEncNode::QueryInterface(PVMFSessionId s, const PVUuid& aUuid,
PVInterface*& aInterfacePtr,
const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::QueryInterface() called", iNodeTypeId));
PVMFOMXEncNodeCommand cmd;
cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_QUERYINTERFACE, aUuid, aInterfacePtr, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
PVMFCommandId PVMFOMXEncNode::RequestPort(PVMFSessionId s, int32 aPortTag, const PvmfMimeString* aPortConfig, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::RequestPort() called", iNodeTypeId));
PVMFOMXEncNodeCommand cmd;
// IMPORTANT NOTE - ENGINE IS SENDING THE MIME TYPE FOR THE ENCODER INPUT/OUTPUT FORMAT THRU THE PORT PARAMETER
cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMF_GENERIC_NODE_REQUESTPORT, aPortTag, aPortConfig, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFOMXEncNode::ReleasePort(PVMFSessionId s, PVMFPortInterface& aPort, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::ReleasePort() called", iNodeTypeId));
PVMFOMXEncNodeCommand cmd;
cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_RELEASEPORT, aPort, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
PVMFCommandId PVMFOMXEncNode::Init(PVMFSessionId s, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::Init() called", iNodeTypeId));
PVMFOMXEncNodeCommand cmd;
cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_INIT, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
PVMFCommandId PVMFOMXEncNode::Prepare(PVMFSessionId s, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::Prepare() called", iNodeTypeId));
PVMFOMXEncNodeCommand cmd;
cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_PREPARE, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
PVMFCommandId PVMFOMXEncNode::Start(PVMFSessionId s, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::Start() called", iNodeTypeId));
PVMFOMXEncNodeCommand cmd;
cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_START, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
PVMFCommandId PVMFOMXEncNode::Stop(PVMFSessionId s, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::Stop() called", iNodeTypeId));
PVMFOMXEncNodeCommand cmd;
cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_STOP, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
PVMFCommandId PVMFOMXEncNode::Flush(PVMFSessionId s, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::Flush() called", iNodeTypeId));
PVMFOMXEncNodeCommand cmd;
cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_FLUSH, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
PVMFCommandId PVMFOMXEncNode::Pause(PVMFSessionId s, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::Pause() called", iNodeTypeId));
PVMFOMXEncNodeCommand cmd;
cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_PAUSE, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
PVMFCommandId PVMFOMXEncNode::Reset(PVMFSessionId s, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::Reset() called", iNodeTypeId));
PVMFOMXEncNodeCommand cmd;
cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_RESET, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
PVMFCommandId PVMFOMXEncNode::CancelAllCommands(PVMFSessionId s, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::CancelAllCommands() called", iNodeTypeId));
PVMFOMXEncNodeCommand cmd;
cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_CANCELALL, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
PVMFCommandId PVMFOMXEncNode::CancelCommand(PVMFSessionId s, PVMFCommandId aCmdId, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::CancelCommand() called", iNodeTypeId));
PVMFOMXEncNodeCommand cmd;
cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_CANCELCMD, aCmdId, aContext);
return QueueCommandL(cmd);
}
/////////////////////
// Private Section //
/////////////////////
/////////////////////////////////////////////////////////////////////////////
// Class Constructor
/////////////////////////////////////////////////////////////////////////////
PVMFOMXEncNode::PVMFOMXEncNode(int32 aPriority) :
OsclActiveObject(aPriority, "PVMFOMXEncNode"),
iInPort(NULL),
iOutPort(NULL),
iOutBufMemoryPool(NULL),
iMediaDataMemPool(NULL),
iOMXComponentOutputBufferSize(0),
iOutputAllocSize(0),
iNumOutstandingOutputBuffers(0),
iNumOutstandingInputBuffers(0),
iProcessingState(EPVMFOMXEncNodeProcessingState_Idle),
iOMXEncoder(NULL),
iSendBOS(false),
iStreamID(0),
iBOSTimestamp(0),
iSeqNum(0),
iSeqNum_In(0),
iIsAdded(true),
iLogger(NULL),
iDataPathLogger(NULL),
iClockLogger(NULL),
iExtensionRefCount(0),
iEndOfDataReached(false),
iEndOfDataTimestamp(0),
iDiagnosticsLogger(NULL),
iDiagnosticsLogged(false),
iAvgBitrateValue(0),
iResetInProgress(false),
iResetMsgSent(false),
iStopInResetMsgSent(false),
ipExternalInputBufferAllocatorInterface(NULL),
ipFixedSizeBufferAlloc(NULL)
{
iInterfaceState = EPVMFNodeCreated;
// Allocate memory for VOL header
uint refCounterSize = oscl_mem_aligned_size(sizeof(OsclRefCounterDA));
uint VolHdrSize = refCounterSize + DEFAULT_VOL_HEADER_LENGTH;
uint8 *memBufferVOLHeader = NULL;
uint ParamSetSize = refCounterSize + DEFAULT_PARAMS_SET_LENGTH;
uint8 *memBufferParamSet = NULL;
int32 err;
OSCL_TRY(err,
//Create the input command queue. Use a reserve to avoid lots of
//dynamic memory allocation.
iInputCommands.Construct(PVMF_OMXENC_NODE_COMMAND_ID_START, PVMF_OMXENC_NODE_COMMAND_VECTOR_RESERVE);
//Create the "current command" queue. It will only contain one
//command at a time, so use a reserve of 1.
iCurrentCommand.Construct(0, 1);
//Set the node capability data.
//This node can support an unlimited number of ports.
iCapability.iCanSupportMultipleInputPorts = false;
iCapability.iCanSupportMultipleOutputPorts = false;
iCapability.iHasMaxNumberOfPorts = true;
iCapability.iMaxNumberOfPorts = 2;
// video output
iCapability.iOutputFormatCapability.push_back(PVMF_MIME_H264_VIDEO_MP4);
iCapability.iOutputFormatCapability.push_back(PVMF_MIME_H264_VIDEO_RAW);
//iCapability.iOutputFormatCapability.push_back(PVMF_MIME_H264_VIDEO);
iCapability.iOutputFormatCapability.push_back(PVMF_MIME_M4V);
iCapability.iOutputFormatCapability.push_back(PVMF_MIME_H2631998);
iCapability.iOutputFormatCapability.push_back(PVMF_MIME_H2632000);
//iCapability.iOutputFormatCapability.push_back(PVMF_MIME_WMV);
// audio output
iCapability.iOutputFormatCapability.push_back(PVMF_MIME_AMR_IETF);
iCapability.iOutputFormatCapability.push_back(PVMF_MIME_AMRWB_IETF);
iCapability.iOutputFormatCapability.push_back(PVMF_MIME_AMR_IF2);
iCapability.iOutputFormatCapability.push_back(PVMF_MIME_ADTS);
iCapability.iOutputFormatCapability.push_back(PVMF_MIME_ADIF);
iCapability.iOutputFormatCapability.push_back(PVMF_MIME_MPEG4_AUDIO);
// video input
iCapability.iInputFormatCapability.push_back(PVMF_MIME_YUV420);
iCapability.iInputFormatCapability.push_back(PVMF_MIME_YUV422);
iCapability.iInputFormatCapability.push_back(PVMF_MIME_YUV422_INTERLEAVED_UYVY);
iCapability.iInputFormatCapability.push_back(PVMF_MIME_YUV422_INTERLEAVED_YUYV);
iCapability.iInputFormatCapability.push_back(PVMF_MIME_RGB24);
iCapability.iInputFormatCapability.push_back(PVMF_MIME_RGB12);
// audio input
iCapability.iInputFormatCapability.push_back(PVMF_MIME_PCM16);
iAvailableMetadataKeys.reserve(PVMF_OMXENC_NUM_METADATA_VALUES);
iAvailableMetadataKeys.clear();
// for VOL header
memBufferVOLHeader = (uint8*)iAlloc.allocate(VolHdrSize);
if (!memBufferVOLHeader)
{
OSCL_LEAVE(PVMFErrNoMemory);
}
memBufferParamSet = (uint8*) iAlloc.allocate(ParamSetSize);
if (!memBufferParamSet)
{
OSCL_LEAVE(PVMFErrNoMemory);
}
);
// Save default VOL header
oscl_memset(memBufferVOLHeader, 0, DEFAULT_VOL_HEADER_LENGTH);
OsclMemoryFragment volHeader;
OsclRefCounter* refCounterVOLHeader = new(memBufferVOLHeader) OsclRefCounterDA(memBufferVOLHeader,
(OsclDestructDealloc*)&iAlloc);
memBufferVOLHeader += refCounterSize;
volHeader.ptr = memBufferVOLHeader;
oscl_memcpy(volHeader.ptr, (OsclAny*)DEFAULT_VOL_HEADER, DEFAULT_VOL_HEADER_LENGTH);
volHeader.len = DEFAULT_VOL_HEADER_LENGTH;
iVolHeader = OsclRefCounterMemFrag(volHeader, refCounterVOLHeader, DEFAULT_VOL_HEADER_LENGTH);
// construct SPS&PPS placeholder
oscl_memset(memBufferParamSet, 0, DEFAULT_PARAMS_SET_LENGTH);
OsclMemoryFragment paramSet;
OsclRefCounter* refCounterParamSet = new(memBufferParamSet) OsclRefCounterDA(memBufferParamSet,
(OsclDestructDealloc*)&iAlloc);
memBufferParamSet += refCounterSize;
paramSet.ptr = memBufferParamSet;
paramSet.len = DEFAULT_PARAMS_SET_LENGTH;
iParamSet = OsclRefCounterMemFrag(paramSet, refCounterParamSet, DEFAULT_PARAMS_SET_LENGTH);
// initialize length and number of sps/ppss
iParamSet.getMemFrag().len = 0;
iNumPPSs = 0;
iNumSPSs = 0;
iSpsPpsSequenceOver = false;
iFirstNAL = false; //set this to false so that mp4 can proceed without a problem.
// in case of AVC, this flag will be set after spspps
iNALSizeArray = NULL;
iNALPtrArray = NULL;
iNALSizeArrayMaxElems = 0;
iNumNALs = 0;
iFirstNALStartCodeSize = 0;
iThreadSafeHandlerEventHandler = NULL;
iThreadSafeHandlerEmptyBufferDone = NULL;
iThreadSafeHandlerFillBufferDone = NULL;
iInBufMemoryPool = NULL;
iOutBufMemoryPool = NULL;
in_ctrl_struct_ptr = NULL;
in_buff_hdr_ptr = NULL;
out_ctrl_struct_ptr = NULL;
out_buff_hdr_ptr = NULL;
// init to some value
iOMXComponentOutputBufferSize = 0;
iNumOutputBuffers = 0;
iOMXComponentInputBufferSize = 0;
iNumInputBuffers = 0;
iDoNotSendOutputBuffersDownstreamFlag = false;
iDoNotSaveInputBuffersFlag = false;
iOutputBuffersFreed = true;// buffers have not been created yet, so they can be considered freed
iInputBuffersFreed = true;
// dynamic port reconfig init vars
iSecondPortReportedChange = false;
iDynamicReconfigInProgress = false;
// EOS flag init
iIsEOSSentToComponent = false;
iIsEOSReceivedFromComponent = false;
// init state of component
iCurrentEncoderState = OMX_StateInvalid;
iTimeStampOut = 0;
iTimeStampPrevious = 0;
iBufferLenOut = 0;
iBufferLenPrevious = 0;
iEndOfFrameFlagPrevious = 0;
iKeyFrameFlagPrevious = 0;
iEndOfNALFlagPrevious = 0;
iEndOfFrameFlagOut = 0;
iKeyFrameFlagOut = 0;
iEndOfNALFlagOut = 0;
//if timescale value is 1 000 000 - it means that
//timestamp is expressed in units of 1/10^6 (i.e. microseconds)
iTimeScale = 1000000;
iInTimeScale = 1000;
iOutTimeScale = 1000;
iInputTimestampClock.set_timescale(iInTimeScale); // keep the timescale set to input timestamp
// counts output frames (for logging)
iFrameCounter = 0;
iInFormat = PVMF_MIME_FORMAT_UNKNOWN;
iOutFormat = PVMF_MIME_FORMAT_UNKNOWN;
// zero out encoder param structure
oscl_memset(&iVideoInputFormat, 0, sizeof(iVideoInputFormat));
// set default values
iVideoInputFormat.iFrameWidth = DEFAULT_FRAME_WIDTH;
iVideoInputFormat.iFrameHeight = DEFAULT_FRAME_HEIGHT;
iVideoInputFormat.iFrameRate = (float)DEFAULT_FRAME_RATE;
iVideoInputFormat.iFrameOrientation = 0;
oscl_memset(&iVideoEncodeParam, 0, sizeof(iVideoEncodeParam));
iVideoEncodeParam.iEncodeID = 0;
iVideoEncodeParam.iNumLayer = 1;
iVideoEncodeParam.iFrameWidth[0] = DEFAULT_FRAME_WIDTH;
iVideoEncodeParam.iFrameHeight[0] = DEFAULT_FRAME_HEIGHT;
iVideoEncodeParam.iBitRate[0] = DEFAULT_BITRATE;
iVideoEncodeParam.iFrameRate[0] = (float)DEFAULT_FRAME_RATE;
iVideoEncodeParam.iFrameQuality = 10;
iVideoEncodeParam.iSceneDetection = false;
iVideoEncodeParam.iRVLCEnable = false;
iVideoEncodeParam.iIFrameInterval = DEFAULT_I_FRAME_INTERVAL;
iVideoEncodeParam.iBufferDelay = (float)0.2;
iVideoEncodeParam.iShortHeader = false;
iVideoEncodeParam.iDataPartitioning = false;
iVideoEncodeParam.iResyncMarker = true;
// set the default rate control type to variable bit rate control
// since it has better performance
iVideoEncodeParam.iRateControlType = PVMFVEN_RATE_CONTROL_VBR;
iVideoEncodeParam.iIquant[0] = 15;
iVideoEncodeParam.iPquant[0] = 12;
iVideoEncodeParam.iBquant[0] = 12;
iVideoEncodeParam.iSearchRange = 16;
iVideoEncodeParam.iMV8x8 = false;
iVideoEncodeParam.iMVHalfPel = true;
iVideoEncodeParam.iPacketSize = 256;
iVideoEncodeParam.iNoCurrentSkip = false;
iVideoEncodeParam.iNoFrameSkip = false;
iVideoEncodeParam.iClipDuration = 0;
iVideoEncodeParam.iProfileLevel = EI_CORE_LEVEL2;
/////////////////AVC SPECIFIC///////////////////////////
iVideoEncodeParam.iEncMode = EI_ENCMODE_RECORDER;
iVideoEncodeParam.iAVCProfile = EI_PROFILE_BASELINE;
iVideoEncodeParam.iAVCLevel = EI_LEVEL_11;
oscl_memset(&iAudioInputFormat, 0, sizeof(iAudioInputFormat));
// Currently, set according to AMR values
iAudioInputFormat.iInputInterleaveMode = EINTERLEAVE_LR;
iAudioInputFormat.iInputBitsPerSample = 16;
iAudioInputFormat.iInputNumChannels = 1;
iAudioInputFormat.iInputSamplingRate = 8000;
oscl_memset(&iAudioEncodeParam, 0, sizeof(iAudioEncodeParam));
iAudioEncodeParam.iMaxNumOutputFramesPerBuffer = MAX_NUM_AMR_FRAMES_PER_BUFFER;
iAudioEncodeParam.iAMRBitrate = GSM_AMR_12_2;
iAudioEncodeParam.iOutputBitrate = 24000;
iAudioEncodeParam.iOutputNumChannels = iAudioInputFormat.iInputNumChannels;
iAudioEncodeParam.iOutputSamplingRate = iAudioInputFormat.iInputSamplingRate;
#ifdef _TEST_AE_ERROR_HANDLING
iErrorHandlingInit = false;
iErrorHandlingEncodeCount = 0;
iCountFrames = 0;
iErrorDataPathStall = 0;
iErrorNodeCmd = 0;
iErrorConfigHeader = false;
iErrorEncodeFlag = 0;
#endif
iInputTimestampClock.set_clock(iBOSTimestamp, 0);
iOMXTicksTimestamp = ConvertTimestampIntoOMXTicks(iInputTimestampClock);
sendYuvFsi = true;
iNodeTypeId = LOG_ID_UNKNOWN;
iLogger = PVLogger::GetLoggerObject("PVMFOMXEncNode");
iRunlLogger = PVLogger::GetLoggerObject("Run.PVMFOMXEncNode");
iDataPathLogger = PVLogger::GetLoggerObject("datapath");
iClockLogger = PVLogger::GetLoggerObject("clock");
iDiagnosticsLogger = PVLogger::GetLoggerObject("pvplayerdiagnostics.encnode.OMXEncnode");
}
/////////////////////////////////////////////////////////////////////////////
// Local Run Routine
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::Run()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::Run() In", iNodeTypeId));
// if reset is in progress, call DoReset again until Reset Msg is sent
if ((iResetInProgress == true) &&
(iResetMsgSent == false) &&
(iCurrentCommand.size() > 0) &&
(iCurrentCommand.front().iCmd == PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_RESET)
)
{
DoReset(iCurrentCommand.front());
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVMFOMXEncNode-%s::Run() - Calling DoReset", iNodeTypeId));
return; // don't do anything else
}
//Check for NODE commands...
if (!iInputCommands.empty())
{
if (ProcessCommand(iInputCommands.front()))
{
if (iInterfaceState != EPVMFNodeCreated
&& (!iInputCommands.empty() || (iInPort && (iInPort->IncomingMsgQueueSize() > 0)) ||
(iDataIn.GetRep() != NULL)))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVMFOMXEncNode-%s::Run() - rescheduling after process command", iNodeTypeId));
RunIfNotReady();
}
return;
}
if (!iInputCommands.empty())
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVMFOMXEncNode-%s::Run() - rescheduling to process more commands", iNodeTypeId));
RunIfNotReady();
}
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVMFOMXEncNode-%s::Run() - Input commands empty", iNodeTypeId));
}
if (((iCurrentCommand.size() == 0) && (iInterfaceState != EPVMFNodeStarted)) ||
((iCurrentCommand.size() > 0) && (iCurrentCommand.front().iCmd == PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_START) && (iInterfaceState != EPVMFNodeStarted)))
{
// rescheduling because of input data will be handled in Command Processing Part
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVMFOMXEncNode-%s::Run() - Node not in Started state yet", iNodeTypeId));
return;
}
// Process port activity, push out all outgoing messages
if (iOutPort)
{
while (iOutPort->OutgoingMsgQueueSize())
{
// if port is busy it is going to wakeup from port ready event
if (!ProcessOutgoingMsg(iOutPort))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVMFOMXEncNode-%s::Run() - Outgoing Port Busy, cannot send more msgs", iNodeTypeId));
break;
}
}
}
int loopCount = 0;
#if (PVLOGGER_INST_LEVEL >= PVLOGMSG_INST_REL)
uint32 startticks = OsclTickCount::TickCount();
uint32 starttime = OsclTickCount::TicksToMsec(startticks);
#endif
do // Try to consume all the data from the Input port
{
// Process port activity if there is no input data that is being processed
// Do not accept any input if EOS needs to be sent out
if (iInPort && (iInPort->IncomingMsgQueueSize() > 0) && (iDataIn.GetRep() == NULL) && !iEndOfDataReached)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVMFOMXEncNode-%s::Run() - Getting more input", iNodeTypeId));
if (!ProcessIncomingMsg(iInPort))
{
//Re-schedule to come back.
RunIfNotReady();
return;
}
}
if (iSendBOS)
{
SendBeginOfMediaStreamCommand();
}
// If in init or ready to encode state, process data in the input port if there is input available and input buffers are present
// (note: at EOS, iDataIn will not be available)
if ((iDataIn.GetRep() != NULL) ||
((iNumOutstandingOutputBuffers < iNumOutputBuffers) &&
(iProcessingState == EPVMFOMXEncNodeProcessingState_ReadyToEncode) &&
(iResetMsgSent == false)) ||
((iDynamicReconfigInProgress == true) && (iResetMsgSent == false))
)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "PVMFOMXEncNode-%s::Run() - Calling HandleProcessingState", iNodeTypeId));
// input data is available, that means there is data to be encoded
if (HandleProcessingState() != PVMFSuccess)
{
// If HandleProcessingState does not return Success, we must wait for an event
// no point in rescheduling
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "PVMFOMXEncNode-%s::Run() - HandleProcessingState did not return Success", iNodeTypeId));
return;
}
}
loopCount++;
}
while (iInPort &&
(((iInPort->IncomingMsgQueueSize() > 0) || (iDataIn.GetRep() != NULL)) && (iNumOutstandingInputBuffers < iNumInputBuffers))
&& (!iEndOfDataReached)
&& (iResetMsgSent == false)
);
#if (PVLOGGER_INST_LEVEL >= PVLOGMSG_INST_REL)
uint32 endticks = OsclTickCount::TickCount();
uint32 endtime = OsclTickCount::TicksToMsec(endticks);
uint32 timeinloop;
timeinloop = (endtime - starttime);
PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iRunlLogger, PVLOGMSG_INFO,
(0, "PVMFOMXEncNode-%s::Run() - LoopCount = %d, Time spent in loop(in ms) = %d, iNumOutstandingInputBuffers = %d, iNumOutstandingOutputBuffers = %d ", iNodeTypeId,
loopCount, timeinloop, iNumOutstandingInputBuffers, iNumOutstandingOutputBuffers));
#endif
// EOS processing:
// first send an empty buffer to OMX component and mark the EOS flag
// wait for the OMX component to send async event to indicate that it has reached this EOS buffer
// then, create and send the EOS message downstream
if (iEndOfDataReached && !iDynamicReconfigInProgress)
{
// if EOS was not sent yet and we have an available input buffer, send EOS buffer to component
if (!iIsEOSSentToComponent && (iNumOutstandingInputBuffers < iNumInputBuffers))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "PVMFOMXEncNode-%s::Run() - Sending EOS marked buffer To Component ", iNodeTypeId));
iIsEOSSentToComponent = true;
// if the component is not yet initialized or if it's in the middle of port reconfig,
// don't send EOS buffer to component. It does not care. Just set the flag as if we received
// EOS from the component to enable sending EOS downstream
if (iProcessingState != EPVMFOMXEncNodeProcessingState_ReadyToEncode)
{
iIsEOSReceivedFromComponent = true;
}
else if (!SendEOSBufferToOMXComponent())
{
// for some reason, Component can't receive the EOS buffer
// it could be that it is not initialized yet (because EOS could be the first msg). In this case,
// send the EOS downstream anyway
iIsEOSReceivedFromComponent = true;
}
}
// DV: we must wait for event (acknowledgment from component)
// before sending EOS downstream. This is because OMX Component will send
// the EOS event only after processing remaining buffers
if (iIsEOSReceivedFromComponent)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "PVMFOMXEncNode-%s::Run() - Received EOS from component, Sending EOS msg downstream ", iNodeTypeId));
if (iOutPort && iOutPort->IsOutgoingQueueBusy())
{
// note: we already tried to empty the outgoing q. If it's still busy,
// it means that output port is busy. Just return and wait for the port to become free.
// this will wake up the node and it will send out a msg from the q etc.
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "PVMFOMXEncNode-%s::Run() - - EOS cannot be sent downstream, outgoing queue busy - wait", iNodeTypeId));
return;
}
if (SendEndOfTrackCommand()) // this will only q the EOS
{
// EOS send downstream OK, so reset the flag
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "PVMFOMXEncNode-%s::Run() - EOS was queued to be sent downstream", iNodeTypeId));
iEndOfDataReached = false; // to resume normal processing, reset the flags
iIsEOSSentToComponent = false;
iIsEOSReceivedFromComponent = false;
RunIfNotReady(); // Run again to send out the EOS msg from the outgoing q, and resume
// normal processing
// END OF STREAM EVENT reported by the downstream node.
//ReportInfoEvent(PVMFInfoEndOfData);
}
}
else
{
// keep sending output buffers, it's possible that the component needs to flush output
// data at the end
while (iNumOutstandingOutputBuffers < iNumOutputBuffers)
{
if (!SendOutputBufferToOMXComponent())
break;
}
}
}
//Check for flash command complition...
if (iInPort && iOutPort && (iCurrentCommand.size() > 0) &&
(iCurrentCommand.front().iCmd == PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_FLUSH) &&
(iInPort->IncomingMsgQueueSize() == 0) &&
(iOutPort->OutgoingMsgQueueSize() == 0) &&
(iDataIn.GetRep() == NULL) &&
(iNumOutstandingOutputBuffers == iNumOutputBuffers) && // all output buffers are with the component or outstanding
(iNumOutstandingInputBuffers == 0) // all input buffers were processed and returned. These 2 conditions mean the component is idle
)
{
//flush command is almost completed
//Debug check-- all the port queues should be empty at this point.
OMX_ERRORTYPE err = OMX_ErrorNone;
OMX_STATETYPE sState = OMX_StateInvalid;
OSCL_ASSERT(iInPort->IncomingMsgQueueSize() == 0 && iOutPort->OutgoingMsgQueueSize() == 0);
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVMFOMXEncNode-%s::Run() - Flush pending", iNodeTypeId));
// now, drive the state of the omx component to IDLE - wait for the callback from the component and send cmd complete from there
iDataIn.Unbind();
iPreviousMediaData.Unbind(); // make sure nothing is holding this data
if ((iOutFormat == PVMF_MIME_H264_VIDEO_MP4) || (iOutFormat == PVMF_MIME_H264_VIDEO_RAW))
{
// prepare for next start
iFirstNAL = true;
}
// Clear the data flags
iEndOfDataReached = false;
iIsEOSSentToComponent = false;
iIsEOSReceivedFromComponent = false;
iDoNotSendOutputBuffersDownstreamFlag = true; // stop sending output buffers downstream
iDoNotSaveInputBuffersFlag = true;
//Get state of OpenMAX encoder
err = OMX_GetState(iOMXEncoder, &sState);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::Run(): Flush pending - Can't get State of encoder!", iNodeTypeId));
sState = OMX_StateInvalid;
}
if ((sState == OMX_StateExecuting) || (sState == OMX_StatePause))
{
/* Change state to OMX_StateIdle from OMX_StateExecuting or OMX_StatePause. */
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::Run(): Flush pending: Changing Component State Executing->Idle or Pause->Idle", iNodeTypeId));
if (iOutPort) iOutPort->ClearMsgQueues();
err = OMX_SendCommand(iOMXEncoder, OMX_CommandStateSet, OMX_StateIdle, NULL);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::Run(): Flush pending : Can't send StateSet command to encoder!", iNodeTypeId));
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFErrInvalidState);
return;
}
// prevent the node from sending more buffers etc.
// if port reconfiguration is in process, let the state remain one of the port config states
// if there is a start command, we can do it seemlessly (by continuing the port reconfig)
if (iProcessingState == EPVMFOMXEncNodeProcessingState_ReadyToEncode)
iProcessingState = EPVMFOMXEncNodeProcessingState_Stopping;
}
else
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::Run(): Flush pending : Encoder is not in the Executing or Pause state!", iNodeTypeId));
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFErrInvalidState);
return;
}
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::Run() Out", iNodeTypeId));
}
/////////////////////////////////////////////////////////////////////////////
// This routine will dispatch recived commands
/////////////////////////////////////////////////////////////////////////////
bool PVMFOMXEncNode::ProcessCommand(PVMFOMXEncNodeCommand& aCmd)
{
//normally this node will not start processing one command
//until the prior one is finished. However, a hi priority
//command such as Cancel must be able to interrupt a command
//in progress.
if (!iCurrentCommand.empty() && !aCmd.hipri())
return false;
switch (aCmd.iCmd)
{
case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_QUERYUUID:
DoQueryUuid(aCmd);
break;
case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_QUERYINTERFACE:
DoQueryInterface(aCmd);
break;
case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_REQUESTPORT:
DoRequestPort(aCmd);
break;
case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_RELEASEPORT:
DoReleasePort(aCmd);
break;
case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_INIT:
DoInit(aCmd);
break;
case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_PREPARE:
DoPrepare(aCmd);
break;
case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_START:
DoStart(aCmd);
break;
case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_STOP:
DoStop(aCmd);
break;
case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_FLUSH:
DoFlush(aCmd);
break;
case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_PAUSE:
DoPause(aCmd);
break;
case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_RESET:
DoReset(aCmd);
break;
case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_CANCELCMD:
DoCancelCommand(aCmd);
break;
case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_CANCELALL:
DoCancelAllCommands(aCmd);
break;
case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_GETNODEMETADATAKEY:
{
PVMFStatus retval = DoGetNodeMetadataKey(aCmd);
CommandComplete(iInputCommands, aCmd, retval);
}
break;
case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_GETNODEMETADATAVALUE:
{
PVMFStatus retval = DoGetNodeMetadataValue(aCmd);
CommandComplete(iInputCommands, aCmd, retval);
}
break;
default://unknown command type
CommandComplete(iInputCommands, aCmd, PVMFFailure);
break;
}
return true;
}
/////////////////////////////////////////////////////////////////////////////
// This routine will process incomming message from the port
/////////////////////////////////////////////////////////////////////////////
bool PVMFOMXEncNode::ProcessIncomingMsg(PVMFPortInterface* aPort)
{
//Called by the AO to process one buffer off the port's
//incoming data queue. This routine will dequeue and
//dispatch the data.
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "0x%x PVMFOMXEncNode-%s::ProcessIncomingMsg: aPort=0x%x", this, iNodeTypeId, aPort));
PVMFStatus status = PVMFFailure;
//#define SIMULATE_BOS
#ifdef SIMULATE_BOS
if (((PVMFOMXEncPort*)aPort)->iNumFramesConsumed == 6))
{
PVMFSharedMediaCmdPtr BOSCmdPtr = PVMFMediaCmd::createMediaCmd();
// Set the format ID to BOS
BOSCmdPtr->setFormatID(PVMF_MEDIA_CMD_BOS_FORMAT_ID);
// Set the timestamp
BOSCmdPtr->setTimestamp(201);
BOSCmdPtr->setStreamID(0);
// Convert to media message and send it out
PVMFSharedMediaMsgPtr mediaMsgOut;
convertToPVMFMediaCmdMsg(mediaMsgOut, BOSCmdPtr);
//store the stream id and time stamp of bos message
iStreamID = mediaMsgOut->getStreamID();
iBOSTimestamp = mediaMsgOut->getTimestamp();
iInputTimestampClock.set_clock(iBOSTimestamp, 0);
iOMXTicksTimestamp = ConvertTimestampIntoOMXTicks(iInputTimestampClock);
iSendBOS = true;
#ifdef _DEBUG
printf("PVMFOMXEncNode-%s::ProcessIncomingMsg() SIMULATED BOS\n", iNodeTypeId);
#endif
((PVMFOMXEncPort*)aPort)->iNumFramesConsumed++;
return true;
}
#endif
//#define SIMULATE_PREMATURE_EOS
#ifdef SIMULATE_PREMATURE_EOS
if (((PVMFOMXEncPort*)aPort)->iNumFramesConsumed == 5)
{
PVMFSharedMediaCmdPtr EOSCmdPtr = PVMFMediaCmd::createMediaCmd();
// Set the format ID to EOS
EOSCmdPtr->setFormatID(PVMF_MEDIA_CMD_EOS_FORMAT_ID);
// Set the timestamp
EOSCmdPtr->setTimestamp(200);
// Convert to media message and send it out
PVMFSharedMediaMsgPtr mediaMsgOut;
convertToPVMFMediaCmdMsg(mediaMsgOut, EOSCmdPtr);
((PVMFOMXEncPort*)aPort)->iNumFramesConsumed++;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::ProcessIncomingMsg: SIMULATED EOS", iNodeTypeId));
#ifdef _DEBUG
printf("PVMFOMXEncNode-%s::ProcessIncomingMsg() SIMULATED EOS\n", iNodeTypeId);
#endif
// Set EOS flag
iEndOfDataReached = true;
// Save the timestamp for the EOS cmd
iEndOfDataTimestamp = mediaMsgOut->getTimestamp();
return true;
}
#endif
PVMFSharedMediaMsgPtr msg;
status = aPort->DequeueIncomingMsg(msg);
if (status != PVMFSuccess)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "0x%x PVMFOMXEncNode-%s::ProcessIncomingMsg: Error - DequeueIncomingMsg failed", this, iNodeTypeId));
return false;
}
if (msg->getFormatID() == PVMF_MEDIA_CMD_BOS_FORMAT_ID)
{
//store the stream id and time stamp of bos message
iStreamID = msg->getStreamID();
iBOSTimestamp = msg->getTimestamp();
// we need to initialize the timestamp here - so that updates later on are accurate (in terms of rollover etc)
iInputTimestampClock.set_clock(iBOSTimestamp, 0);
iOMXTicksTimestamp = ConvertTimestampIntoOMXTicks(iInputTimestampClock);
iSendBOS = true;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::ProcessIncomingMsg: Received BOS stream %d, timestamp %d", iNodeTypeId, iStreamID, iBOSTimestamp));
((PVMFOMXEncPort*)aPort)->iNumFramesConsumed++;
return true;
}
else if (msg->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID)
{
// Set EOS flag
iEndOfDataReached = true;
// Save the timestamp for the EOS cmd
iEndOfDataTimestamp = msg->getTimestamp();
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::ProcessIncomingMsg: Received EOS", iNodeTypeId));
((PVMFOMXEncPort*)aPort)->iNumFramesConsumed++;
return true; // do not do conversion into media data, just set the flag and leave
}
convertToPVMFMediaData(iDataIn, msg);
iCurrFragNum = 0; // for new message, reset the fragment counter
((PVMFOMXEncPort*)aPort)->iNumFramesConsumed++;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::ProcessIncomingMsg() Received %d frames", iNodeTypeId, ((PVMFOMXEncPort*)aPort)->iNumFramesConsumed));
//return true if we processed an activity...
return true;
}
/////////////////////////////////////////////////////////////////////////////
// This routine will process outgoing message by sending it into output the port
/////////////////////////////////////////////////////////////////////////////
bool PVMFOMXEncNode::ProcessOutgoingMsg(PVMFPortInterface* aPort)
{
//Called by the AO to process one message off the outgoing
//message queue for the given port. This routine will
//try to send the data to the connected port.
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "0x%x PVMFOMXEncNode-%s::ProcessOutgoingMsg: aPort=0x%x", this, iNodeTypeId, aPort));
PVMFStatus status = aPort->Send();
if (status == PVMFErrBusy)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "0x%x PVMFOMXEncNode-%s::ProcessOutgoingMsg: Connected port goes into busy state", this, iNodeTypeId));
}
//Report any unexpected failure in port processing...
//(the InvalidState error happens when port input is suspended,
//so don't report it.)
if (status != PVMFErrBusy
&& status != PVMFSuccess
&& status != PVMFErrInvalidState)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "0x%x PVMFOMXEncNode-%s::ProcessOutgoingMsg: Error - ProcessPortActivity failed. port=0x%x, type=%d",
this, iNodeTypeId, iOutPort, PVMF_PORT_ACTIVITY_OUTGOING_MSG));
ReportErrorEvent(PVMFErrPortProcessing);
}
//return true if we processed an activity...
return (status != PVMFErrBusy);
}
/////////////////////////////////////////////////////////////////////////////
// This routine will process received data usign State Machine
/////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFOMXEncNode::HandleProcessingState()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::HandleProcessingState() In", iNodeTypeId));
PVMFStatus status = PVMFSuccess;
switch (iProcessingState)
{
// The FOLLOWING 4 states handle Dynamic Port Reconfiguration
case EPVMFOMXEncNodeProcessingState_PortReconfig:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> Sending Port Disable Command", iNodeTypeId));
// port reconfiguration is required. Only one port at a time is disabled and then re-enabled after buffer resizing
OMX_SendCommand(iOMXEncoder, OMX_CommandPortDisable, iPortIndexForDynamicReconfig, NULL);
// the port will now start returning outstanding buffers
// set the flag to prevent output from going downstream (in case of output port being reconfigd)
// set the flag to prevent input from being saved and returned to component (in case of input port being reconfigd)
// set the state to wait for port saying it is disabled
if (iPortIndexForDynamicReconfig == iOutputPortIndex)
{
iDoNotSendOutputBuffersDownstreamFlag = true;
}
else if (iPortIndexForDynamicReconfig == iInputPortIndex)
{
iDoNotSaveInputBuffersFlag = true;
}
iProcessingState = EPVMFOMXEncNodeProcessingState_WaitForBufferReturn;
// fall through to the next case to check if all buffers are already back
}
case EPVMFOMXEncNodeProcessingState_WaitForBufferReturn:
{
// as buffers are coming back, Run may be called, wait until all buffers are back, then Free them all
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> WaitForBufferReturn ", iNodeTypeId));
// check if it's output port being reconfigured
if (iPortIndexForDynamicReconfig == iOutputPortIndex)
{
// if all buffers have returned, free them
if (iNumOutstandingOutputBuffers == 0)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> all output buffers are back, free them", iNodeTypeId));
if (false == iOutputBuffersFreed)
{
if (!FreeBuffersFromComponent(iOutBufMemoryPool, // allocator
iOutputAllocSize, // size to allocate from pool (hdr only or hdr+ buffer)
iNumOutputBuffers, // number of buffers
iOutputPortIndex, // port idx
false // this is not input
))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> Cannot free output buffers ", iNodeTypeId));
SetState(EPVMFNodeError);
ReportErrorEvent(PVMFErrNoMemory);
return PVMFErrNoMemory;
}
}
// if the callback (that port is disabled) has not arrived yet, wait for it
// if it has arrived, it will set the state to PortReEnable
if (iProcessingState != EPVMFOMXEncNodeProcessingState_PortReEnable)
iProcessingState = EPVMFOMXEncNodeProcessingState_WaitForPortDisable;
status = PVMFSuccess; // allow rescheduling of the node potentially
}
else
status = PVMFErrNoMemory; // must wait for buffers to come back. No point in automatic rescheduling
// but each buffer will reschedule the node when it comes in
}
else
{
// this is input port
// if all buffers have returned, free them
if (iNumOutstandingInputBuffers == 0)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> all input buffers are back, free them", iNodeTypeId));
if (false == iInputBuffersFreed)
{
if (!FreeBuffersFromComponent(iInBufMemoryPool, // allocator
iInputAllocSize, // size to allocate from pool (hdr only or hdr+ buffer)
iNumInputBuffers, // number of buffers
iInputPortIndex, // port idx
true // this is input
))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> Cannot free input buffers ", iNodeTypeId));
SetState(EPVMFNodeError);
ReportErrorEvent(PVMFErrNoMemory);
return PVMFErrNoMemory;
}
}
// if the callback (that port is disabled) has not arrived yet, wait for it
// if it has arrived, it will set the state to PortReEnable
if (iProcessingState != EPVMFOMXEncNodeProcessingState_PortReEnable)
iProcessingState = EPVMFOMXEncNodeProcessingState_WaitForPortDisable;
status = PVMFSuccess; // allow rescheduling of the node
}
else
status = PVMFErrNoMemory; // must wait for buffers to come back. No point in automatic
// rescheduling. Each buffer will reschedule the node
// when it comes in
}
// the state will be changed to PortReEnable once we get confirmation that Port was actually disabled
break;
}
case EPVMFOMXEncNodeProcessingState_WaitForPortDisable:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> wait for port disable callback", iNodeTypeId));
// do nothing. Just wait for the port to become disabled (we'll get event from component, which will
// transition the state to PortReEnable
status = PVMFErrNoMemory; // prevent Rescheduling the node
break;
}
case EPVMFOMXEncNodeProcessingState_PortReEnable:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> Sending reenable port command", iNodeTypeId));
// set the port index so that we get parameters for the proper port
iParamPort.nPortIndex = iPortIndexForDynamicReconfig;
// iParamPort.nVersion = OMX_VERSION;
// get new parameters of the port
OMX_GetParameter(iOMXEncoder, OMX_IndexParamPortDefinition, &iParamPort);
// send command for port re-enabling (for this to happen, we must first recreate the buffers)
OMX_SendCommand(iOMXEncoder, OMX_CommandPortEnable, iPortIndexForDynamicReconfig, NULL);
// is this output port?
if (iPortIndexForDynamicReconfig == iOutputPortIndex)
{
iOMXComponentOutputBufferSize = ((iParamPort.format.video.nFrameWidth + 15) & (~15)) * ((iParamPort.format.video.nFrameHeight + 15) & (~15)) * 3 / 2;
// check the new buffer size
if (iInPort)
{
if (((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H264_VIDEO ||
((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H264_VIDEO_MP4 ||
((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H264_VIDEO_RAW ||
((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_M4V ||
((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H2631998 ||
((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H2632000)
{
iOMXComponentOutputBufferSize = ((iParamPort.format.video.nFrameWidth + 15) & (~15)) * ((iParamPort.format.video.nFrameHeight + 15) & (~15)) * 3 / 2;
}
else if (((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_WMV)
{
// This is a requirement for the WMV encoder that we have currently
iOMXComponentOutputBufferSize = ((iParamPort.format.video.nFrameWidth + 3) & (~3)) * (iParamPort.format.video.nFrameHeight) * 3 / 2;
}
else
{
OSCL_ASSERT(false);
}
}
// set the new width / height
iYUVWidth = iParamPort.format.video.nFrameWidth;
iYUVHeight = iParamPort.format.video.nFrameHeight;
if (iOMXComponentOutputBufferSize < iParamPort.nBufferSize)
iOMXComponentOutputBufferSize = iParamPort.nBufferSize;
// do we need to increase the number of buffers?
if (iNumOutputBuffers < iParamPort.nBufferCountMin)
iNumOutputBuffers = iParamPort.nBufferCountMin;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::HandleProcessingState() new output buffers %d, size %d", iNodeTypeId, iNumOutputBuffers, iOMXComponentOutputBufferSize));
/* Allocate output buffers */
if (!CreateOutMemPool(iNumOutputBuffers))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> Cannot allocate output buffers ", iNodeTypeId));
SetState(EPVMFNodeError);
ReportErrorEvent(PVMFErrNoMemory);
return PVMFErrNoMemory;
}
if (!ProvideBuffersToComponent(iOutBufMemoryPool, // allocator
iOutputAllocSize, // size to allocate from pool (hdr only or hdr+ buffer)
iNumOutputBuffers, // number of buffers
iOMXComponentOutputBufferSize, // actual buffer size
iOutputPortIndex, // port idx
iOMXComponentSupportsExternalOutputBufferAlloc, // can component use OMX_UseBuffer
false // this is not input
))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> Cannot provide output buffers to component", iNodeTypeId));
SetState(EPVMFNodeError);
ReportErrorEvent(PVMFErrNoMemory);
return PVMFErrNoMemory;
}
// do not drop output any more, i.e. enable output to be sent downstream
iDoNotSendOutputBuffersDownstreamFlag = false;
}
else
{
// this is input port
iOMXComponentInputBufferSize = iParamPort.nBufferSize;
// do we need to increase the number of buffers?
if (iNumInputBuffers < iParamPort.nBufferCountMin)
iNumInputBuffers = iParamPort.nBufferCountMin;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::HandleProcessingState() new buffers %d, size %d", iNodeTypeId, iNumInputBuffers, iOMXComponentInputBufferSize));
/* Allocate input buffers */
if (!CreateInputMemPool(iNumInputBuffers))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> Cannot allocate new input buffers to component", iNodeTypeId));
SetState(EPVMFNodeError);
ReportErrorEvent(PVMFErrNoMemory);
return PVMFErrNoMemory;
}
if (!ProvideBuffersToComponent(iInBufMemoryPool, // allocator
iInputAllocSize, // size to allocate from pool (hdr only or hdr+ buffer)
iNumInputBuffers, // number of buffers
iOMXComponentInputBufferSize, // actual buffer size
iInputPortIndex, // port idx
iOMXComponentSupportsExternalInputBufferAlloc, // can component use OMX_UseBuffer
true // this is input
))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> Cannot provide new input buffers to component", iNodeTypeId));
SetState(EPVMFNodeError);
ReportErrorEvent(PVMFErrNoMemory);
return PVMFErrNoMemory;
}
// do not drop partially consumed input
iDoNotSaveInputBuffersFlag = false;
}
// if the callback that the port was re-enabled has not arrived yet, wait for it
// if it has arrived, it will set the state to either PortReconfig or to ReadyToEncode
if (iProcessingState != EPVMFOMXEncNodeProcessingState_PortReconfig &&
iProcessingState != EPVMFOMXEncNodeProcessingState_ReadyToEncode)
iProcessingState = EPVMFOMXEncNodeProcessingState_WaitForPortEnable;
status = PVMFSuccess; // allow rescheduling of the node
break;
}
case EPVMFOMXEncNodeProcessingState_WaitForPortEnable:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> wait for port enable callback", iNodeTypeId));
// do nothing. Just wait for the port to become enabled (we'll get event from component, which will
// transition the state to ReadyToEncode
status = PVMFErrNoMemory; // prevent ReScheduling
break;
}
// NORMAL DATA FLOW STATE:
case EPVMFOMXEncNodeProcessingState_ReadyToEncode:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::HandleProcessingState() Ready To Encode start", iNodeTypeId));
// In normal data flow and decoding state
// Send all available output buffers to the encoder
while (iNumOutstandingOutputBuffers < iNumOutputBuffers)
{
// grab buffer header from the mempool if possible, and send to component
if (!SendOutputBufferToOMXComponent())
break;
}
// next, see if partially consumed input buffer needs to be resent back to OMX component
// NOTE: it is not allowed that the component returns more than 1 partially consumed input buffers
// i.e. if a partially consumed input buffer is returned, it is assumed that the OMX component
// will be waiting to get data
if (iInputBufferToResendToComponent != NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "PVMFOMXEncNode-%s::HandleProcessingState() Sending previous - partially consumed input back to the OMX component", iNodeTypeId));
OMX_EmptyThisBuffer(iOMXEncoder, iInputBufferToResendToComponent);
iInputBufferToResendToComponent = NULL; // do this only once
}
else if ((iNumOutstandingInputBuffers < iNumInputBuffers) && (iDataIn.GetRep() != NULL))
{
// try to get an input buffer header
// and send the input data over to the component
SendInputBufferToOMXComponent();
}
status = PVMFSuccess;
break;
}
case EPVMFOMXEncNodeProcessingState_Stopping:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::HandleProcessingState() Stopping -> wait for Component to move from Executing->Idle", iNodeTypeId));
status = PVMFErrNoMemory; // prevent rescheduling
break;
}
case EPVMFOMXEncNodeProcessingState_WaitForOutgoingQueue:
status = PVMFErrNoMemory;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::HandleProcessingState() Do nothing since waiting for output port queue to become available", iNodeTypeId));
break;
default:
break;
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::HandleProcessingState() Out", iNodeTypeId));
return status;
}
/////////////////////////////////////////////////////////////////////////////
bool PVMFOMXEncNode::SendOutputBufferToOMXComponent()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SendOutputBufferToOMXComponent() In", iNodeTypeId));
OutputBufCtrlStruct *output_buf = NULL;
int32 errcode = 0;
uint32 ii;
// try to get output buffer header
OSCL_TRY(errcode, output_buf = (OutputBufCtrlStruct *) iOutBufMemoryPool->allocate(iOutputAllocSize));
if (errcode != 0)
{
if (errcode == OsclErrNoResources)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger,
PVLOGMSG_DEBUG, (0, "PVMFOMXEncNode-%s::SendOutputBufferToOMXComponent() No more output buffers in the mempool", iNodeTypeId));
iOutBufMemoryPool->notifyfreechunkavailable(*this, (OsclAny *) iOutBufMemoryPool); // To signal when next deallocate() is called on mempool
return false;
}
else
{
// Memory allocation for the pool failed
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SendOutputBufferToOMXComponent() Output mempool error", iNodeTypeId));
SetState(EPVMFNodeError);
ReportErrorEvent(PVMFErrNoMemory);
return false;
}
}
//for every allocated buffer, make sure you notify when buffer is released. Keep track of allocated buffers
// use mempool as context to recognize which buffer (input or output) was returned
iOutBufMemoryPool->notifyfreechunkavailable(*this, (OsclAny *)iOutBufMemoryPool);
iNumOutstandingOutputBuffers++;
for (ii = 0; ii < iNumOutputBuffers; ii++)
{
if (output_buf == out_ctrl_struct_ptr[ii])
{
break;
}
}
if (ii == iNumOutputBuffers)
return false;
output_buf->pBufHdr = (OMX_BUFFERHEADERTYPE *)out_buff_hdr_ptr[ii];
output_buf->pBufHdr->nFilledLen = 0; // make sure you tell OMX component buffer is empty
output_buf->pBufHdr->nOffset = 0;
output_buf->pBufHdr->pAppPrivate = output_buf; // set pAppPrivate to be pointer to output_buf
// (this is context for future release of this buffer to the mempool)
// this was done during buffer creation, but still repeat just in case
output_buf->pBufHdr->nFlags = 0; // zero out the flags
OMX_FillThisBuffer(iOMXEncoder, output_buf->pBufHdr);
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SendOutputBufferToOMXComponent() Out", iNodeTypeId));
return true;
}
////////////////////////////////////////////////////////////////////////////////
bool PVMFOMXEncNode::NegotiateVideoComponentParameters()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoParameters() In", iNodeTypeId));
OMX_ERRORTYPE Err;
OMX_CONFIG_ROTATIONTYPE InputRotationType;
// first get the number of ports and port indices
OMX_PORT_PARAM_TYPE VideoPortParameters;
uint32 NumPorts;
uint32 ii;
// get starting number
CONFIG_SIZE_AND_VERSION(VideoPortParameters);
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoInit, &VideoPortParameters);
NumPorts = VideoPortParameters.nPorts; // must be at least 2 of them (in&out)
if (Err != OMX_ErrorNone || NumPorts < 2)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() There is insuffucient (%d) ports", iNodeTypeId, NumPorts));
return false;
}
// loop through video ports starting from the starting index to find index of the first input port
for (ii = VideoPortParameters.nStartPortNumber ; ii < VideoPortParameters.nStartPortNumber + NumPorts; ii++)
{
// get port parameters, and determine if it is input or output
// if there are more than 2 ports, the first one we encounter that has input direction is picked
CONFIG_SIZE_AND_VERSION(iParamPort);
//port
iParamPort.nPortIndex = ii; // iInputPortIndex; //OMF_MC_H264D_PORT_INDEX_OF_STREAM;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamPortDefinition, &iParamPort);
if (Err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem negotiating with port %d ", iNodeTypeId, ii));
return false;
}
if (iParamPort.eDir == OMX_DirInput)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Found Input port index %d ", iNodeTypeId, ii));
iInputPortIndex = ii;
break;
}
}
if (ii == VideoPortParameters.nStartPortNumber + NumPorts)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Cannot find any input port ", iNodeTypeId));
return false;
}
// loop through video ports starting from the starting index to find index of the first output port
for (ii = VideoPortParameters.nStartPortNumber ; ii < VideoPortParameters.nStartPortNumber + NumPorts; ii++)
{
// get port parameters, and determine if it is input or output
// if there are more than 2 ports, the first one we encounter that has output direction is picked
CONFIG_SIZE_AND_VERSION(iParamPort);
//port
iParamPort.nPortIndex = ii;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamPortDefinition, &iParamPort);
if (Err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem negotiating with port %d ", iNodeTypeId, ii));
return false;
}
if (iParamPort.eDir == OMX_DirOutput)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Found Output port index %d ", iNodeTypeId, ii));
iOutputPortIndex = ii;
break;
}
}
if (ii == VideoPortParameters.nStartPortNumber + NumPorts)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Cannot find any output port ", iNodeTypeId));
return false;
}
// now get input parameters
//INPUT PORT
// first check if encode parameters have been set correctly
if ((0 == iVideoEncodeParam.iFrameWidth[0]) ||
(0 == iVideoEncodeParam.iFrameHeight[0]) ||
(0 == iVideoEncodeParam.iFrameRate[0]) ||
(0 == iVideoEncodeParam.iBitRate[0]) ||
(0 == iVideoInputFormat.iFrameWidth) ||
(0 == iVideoInputFormat.iFrameHeight) ||
(0 == iVideoInputFormat.iFrameRate)
)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Encode parameters not set correctly", iNodeTypeId));
return false;
}
// first of all, check if the port supports the adequate port format
OMX_VIDEO_PARAM_PORTFORMATTYPE Video_port_format;
OMX_COLOR_FORMATTYPE DesiredPortColorFormat;
if (iInFormat == PVMF_MIME_RGB24)
{
DesiredPortColorFormat = OMX_COLOR_Format24bitRGB888;
}
else if (iInFormat == PVMF_MIME_RGB12)
{
DesiredPortColorFormat = OMX_COLOR_Format12bitRGB444;
}
else if (iInFormat == PVMF_MIME_YUV420)
{
//TODO: get color format from MIO. JJ 03/09/09
DesiredPortColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
//DesiredPortColorFormat = OMX_COLOR_FormatYUV420Planar;
}
else if (iInFormat == PVMF_MIME_YUV422_INTERLEAVED_UYVY)
{
DesiredPortColorFormat = OMX_COLOR_FormatCbYCrY;
}
else if (iInFormat == PVMF_MIME_YUV422_INTERLEAVED_YUYV)
{
DesiredPortColorFormat = OMX_COLOR_FormatYCbYCr;
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem with input port %d color format", iNodeTypeId, iInputPortIndex));
return false;
}
CONFIG_SIZE_AND_VERSION(Video_port_format);
Video_port_format.nPortIndex = iInputPortIndex; // set input port as target
// loop over supported formats until we hit the one we want
// or until the component has no more supported formats (in which case it returns OMX_ErrorNoMore
Err = OMX_ErrorNone;
Video_port_format.nIndex = 0; //init the format counter
while (OMX_ErrorNone == Err)
{
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoPortFormat, &Video_port_format);
if ((OMX_ErrorNone != Err))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem getting port format for input port %d or no desired port format found", iNodeTypeId, iInputPortIndex));
return false;
}
if ((Video_port_format.eColorFormat == DesiredPortColorFormat))
break;
Video_port_format.nIndex ++;
}
// OK, we've found the desired format, set it as the one used
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoPortFormat, &Video_port_format);
if ((OMX_ErrorNone != Err))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem setting port format for input port %d ", iNodeTypeId, iInputPortIndex));
return false;
}
CONFIG_SIZE_AND_VERSION(iParamPort);
iParamPort.nPortIndex = iInputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamPortDefinition, &iParamPort);
if (Err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem negotiating with input port %d ", iNodeTypeId, iInputPortIndex));
return false;
}
if (iInFormat == PVMF_MIME_RGB24)
{
iOMXComponentInputBufferSize = (iVideoInputFormat.iFrameWidth * iVideoInputFormat.iFrameHeight * 3);
iParamPort.format.video.eColorFormat = OMX_COLOR_Format24bitRGB888;
}
else if (iInFormat == PVMF_MIME_RGB12)
{
iOMXComponentInputBufferSize = (iVideoInputFormat.iFrameWidth * iVideoInputFormat.iFrameHeight * 2);
iParamPort.format.video.eColorFormat = OMX_COLOR_Format12bitRGB444;
}
else if (iInFormat == PVMF_MIME_YUV420)
{
iOMXComponentInputBufferSize = (iVideoInputFormat.iFrameWidth * iVideoInputFormat.iFrameHeight * 3) >> 1;
//TODO: get color format from MIO. JJ 03/09/09
iParamPort.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
//iParamPort.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
}
else if (iInFormat == PVMF_MIME_YUV422_INTERLEAVED_UYVY)
{
iOMXComponentInputBufferSize = iVideoInputFormat.iFrameWidth * iVideoInputFormat.iFrameHeight * 2;
iParamPort.format.video.eColorFormat = OMX_COLOR_FormatCbYCrY;
}
else if (iInFormat == PVMF_MIME_YUV422_INTERLEAVED_YUYV)
{
iOMXComponentInputBufferSize = iVideoInputFormat.iFrameWidth * iVideoInputFormat.iFrameHeight * 2;
iParamPort.format.video.eColorFormat = OMX_COLOR_FormatYCbYCr;
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem with input port %d color format", iNodeTypeId, iInputPortIndex));
return false;
}
//The input buffer size is a read-only parameter and the encoder component needs to adjust it.
// We (the client) determine the size of the buffers based on width/height -
// the component doesn't know width/height yet
//iParamPort.nBufferSize = iOMXComponentInputBufferSize;
// set the width and height of video frame and input framerate
iParamPort.format.video.nFrameWidth = iVideoInputFormat.iFrameWidth;
iParamPort.format.video.nFrameHeight = iVideoInputFormat.iFrameHeight;
// This is Q16 value, so shift by 16 first and cast to preserve accuracy
iParamPort.format.video.xFramerate = (uint32)(iVideoInputFormat.iFrameRate * (1 << 16));
// indicate that input is uncompressed so that color format is valid
iParamPort.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
// let the component decide about the number of input buffers
iNumInputBuffers = iParamPort.nBufferCountActual;
// do we need to increase the number of buffers?
if (iNumInputBuffers < iParamPort.nBufferCountMin)
iNumInputBuffers = iParamPort.nBufferCountMin;
/* OMX_UseBuffer, ie. if OMX client instead of OMX component is to allocate buffers,
* if the buffers are allocated in MIO, check MIO allocator the max number of buffers;
* else (the buffer is allocated by OMX client itself) floor the number of buffers to NUMBER_INPUT_BUFFER
* validate with OMX component whether it is ok with the number decided above.
* Note: the spec says in OMX_UseBuffer, the OMX client can decide number of input buffers.
*/
if(iOMXComponentSupportsExternalInputBufferAlloc)
{
ipExternalInputBufferAllocatorInterface = NULL;
PvmiKvp* kvp = NULL;
int numKvp = 0;
PvmiKeyType aIdentifier = (PvmiKeyType)PVMF_BUFFER_ALLOCATOR_KEY;
int32 err, err1;
OSCL_TRY(err, ((PVMFOMXEncPort*)iInPort)->pvmiGetBufferAllocatorSpecificInfoSync(aIdentifier, kvp, numKvp););
if ((err == OsclErrNone) && (NULL != kvp))
{
ipExternalInputBufferAllocatorInterface = (PVInterface*) kvp->value.key_specific_value;
if (ipExternalInputBufferAllocatorInterface)
{
PVInterface* pTempPVInterfacePtr = NULL;
OSCL_TRY(err, ipExternalInputBufferAllocatorInterface->queryInterface(PVMFFixedSizeBufferAllocUUID, pTempPVInterfacePtr););
OSCL_TRY(err1, ((PVMFOMXEncPort*)iInPort)->releaseParametersSync(kvp, numKvp););
OSCL_FIRST_CATCH_ANY(err1,
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "PVMFOMXEncNode-%s::NegotiateComponentParameters() - Unable to Release Parameters", iNodeTypeId));
);
if ((err == OsclErrNone) && (NULL != pTempPVInterfacePtr))
{
ipFixedSizeBufferAlloc = OSCL_STATIC_CAST(PVMFFixedSizeBufferAlloc*, pTempPVInterfacePtr);
uint32 iNumBuffers = ipFixedSizeBufferAlloc->getNumBuffers();
uint32 iBufferSize = ipFixedSizeBufferAlloc->getBufferSize();
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "PVMFOMXEncNode-%s iNumBuffers %d iBufferSize %d iOMXComponentInputBufferSize %d iParamPort.nBufferCountMin %d", iNodeTypeId, iNumBuffers , iBufferSize , iOMXComponentInputBufferSize, iParamPort.nBufferCountMin ) );
//TODO should let camera decide number of buffers.
if ((iNumBuffers < iParamPort.nBufferCountMin) || (iBufferSize < iOMXComponentInputBufferSize ))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::NegotiateComponentParameters() - not enough buffer. Got %d x %d. Require %d x %d", iNodeTypeId, iNumBuffers , iBufferSize , iOMXComponentInputBufferSize, iParamPort.nBufferCountMin));
//ipFixedSizeBufferAlloc = NULL;
ipExternalInputBufferAllocatorInterface->removeRef();
ipExternalInputBufferAllocatorInterface = NULL;
}
else
{
iNumInputBuffers = iNumBuffers;
iOMXComponentInputBufferSize = iBufferSize;
}
}
else
{
ipExternalInputBufferAllocatorInterface->removeRef();
ipExternalInputBufferAllocatorInterface = NULL;
}
}
}
}
// if component allows us to allocate buffers, we'll decide how many to allocate
if (iOMXComponentSupportsExternalInputBufferAlloc && (iParamPort.nBufferCountMin < NUMBER_INPUT_BUFFER))
{
if(NULL == ipFixedSizeBufferAlloc)
{
// preset the number of input buffers
iNumInputBuffers = NUMBER_INPUT_BUFFER;
}
}
// set the number of input buffer
iParamPort.nBufferCountActual = iNumInputBuffers;
// set the number of actual input buffers
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Inport buffers %d,size %d", iNodeTypeId, iNumInputBuffers, iOMXComponentInputBufferSize));
// lock in the input port parameters
CONFIG_SIZE_AND_VERSION(iParamPort);
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamPortDefinition, &iParamPort);
if (Err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem setting parameters in input port %d ", iNodeTypeId, iInputPortIndex));
return false;
}
//////////////////// OUTPUT PORT //////////////////////////////////////////////
CONFIG_SIZE_AND_VERSION(Video_port_format);
Video_port_format.nPortIndex = iOutputPortIndex; // set output port as target
OMX_VIDEO_CODINGTYPE DesiredPortFormat = OMX_VIDEO_CodingUnused;
if (iOutFormat == PVMF_MIME_M4V)
{
DesiredPortFormat = OMX_VIDEO_CodingMPEG4;
}
else if (iOutFormat == PVMF_MIME_H2631998 ||
iOutFormat == PVMF_MIME_H2632000)
{
DesiredPortFormat = OMX_VIDEO_CodingH263;
}
else if (iOutFormat == PVMF_MIME_H264_VIDEO_RAW ||
iOutFormat == PVMF_MIME_H264_VIDEO_MP4)
{
DesiredPortFormat = OMX_VIDEO_CodingAVC;
}
else
{
DesiredPortFormat = OMX_VIDEO_CodingUnused;
}
if (DesiredPortFormat == OMX_VIDEO_CodingUnused)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem with output port %d format", iNodeTypeId, iOutputPortIndex));
return false;
}
// loop over supported formats until we hit the one we want
// or until the component has no more supported formats (in which case it returns OMX_ErrorNoMore
Err = OMX_ErrorNone;
Video_port_format.nIndex = 0; //init the format counter
while (OMX_ErrorNone == Err)
{
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoPortFormat, &Video_port_format);
if ((OMX_ErrorNone != Err))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem getting port format for output port %d or no desired port format found", iNodeTypeId, iOutputPortIndex));
return false;
}
if ((Video_port_format.eCompressionFormat == DesiredPortFormat))
break;
Video_port_format.nIndex ++;
}
// OK, we've found the desired format, set it as the one used
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoPortFormat, &Video_port_format);
if ((OMX_ErrorNone != Err))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem setting port format for output port %d ", iNodeTypeId, iOutputPortIndex));
return false;
}
//Port 1 for output port
CONFIG_SIZE_AND_VERSION(iParamPort);
iParamPort.nPortIndex = iOutputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamPortDefinition, &iParamPort);
if (Err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem negotiating with output port %d ", iNodeTypeId, iOutputPortIndex));
return false;
}
// let the component decide num output buffers
iNumOutputBuffers = iParamPort.nBufferCountActual;
//check the number
if (iNumOutputBuffers < iParamPort.nBufferCountMin)
iNumOutputBuffers = iParamPort.nBufferCountMin;
// set the number ourselves
if (iOMXComponentSupportsExternalOutputBufferAlloc && (iParamPort.nBufferCountMin < NUMBER_OUTPUT_BUFFER))
{
iNumOutputBuffers = NUMBER_OUTPUT_BUFFER;
}
iParamPort.nBufferCountActual = iNumOutputBuffers;
// set the output (target) bitrate, framerate, width/height etc.
iParamPort.format.video.nFrameWidth = iVideoEncodeParam.iFrameWidth[0];
iParamPort.format.video.nFrameHeight = iVideoEncodeParam.iFrameHeight[0];
// Q16 value, cast after the shift to preserve the accuracy.
iParamPort.format.video.xFramerate = (uint32)(iVideoEncodeParam.iFrameRate[0] * (1 << 16));
iParamPort.format.video.nBitrate = iVideoEncodeParam.iBitRate[0];
iParamPort.format.video.eColorFormat = OMX_COLOR_FormatUnused;
if (iOutFormat == PVMF_MIME_M4V)
{
iParamPort.format.video.eCompressionFormat = OMX_VIDEO_CodingMPEG4;
}
else if (iOutFormat == PVMF_MIME_H2631998 ||
iOutFormat == PVMF_MIME_H2632000)
{
iParamPort.format.video.eCompressionFormat = OMX_VIDEO_CodingH263;
}
else if (iOutFormat == PVMF_MIME_H264_VIDEO_RAW ||
iOutFormat == PVMF_MIME_H264_VIDEO_MP4)
{
iParamPort.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
}
else
{
iParamPort.format.video.eCompressionFormat = OMX_VIDEO_CodingAutoDetect;
}
CONFIG_SIZE_AND_VERSION(iParamPort);
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamPortDefinition, &iParamPort);
if (Err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem setting parameters in output port %d ", iNodeTypeId, iOutputPortIndex));
return false;
}
//ask for the calculated buffer size
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamPortDefinition, &iParamPort);
if (Err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem negotiating with output port %d ", iNodeTypeId, iOutputPortIndex));
return false;
}
iOMXComponentOutputBufferSize = iParamPort.nBufferSize;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Outport buffers %d size %d", iNodeTypeId, iNumOutputBuffers, iOMXComponentOutputBufferSize));
CONFIG_SIZE_AND_VERSION(InputRotationType);
InputRotationType.nPortIndex = iInputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexConfigCommonRotate, &InputRotationType);
if (Err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem getting OMX_IndexConfigCommonRotate param ", iNodeTypeId));
}
//Set the OMX_CONFIG_ROTATIONTYPE parameters
InputRotationType.nRotation = ((iVideoInputFormat.iFrameOrientation == 1) ? 180 : 0);
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexConfigCommonRotate, &InputRotationType);
if (Err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem setting OMX_IndexConfigCommonRotate param ", iNodeTypeId));
}
// now call codec specific parameter setting
bool status = true;
if (iOutFormat == PVMF_MIME_M4V)
{
status = SetMP4EncoderParameters();
}
else if (iOutFormat == PVMF_MIME_H2631998 ||
iOutFormat == PVMF_MIME_H2632000)
{
status = SetH263EncoderParameters();
}
else if (iOutFormat == PVMF_MIME_H264_VIDEO_RAW ||
iOutFormat == PVMF_MIME_H264_VIDEO_MP4)
{
status = SetH264EncoderParameters();
}
return status;
}
bool PVMFOMXEncNode::SetMP4EncoderParameters()
{
OMX_ERRORTYPE Err = OMX_ErrorNone;
OMX_VIDEO_PARAM_MPEG4TYPE Mpeg4Type;
OMX_VIDEO_PARAM_BITRATETYPE BitRateType;
OMX_VIDEO_PARAM_QUANTIZATIONTYPE QuantParam;
OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE ErrCorrType;
// DV: VALUES HERE ARE FOR THE MOST PART HARDCODED BASED ON PV DEFAULTS
OMX_VIDEO_PARAM_MOTIONVECTORTYPE MotionVector;
OMX_VIDEO_PARAM_INTRAREFRESHTYPE RefreshParam;
CONFIG_SIZE_AND_VERSION(Mpeg4Type);
Mpeg4Type.nPortIndex = iOutputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoMpeg4, &Mpeg4Type);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId));
}
//Set the OMX_VIDEO_PARAM_MPEG4TYPE parameters
Mpeg4Type.nPortIndex = iOutputPortIndex;
// extra parameters - hardcoded
Mpeg4Type.nSliceHeaderSpacing = 0;
Mpeg4Type.bSVH = OMX_FALSE; //((iEncoderParam.iContentType == EI_H263)? true: false);
Mpeg4Type.bGov = OMX_FALSE; // disable or enable GOV header
// extra parameters - hardcoded
Mpeg4Type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
// params based on iFrame interval
if (iVideoEncodeParam.iIFrameInterval == -1) // encode only one frame
{
Mpeg4Type.nPFrames = 0xFFFFFFFF;
}
else if (iVideoEncodeParam.iIFrameInterval == 0) // no P frames
{
Mpeg4Type.nPFrames = 0;
Mpeg4Type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI; // maps to only supporting I-frames
}
else
{
Mpeg4Type.nPFrames = (OMX_U32)(iVideoEncodeParam.iIFrameInterval * iVideoEncodeParam.iFrameRate[0] - 1);
}
// extra parameters - hardcoded
Mpeg4Type.nBFrames = 0;
Mpeg4Type.nIDCVLCThreshold = 0;
Mpeg4Type.bACPred = OMX_TRUE;
Mpeg4Type.nMaxPacketSize = iVideoEncodeParam.iPacketSize;
Mpeg4Type.nTimeIncRes = 1000; // (in relation to (should be higher than) frame rate )
Mpeg4Type.nHeaderExtension = 0;
Mpeg4Type.bReversibleVLC = ((iVideoEncodeParam.iRVLCEnable == true) ? OMX_TRUE : OMX_FALSE);
switch (iVideoEncodeParam.iProfileLevel)
{
case EI_SIMPLE_LEVEL0:
Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileSimple;
Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level0;
break;
case EI_SIMPLE_LEVEL1:
Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileSimple;
Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level1;
break;
case EI_SIMPLE_LEVEL2:
Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileSimple;
Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level2;
break;
case EI_SIMPLE_LEVEL3:
Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileSimple;
Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level3;
break;
case EI_CORE_LEVEL1:
Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileCore;
Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level1;
break;
case EI_CORE_LEVEL2:
Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileCore;
Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level2;
break;
case EI_SIMPLE_SCALABLE_LEVEL0:
Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileSimpleScalable;
Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level0;
break;
case EI_SIMPLE_SCALABLE_LEVEL1:
Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileSimpleScalable;
Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level1;
break;
case EI_SIMPLE_SCALABLE_LEVEL2:
Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileSimpleScalable;
Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level2;
break;
case EI_CORE_SCALABLE_LEVEL1:
Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileCoreScalable;
Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level1;
break;
case EI_CORE_SCALABLE_LEVEL2:
Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileCoreScalable;
Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level2;
break;
case EI_CORE_SCALABLE_LEVEL3:
Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileCoreScalable;
Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level3;
break;
}
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoMpeg4, &Mpeg4Type);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId));
}
//OMX_VIDEO_PARAM_BITRATETYPE Settings
CONFIG_SIZE_AND_VERSION(BitRateType);
BitRateType.nPortIndex = iOutputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoBitrate, &BitRateType);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId));
}
//Set the parameters now
BitRateType.nPortIndex = iOutputPortIndex;
BitRateType.eControlRate = static_cast<OMX_VIDEO_CONTROLRATETYPE>(iVideoEncodeParam.iRateControlType);
BitRateType.nTargetBitrate = iVideoEncodeParam.iBitRate[0];
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoBitrate, &BitRateType);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId));
}
//OMX_VIDEO_PARAM_QUANTIZATIONTYPE Settings
if (BitRateType.eControlRate == OMX_Video_ControlRateDisable)
{
CONFIG_SIZE_AND_VERSION(QuantParam);
QuantParam.nPortIndex = iOutputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoQuantization, &QuantParam);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId));
}
//Set the parameters now
QuantParam.nPortIndex = iOutputPortIndex;
QuantParam.nQpI = DEFAULT_OMX_MP4ENC_QPI;
QuantParam.nQpP = DEFAULT_OMX_MP4ENC_QPP;
QuantParam.nQpB = DEFAULT_OMX_MP4ENC_QPB;
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoQuantization, &QuantParam);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId));
}
}
//OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE Settings (For streaming/2-way)
CONFIG_SIZE_AND_VERSION(ErrCorrType);
ErrCorrType.nPortIndex = iOutputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoErrorCorrection, &ErrCorrType);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId));
}
//Set the parameters now
ErrCorrType.nPortIndex = iOutputPortIndex;
ErrCorrType.bEnableDataPartitioning = ((iVideoEncodeParam.iDataPartitioning == true) ? OMX_TRUE : OMX_FALSE);
ErrCorrType.bEnableResync = ((iVideoEncodeParam.iResyncMarker == true) ? OMX_TRUE : OMX_FALSE);
// extra parameters - hardcoded
ErrCorrType.bEnableHEC = OMX_FALSE;
ErrCorrType.nResynchMarkerSpacing = iVideoEncodeParam.iPacketSize;
ErrCorrType.bEnableRVLC = ((iVideoEncodeParam.iRVLCEnable == true) ? OMX_TRUE : OMX_FALSE); // corresponds to encode param rvlcEnable
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoErrorCorrection, &ErrCorrType);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId));
}
//OMX_VIDEO_PARAM_MOTIONVECTORTYPE Settings
CONFIG_SIZE_AND_VERSION(MotionVector);
MotionVector.nPortIndex = iOutputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoMotionVector, &MotionVector);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId));
}
MotionVector.nPortIndex = iOutputPortIndex;
// extra parameters - hardcoded
MotionVector.sXSearchRange = iVideoEncodeParam.iSearchRange;
MotionVector.sYSearchRange = iVideoEncodeParam.iSearchRange;
MotionVector.bFourMV = ((iVideoEncodeParam.iMV8x8 == true) ? OMX_TRUE : OMX_FALSE);
MotionVector.eAccuracy = ((iVideoEncodeParam.iMVHalfPel == true) ? OMX_Video_MotionVectorHalfPel : OMX_Video_MotionVectorPixel);
MotionVector.bUnrestrictedMVs = OMX_TRUE;
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoMotionVector, &MotionVector);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId));
}
//OMX_VIDEO_PARAM_INTRAREFRESHTYPE Settings
CONFIG_SIZE_AND_VERSION(RefreshParam);
RefreshParam.nPortIndex = iOutputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoIntraRefresh, &RefreshParam);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId));
}
// extra parameters - hardcoded based on PV defaults
RefreshParam.nPortIndex = iOutputPortIndex;
RefreshParam.eRefreshMode = OMX_VIDEO_IntraRefreshBoth;
RefreshParam.nCirMBs = iVideoEncodeParam.iNumIntraMBRefresh;
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoIntraRefresh, &RefreshParam);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId));
}
return true;
}
bool PVMFOMXEncNode::SetH263EncoderParameters()
{
OMX_ERRORTYPE Err = OMX_ErrorNone;
OMX_VIDEO_PARAM_H263TYPE H263Type;
OMX_VIDEO_PARAM_BITRATETYPE BitRateType;
OMX_VIDEO_PARAM_QUANTIZATIONTYPE QuantParam;
OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE ErrCorrType;
// DV: VALUES HERE ARE FOR THE MOST PART HARDCODED BASED ON PV DEFAULTS
OMX_VIDEO_PARAM_MOTIONVECTORTYPE MotionVector;
OMX_VIDEO_PARAM_INTRAREFRESHTYPE RefreshParam;
CONFIG_SIZE_AND_VERSION(H263Type);
H263Type.nPortIndex = iOutputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoH263, &H263Type);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_GetParameter() failed for index(0x%x)", iNodeTypeId, OMX_IndexParamVideoH263));
}
//Set the OMX_VIDEO_PARAM_H263TYPE parameters
//DV: Here, we only set the nPFrames and AllowedFrameTypes, i.e. iIFrameInterval related variables
H263Type.nPortIndex = iOutputPortIndex;
H263Type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
if (iVideoEncodeParam.iIFrameInterval == -1) // encode only one I frame followed by P frames
{
H263Type.nPFrames = 0xFFFFFFFF;
}
else if (iVideoEncodeParam.iIFrameInterval == 0) // no P frames
{
H263Type.nPFrames = 0;
H263Type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI; // maps to only supporting I-frames
}
else
{
H263Type.nPFrames = (OMX_U32)(iVideoEncodeParam.iIFrameInterval * iVideoEncodeParam.iFrameRate[0] - 1);
}
// extra parameters - hardcoded
H263Type.nBFrames = 0;
H263Type.eProfile = OMX_VIDEO_H263ProfileBaseline;
// the supported level is up to OMX_VIDEO_H263Level45
if (H263Type.eLevel > OMX_VIDEO_H263Level45)
{
H263Type.eLevel = OMX_VIDEO_H263Level45;
}
H263Type.bPLUSPTYPEAllowed = OMX_FALSE;
H263Type.bForceRoundingTypeToZero = OMX_FALSE;
H263Type.nPictureHeaderRepetition = 0;
H263Type.nGOBHeaderInterval = 0;
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoH263, &H263Type);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_SetParameter() failed for index(0x%x)", iNodeTypeId, OMX_IndexParamVideoH263));
}
//OMX_VIDEO_PARAM_BITRATETYPE Settings
CONFIG_SIZE_AND_VERSION(BitRateType);
BitRateType.nPortIndex = iOutputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoBitrate, &BitRateType);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_GetParameter() failed for index(0x%x)", iNodeTypeId, OMX_IndexParamVideoBitrate));
}
//Set the parameters now
BitRateType.nPortIndex = iOutputPortIndex;
BitRateType.eControlRate = static_cast<OMX_VIDEO_CONTROLRATETYPE>(iVideoEncodeParam.iRateControlType);
BitRateType.nTargetBitrate = iVideoEncodeParam.iBitRate[0];
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoBitrate, &BitRateType);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_SetParameter() failed for index(0x%x)", iNodeTypeId, OMX_IndexParamVideoBitrate));
}
//OMX_VIDEO_PARAM_QUANTIZATIONTYPE Settings
if (BitRateType.eControlRate == OMX_Video_ControlRateDisable)
{
CONFIG_SIZE_AND_VERSION(QuantParam);
QuantParam.nPortIndex = iOutputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoQuantization, &QuantParam);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_GetParameter() failed for index(0x%x", iNodeTypeId, OMX_IndexParamVideoQuantization));
}
//Set the parameters now
QuantParam.nPortIndex = iOutputPortIndex;
QuantParam.nQpI = DEFAULT_OMX_MP4ENC_QPI;
QuantParam.nQpP = DEFAULT_OMX_MP4ENC_QPP;
QuantParam.nQpB = DEFAULT_OMX_MP4ENC_QPB;
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoQuantization, &QuantParam);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_SetParameter() failed for index(0x%x)", iNodeTypeId, OMX_IndexParamVideoQuantization));
}
}
//OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE Settings (For streaming/2-way)
CONFIG_SIZE_AND_VERSION(ErrCorrType);
ErrCorrType.nPortIndex = iOutputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoErrorCorrection, &ErrCorrType);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_GetParameter() faile for index(0x%x)", iNodeTypeId, OMX_IndexParamVideoErrorCorrection));
}
//Set the parameters now
ErrCorrType.nPortIndex = iOutputPortIndex;
//if (iVideoEncodeParam.iContentType == EI_M4V_STREAMING)
//{
// ErrCorrType.bEnableDataPartitioning = OMX_TRUE;
//}
//else
//{
// ErrCorrType.bEnableDataPartitioning = OMX_FALSE;
//}
ErrCorrType.bEnableHEC = OMX_FALSE;
ErrCorrType.bEnableResync = OMX_FALSE;
ErrCorrType.nResynchMarkerSpacing = 0;
ErrCorrType.bEnableRVLC = OMX_FALSE; // corresponds to encode param rvlcEnable
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoErrorCorrection, &ErrCorrType);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_SetParameter() failed for index(0x%x)", iNodeTypeId, OMX_IndexParamVideoErrorCorrection));
}
//OMX_VIDEO_PARAM_MOTIONVECTORTYPE Settings
CONFIG_SIZE_AND_VERSION(MotionVector);
MotionVector.nPortIndex = iOutputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoMotionVector, &MotionVector);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_GetParameter() failed for index(0x%x)", iNodeTypeId, OMX_IndexParamVideoMotionVector));
}
// extra parameters - hardcoded
MotionVector.sXSearchRange = iVideoEncodeParam.iSearchRange;
MotionVector.sYSearchRange = iVideoEncodeParam.iSearchRange;
MotionVector.bFourMV = OMX_FALSE;
MotionVector.eAccuracy = ((iVideoEncodeParam.iMVHalfPel == true) ? OMX_Video_MotionVectorHalfPel : OMX_Video_MotionVectorPixel);
MotionVector.bUnrestrictedMVs = OMX_FALSE;
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoMotionVector, &MotionVector);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_SetParameter() failed for index(0x%x", iNodeTypeId, OMX_IndexParamVideoMotionVector));
}
//OMX_VIDEO_PARAM_INTRAREFRESHTYPE Settings
CONFIG_SIZE_AND_VERSION(RefreshParam);
RefreshParam.nPortIndex = iOutputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoIntraRefresh, &RefreshParam);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_GetParameter() failed for index(0x%x)", iNodeTypeId, OMX_IndexParamVideoIntraRefresh));
}
// extra parameters - hardcoded based on PV defaults
RefreshParam.nPortIndex = iOutputPortIndex;
RefreshParam.eRefreshMode = OMX_VIDEO_IntraRefreshBoth;
RefreshParam.nCirMBs = iVideoEncodeParam.iNumIntraMBRefresh;
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoIntraRefresh, &RefreshParam);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_SetParameter() failed for index(0x%x)", iNodeTypeId, OMX_IndexParamVideoIntraRefresh));
}
return true;
}
bool PVMFOMXEncNode::SetH264EncoderParameters()
{
OMX_ERRORTYPE Err = OMX_ErrorNone;
OMX_VIDEO_PARAM_AVCTYPE H264Type;
OMX_VIDEO_PARAM_BITRATETYPE BitRateType;
OMX_VIDEO_PARAM_QUANTIZATIONTYPE QuantParam;
// to be refined
OMX_VIDEO_PARAM_MOTIONVECTORTYPE MotionVector;
OMX_VIDEO_PARAM_INTRAREFRESHTYPE RefreshParam;
OMX_VIDEO_PARAM_VBSMCTYPE VbsmcType;
CONFIG_SIZE_AND_VERSION(H264Type);
H264Type.nPortIndex = iOutputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoAvc, &H264Type);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH264EncoderParameters Parameter Invalid", iNodeTypeId));
}
H264Type.nPortIndex = iOutputPortIndex;
H264Type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
if (iVideoEncodeParam.iIFrameInterval == -1) // encode only one I frame followed by P frames
{
H264Type.nPFrames = 0xFFFFFFFF;
}
else if (iVideoEncodeParam.iIFrameInterval == 0) // no P frames
{
H264Type.nPFrames = 0;
H264Type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI; // maps to only supporting I-frames
}
else
{
H264Type.nPFrames = (OMX_U32)(iVideoEncodeParam.iIFrameInterval * iVideoEncodeParam.iFrameRate[0] - 1);
}
// extra parameters -hardcoded
H264Type.nSliceHeaderSpacing = 0;
H264Type.nBFrames = 0;
H264Type.bUseHadamard = OMX_TRUE;
H264Type.nRefFrames = 1;
H264Type.nRefIdx10ActiveMinus1 = 0;
H264Type.nRefIdx11ActiveMinus1 = 0;
H264Type.bEnableUEP = OMX_FALSE;
H264Type.bEnableFMO = OMX_FALSE;
H264Type.bEnableASO = OMX_FALSE;
H264Type.bEnableRS = OMX_FALSE;
//H264Type.eProfile = OMX_VIDEO_AVCProfileBaseline;
//H264Type.eLevel = OMX_VIDEO_AVCLevel1b;
H264Type.bFrameMBsOnly = OMX_TRUE;
H264Type.bMBAFF = OMX_FALSE;
H264Type.bEntropyCodingCABAC = OMX_FALSE;
H264Type.bWeightedPPrediction = OMX_FALSE;
H264Type.bconstIpred = OMX_FALSE;
H264Type.bDirect8x8Inference = OMX_FALSE;
H264Type.bDirectSpatialTemporal = OMX_FALSE;
H264Type.nCabacInitIdc = 0;
H264Type.eLoopFilterMode = OMX_VIDEO_AVCLoopFilterEnable;
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoAvc, &H264Type);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH264EncoderParameters Parameter Invalid", iNodeTypeId));
}
//OMX_VIDEO_PARAM_BITRATETYPE Settings
CONFIG_SIZE_AND_VERSION(BitRateType);
BitRateType.nPortIndex = iOutputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoBitrate, &BitRateType);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH264EncoderParameters Parameter Invalid", iNodeTypeId));
}
//Set the parameters now
BitRateType.nPortIndex = iOutputPortIndex;
BitRateType.eControlRate = static_cast<OMX_VIDEO_CONTROLRATETYPE>(iVideoEncodeParam.iRateControlType);
BitRateType.nTargetBitrate = iVideoEncodeParam.iBitRate[0];
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoBitrate, &BitRateType);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH264EncoderParameters Parameter Invalid", iNodeTypeId));
}
//OMX_VIDEO_PARAM_QUANTIZATIONTYPE Settings
if (BitRateType.eControlRate == OMX_Video_ControlRateDisable)
{
CONFIG_SIZE_AND_VERSION(QuantParam);
QuantParam.nPortIndex = iOutputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoQuantization, &QuantParam);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH264EncoderParameters Parameter Invalid", iNodeTypeId));
}
//Set the parameters now
QuantParam.nPortIndex = iOutputPortIndex;
QuantParam.nQpI = DEFAULT_OMX_AVCENC_QPI;
QuantParam.nQpP = DEFAULT_OMX_AVCENC_QPP;
QuantParam.nQpB = DEFAULT_OMX_AVCENC_QPB;
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoQuantization, &QuantParam);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH264EncoderParameters Parameter Invalid", iNodeTypeId));
}
}
//OMX_VIDEO_PARAM_MOTIONVECTORTYPE Settings
CONFIG_SIZE_AND_VERSION(MotionVector);
MotionVector.nPortIndex = iOutputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoMotionVector, &MotionVector);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH264EncoderParameters Parameter Invalid", iNodeTypeId));
}
// extra parameters - hardcoded
MotionVector.sXSearchRange = iVideoEncodeParam.iSearchRange;
MotionVector.sYSearchRange = iVideoEncodeParam.iSearchRange;
MotionVector.bFourMV = OMX_FALSE;
MotionVector.eAccuracy = OMX_Video_MotionVectorQuarterPel; // hardcoded
MotionVector.bUnrestrictedMVs = OMX_TRUE;
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoMotionVector, &MotionVector);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH264EncoderParameters Parameter Invalid", iNodeTypeId));
}
//OMX_VIDEO_PARAM_INTRAREFRESHTYPE Settings
CONFIG_SIZE_AND_VERSION(RefreshParam);
RefreshParam.nPortIndex = iOutputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoIntraRefresh, &RefreshParam);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH264EncoderParameters Parameter Invalid", iNodeTypeId));
}
// extra parameters - hardcoded based on PV defaults
RefreshParam.nPortIndex = iOutputPortIndex;
RefreshParam.eRefreshMode = OMX_VIDEO_IntraRefreshBoth;
RefreshParam.nCirMBs = iVideoEncodeParam.iNumIntraMBRefresh;
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoIntraRefresh, &RefreshParam);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH264EncoderParameters Parameter Invalid", iNodeTypeId));
}
CONFIG_SIZE_AND_VERSION(VbsmcType);
VbsmcType.nPortIndex = iOutputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoVBSMC, &VbsmcType);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH264EncoderParameters Parameter Invalid", iNodeTypeId));
}
VbsmcType.b16x16 = OMX_TRUE;
VbsmcType.b16x8 = VbsmcType.b8x16 = VbsmcType.b8x8 = VbsmcType.b8x4 = VbsmcType.b4x8 = VbsmcType.b4x4 = OMX_FALSE;
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoVBSMC, &VbsmcType);
if (OMX_ErrorNone != Err)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetH264EncoderParameters Parameter Invalid", iNodeTypeId));
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
bool PVMFOMXEncNode::NegotiateAudioComponentParameters()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioParameters() In", iNodeTypeId));
OMX_ERRORTYPE Err;
// first get the number of ports and port indices
OMX_PORT_PARAM_TYPE AudioPortParameters;
uint32 NumPorts;
uint32 ii;
// get starting number
CONFIG_SIZE_AND_VERSION(AudioPortParameters);
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamAudioInit, &AudioPortParameters);
NumPorts = AudioPortParameters.nPorts; // must be at least 2 of them (in&out)
if (Err != OMX_ErrorNone || NumPorts < 2)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioComponentParameters() There is insuffucient (%d) ports", iNodeTypeId, NumPorts));
return false;
}
// loop through ports starting from the starting index to find index of the first input port
for (ii = AudioPortParameters.nStartPortNumber ; ii < AudioPortParameters.nStartPortNumber + NumPorts; ii++)
{
// get port parameters, and determine if it is input or output
// if there are more than 2 ports, the first one we encounter that has input direction is picked
CONFIG_SIZE_AND_VERSION(iParamPort);
//port
iParamPort.nPortIndex = ii;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamPortDefinition, &iParamPort);
if (Err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioComponentParameters() Problem negotiating with port %d ", iNodeTypeId, ii));
return false;
}
if (iParamPort.eDir == OMX_DirInput)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioComponentParameters() Found Input port index %d ", iNodeTypeId, ii));
iInputPortIndex = ii;
break;
}
}
if (ii == AudioPortParameters.nStartPortNumber + NumPorts)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioComponentParameters() Cannot find any input port ", iNodeTypeId));
return false;
}
// loop through ports starting from the starting index to find index of the first output port
for (ii = AudioPortParameters.nStartPortNumber ; ii < AudioPortParameters.nStartPortNumber + NumPorts; ii++)
{
// get port parameters, and determine if it is input or output
// if there are more than 2 ports, the first one we encounter that has output direction is picked
CONFIG_SIZE_AND_VERSION(iParamPort);
//port
iParamPort.nPortIndex = ii;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamPortDefinition, &iParamPort);
if (Err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioComponentParameters() Problem negotiating with port %d ", iNodeTypeId, ii));
return false;
}
if (iParamPort.eDir == OMX_DirOutput)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioComponentParameters() Found Output port index %d ", iNodeTypeId, ii));
iOutputPortIndex = ii;
break;
}
}
if (ii == AudioPortParameters.nStartPortNumber + NumPorts)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioComponentParameters() Cannot find any output port ", iNodeTypeId));
return false;
}
// now get input parameters
//INPUT PORT
// first basic check if encode parameters have been set correctly
if ((0 == iAudioEncodeParam.iMaxNumOutputFramesPerBuffer) ||
(0 == iAudioEncodeParam.iAMRBitrate) ||
(0 == iAudioEncodeParam.iOutputNumChannels) ||
(2 < iAudioEncodeParam.iOutputNumChannels) ||
(0 == iAudioEncodeParam.iOutputSamplingRate) ||
(0 == iAudioInputFormat.iInputBitsPerSample) ||
(0 == iAudioInputFormat.iInputNumChannels) ||
(2 < iAudioInputFormat.iInputNumChannels) ||
(0 == iAudioInputFormat.iInputSamplingRate)
)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioComponentParameters() Encode parameters not set correctly", iNodeTypeId));
return false;
}
// first of all, check if the port supports the adequate port format
OMX_AUDIO_PARAM_PORTFORMATTYPE Audio_port_format;
OMX_AUDIO_CODINGTYPE DesiredPortFormat = OMX_AUDIO_CodingPCM;
CONFIG_SIZE_AND_VERSION(Audio_port_format);
Audio_port_format.nPortIndex = iInputPortIndex; // set input port as target
// loop over supported formats until we hit the one we want
// or until the component has no more supported formats (in which case it returns OMX_ErrorNoMore
Err = OMX_ErrorNone;
Audio_port_format.nIndex = 0; //init the format counter
while (OMX_ErrorNone == Err)
{
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamAudioPortFormat, &Audio_port_format);
if ((OMX_ErrorNone != Err))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioComponentParameters() Problem getting port format for input port %d or no desired port format found", iNodeTypeId, iInputPortIndex));
return false;
}
if (Audio_port_format.eEncoding == DesiredPortFormat)
break;
Audio_port_format.nIndex ++;
}
// OK, we've found the desired format, set it as the one used
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamAudioPortFormat, &Audio_port_format);
if ((OMX_ErrorNone != Err))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioComponentParameters() Problem setting port format for input port %d ", iNodeTypeId, iInputPortIndex));
return false;
}
CONFIG_SIZE_AND_VERSION(iParamPort);
iParamPort.nPortIndex = iInputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamPortDefinition, &iParamPort);
if (Err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioComponentParameters() Problem negotiating with input port %d ", iNodeTypeId, iInputPortIndex));
return false;
}
// TODO: FIX THIS - JUST READ THE BUFFER SIZE FROM COMPONENT PORT
if (iInFormat == PVMF_MIME_PCM16)
{
iOMXComponentInputBufferSize = MAX_NUM_AMR_FRAMES_PER_BUFFER * (PVMF_AMRENC_DEFAULT_FRAME_DURATION * PVMF_AMRENC_DEFAULT_SAMPLING_RATE * PVMF_AMRENC_DEFAULT_BITSPERSAMPLE) / (1000 * 8);
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioComponentParameters() Problem with input port %d color format", iNodeTypeId, iInputPortIndex));
return false;
}
// The buffer size is a read only parameter. If the requested size is larger than what we wish to allocate -
// we'll allocate what the component desires
if (iParamPort.nBufferSize > iOMXComponentInputBufferSize)
{
iOMXComponentInputBufferSize = iParamPort.nBufferSize;
}
// set Encoding type
//iParamPort.format.audio.bFlagErrorConcealment = OMX_TRUE;
// indicate that input is uncompressed i.e. PCM
iParamPort.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
// let the component decide about the number of input buffers
iNumInputBuffers = iParamPort.nBufferCountActual;
// do we need to increase the number of buffers?
if (iNumInputBuffers < iParamPort.nBufferCountMin)
iNumInputBuffers = iParamPort.nBufferCountMin;
// if component allows us to allocate buffers, we'll decide how many to allocate
if (iOMXComponentSupportsExternalInputBufferAlloc && (iParamPort.nBufferCountMin < NUMBER_INPUT_BUFFER))
{
// preset the number of input buffers
iNumInputBuffers = NUMBER_INPUT_BUFFER;
}
// set the number of input buffer
iParamPort.nBufferCountActual = iNumInputBuffers;
// set the number of actual input buffers
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioComponentParameters() Inport buffers %d,size %d", iNodeTypeId, iNumInputBuffers, iOMXComponentInputBufferSize));
// lock in the input port parameters
CONFIG_SIZE_AND_VERSION(iParamPort);
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamPortDefinition, &iParamPort);
if (Err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioComponentParameters() Problem setting parameters in input port %d ", iNodeTypeId, iInputPortIndex));
return false;
}
// For INPUT, we also need to set the PCM parameters, such as sampling rate, etc.
// GET the output buffer params and sizes
OMX_AUDIO_PARAM_PCMMODETYPE Audio_Pcm_Param;
Audio_Pcm_Param.nPortIndex = iInputPortIndex;
CONFIG_SIZE_AND_VERSION(Audio_Pcm_Param);
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamAudioPcm, &Audio_Pcm_Param);
if (Err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioComponentParameters() Problem getting PCM parameters with input port %d ", iNodeTypeId, iInputPortIndex));
return false;
}
Audio_Pcm_Param.nChannels = (OMX_U32) iAudioInputFormat.iInputNumChannels;
Audio_Pcm_Param.eNumData = OMX_NumericalDataSigned; // signed
Audio_Pcm_Param.eEndian = OMX_EndianLittle; // little-endian
Audio_Pcm_Param.bInterleaved = ((EINTERLEAVE_LR == iAudioInputFormat.iInputInterleaveMode) ? OMX_TRUE : OMX_FALSE);
Audio_Pcm_Param.nBitPerSample = (OMX_U32) iAudioInputFormat.iInputBitsPerSample;
Audio_Pcm_Param.nSamplingRate = (OMX_U32) iAudioInputFormat.iInputSamplingRate;
Audio_Pcm_Param.ePCMMode = OMX_AUDIO_PCMModeLinear;
// don't set - let use default Audio_Pcm_Param.eChannelMapping
CONFIG_SIZE_AND_VERSION(Audio_Pcm_Param);
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamAudioPcm, &Audio_Pcm_Param);
if (Err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioComponentParameters() Problem setting PCM parameters with input port %d ", iNodeTypeId, iInputPortIndex));
return false;
}
//////////////////////// OUTPUT PORT////////////////////////////////////////////////
// first of all, check if the port supports the adequate port format
if ((iOutFormat == PVMF_MIME_AMR_IETF) ||
(iOutFormat == PVMF_MIME_AMRWB_IETF) ||
(iOutFormat == PVMF_MIME_AMR_IF2))
{
DesiredPortFormat = OMX_AUDIO_CodingAMR;
}
else if ((iOutFormat == PVMF_MIME_ADIF) ||
(iOutFormat == PVMF_MIME_ADTS) ||
(iOutFormat == PVMF_MIME_MPEG4_AUDIO))
{
DesiredPortFormat = OMX_AUDIO_CodingAAC;
}
else
{
DesiredPortFormat = OMX_AUDIO_CodingUnused;
}
if (DesiredPortFormat == OMX_AUDIO_CodingUnused)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioComponentParameters() Problem with output port %d format", iNodeTypeId, iOutputPortIndex));
return false;
}
CONFIG_SIZE_AND_VERSION(Audio_port_format);
Audio_port_format.nPortIndex = iOutputPortIndex; // set output port as target
// loop over supported formats until we hit the one we want
// or until the component has no more supported formats (in which case it returns OMX_ErrorNoMore
Err = OMX_ErrorNone;
Audio_port_format.nIndex = 0; //init the format counter
while (OMX_ErrorNone == Err)
{
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamAudioPortFormat, &Audio_port_format);
if ((OMX_ErrorNone != Err))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioComponentParameters() Problem getting port format for output port %d or no desired port format found", iNodeTypeId, iOutputPortIndex));
return false;
}
if (Audio_port_format.eEncoding == DesiredPortFormat)
break;
Audio_port_format.nIndex ++;
}
// OK, we've found the desired format, set it as the one used
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamAudioPortFormat, &Audio_port_format);
if ((OMX_ErrorNone != Err))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioComponentParameters() Problem setting port format for output port %d ", iNodeTypeId, iOutputPortIndex));
return false;
}
//Port 1 for output port
CONFIG_SIZE_AND_VERSION(iParamPort);
iParamPort.nPortIndex = iOutputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamPortDefinition, &iParamPort);
if (Err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioComponentParameters() Problem negotiating with output port %d ", iNodeTypeId, iOutputPortIndex));
return false;
}
// let the component decide output buffer size
iOMXComponentOutputBufferSize = iParamPort.nBufferSize;
// let the component decide num output buffers
iNumOutputBuffers = iParamPort.nBufferCountActual;
//check the number
if (iNumOutputBuffers < iParamPort.nBufferCountMin)
iNumOutputBuffers = iParamPort.nBufferCountMin;
// set the number ourselves
if (iOMXComponentSupportsExternalOutputBufferAlloc && (iParamPort.nBufferCountMin < NUMBER_OUTPUT_BUFFER))
{
iNumOutputBuffers = NUMBER_OUTPUT_BUFFER;
}
iParamPort.nBufferCountActual = iNumOutputBuffers;
// set the output (target) format, etc.
iParamPort.format.audio.bFlagErrorConcealment = OMX_TRUE;
if ((iOutFormat == PVMF_MIME_AMR_IETF) ||
(iOutFormat == PVMF_MIME_AMRWB_IETF) ||
(iOutFormat == PVMF_MIME_AMR_IF2))
{
iParamPort.format.audio.eEncoding = OMX_AUDIO_CodingAMR;
}
else if ((iOutFormat == PVMF_MIME_ADTS) ||
(iOutFormat == PVMF_MIME_ADIF) ||
(iOutFormat == PVMF_MIME_MPEG4_AUDIO))
{
iParamPort.format.audio.eEncoding = OMX_AUDIO_CodingAAC;
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioComponentParameters() Outport buffers %d,size %d", iNodeTypeId, iNumOutputBuffers, iOMXComponentOutputBufferSize));
CONFIG_SIZE_AND_VERSION(iParamPort);
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamPortDefinition, &iParamPort);
if (Err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::NegotiateAudioComponentParameters() Problem setting parameters in output port %d ", iNodeTypeId, iOutputPortIndex));
return false;
}
// now call codec specific parameter setting
bool status = true;
if ((iOutFormat == PVMF_MIME_AMR_IETF) ||
(iOutFormat == PVMF_MIME_AMRWB_IETF) ||
(iOutFormat == PVMF_MIME_AMR_IF2))
{
status = SetAMREncoderParameters();
}
else if ((iOutFormat == PVMF_MIME_ADTS) ||
(iOutFormat == PVMF_MIME_ADIF) ||
(iOutFormat == PVMF_MIME_MPEG4_AUDIO))
{
status = SetAACEncoderParameters();
}
return status;
}
bool PVMFOMXEncNode::SetAMREncoderParameters()
{
OMX_ERRORTYPE Err = OMX_ErrorNone;
OMX_AUDIO_PARAM_AMRTYPE AmrType;
CONFIG_SIZE_AND_VERSION(AmrType);
AmrType.nPortIndex = iOutputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamAudioAmr, &AmrType);
if (Err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetAMREncoderParameters - Problem getting AMR parameters in output port %d ", iNodeTypeId, iOutputPortIndex));
return false;
}
AmrType.nChannels = iAudioEncodeParam.iOutputNumChannels; // must be 1
switch (iAudioEncodeParam.iAMRBitrate)
{
case GSM_AMR_4_75: // AMR NB bitrates
AmrType.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0;
break;
case GSM_AMR_5_15:
AmrType.eAMRBandMode = OMX_AUDIO_AMRBandModeNB1;
break;
case GSM_AMR_5_90:
AmrType.eAMRBandMode = OMX_AUDIO_AMRBandModeNB2;
break;
case GSM_AMR_6_70:
AmrType.eAMRBandMode = OMX_AUDIO_AMRBandModeNB3;
break;
case GSM_AMR_7_40:
AmrType.eAMRBandMode = OMX_AUDIO_AMRBandModeNB4;
break;
case GSM_AMR_7_95:
AmrType.eAMRBandMode = OMX_AUDIO_AMRBandModeNB5;
break;
case GSM_AMR_10_2:
AmrType.eAMRBandMode = OMX_AUDIO_AMRBandModeNB6;
break;
case GSM_AMR_12_2:
AmrType.eAMRBandMode = OMX_AUDIO_AMRBandModeNB7;
break;
case GSM_AMR_6_60: // AMR WB bitrates start here
AmrType.eAMRBandMode = OMX_AUDIO_AMRBandModeWB0;
break;
case GSM_AMR_8_85:
AmrType.eAMRBandMode = OMX_AUDIO_AMRBandModeWB1;
break;
case GSM_AMR_12_65:
AmrType.eAMRBandMode = OMX_AUDIO_AMRBandModeWB2;
break;
case GSM_AMR_14_25:
AmrType.eAMRBandMode = OMX_AUDIO_AMRBandModeWB3;
break;
case GSM_AMR_15_85:
AmrType.eAMRBandMode = OMX_AUDIO_AMRBandModeWB4;
break;
case GSM_AMR_18_25:
AmrType.eAMRBandMode = OMX_AUDIO_AMRBandModeWB5;
break;
case GSM_AMR_19_85:
AmrType.eAMRBandMode = OMX_AUDIO_AMRBandModeWB6;
break;
case GSM_AMR_23_05:
AmrType.eAMRBandMode = OMX_AUDIO_AMRBandModeWB7;
break;
case GSM_AMR_23_85:
AmrType.eAMRBandMode = OMX_AUDIO_AMRBandModeWB8;
break;
default:
return false;
}
AmrType.eAMRDTXMode = OMX_AUDIO_AMRDTXModeOnAuto;
if ((iOutFormat == PVMF_MIME_AMR_IETF) || (iOutFormat == PVMF_MIME_AMRWB_IETF))
{
AmrType.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
}
else if (iOutFormat == PVMF_MIME_AMR_IF2)
{
AmrType.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatIF2;
}
CONFIG_SIZE_AND_VERSION(AmrType);
AmrType.nPortIndex = iOutputPortIndex;
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamAudioAmr, &AmrType);
if (Err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetAMREncoderParameters - Problem setting AMR parameters in output port %d ", iNodeTypeId, iOutputPortIndex));
return false;
}
return true;
}
bool PVMFOMXEncNode::SetAACEncoderParameters()
{
OMX_ERRORTYPE Err = OMX_ErrorNone;
OMX_AUDIO_PARAM_AACPROFILETYPE AacType;
CONFIG_SIZE_AND_VERSION(AacType);
AacType.nPortIndex = iOutputPortIndex;
Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamAudioAac, &AacType);
if (Err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetAACEncoderParameters - Problem getting AAC parameters in output port %d ", iNodeTypeId, iOutputPortIndex));
return false;
}
AacType.nChannels = iAudioEncodeParam.iOutputNumChannels;
// The following parameter could be set to input sampling rate or 0 (i.e. unknown)
AacType.nSampleRate = iAudioEncodeParam.iOutputSamplingRate;
// The following parameter could be set to 0 (i.e. unknown)
AacType.nBitRate = iAudioEncodeParam.iOutputBitrate;
// Let encoder decide the following parameters - i.e. set to 0
AacType.nAudioBandWidth = 0;
AacType.nFrameLength = 0;
AacType.nAACtools = OMX_AUDIO_AACToolAll; // this means all tools are allowed - let encoder decide
AacType.nAACERtools = OMX_AUDIO_AACERNone; // error resilience tools are not allowed
// Set the AAC profile to use LC
AacType.eAACProfile = OMX_AUDIO_AACObjectLC;
// Do set the stream format
if (iOutFormat == PVMF_MIME_ADTS)
{
AacType.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
}
else if (iOutFormat == PVMF_MIME_ADIF)
{
AacType.eAACStreamFormat = OMX_AUDIO_AACStreamFormatADIF;
}
else if (iOutFormat == PVMF_MIME_MPEG4_AUDIO)
{
AacType.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
}
// Set the AAC channel mode - (stereo, or mono)
if (iAudioEncodeParam.iOutputNumChannels == 1)
{
AacType.eChannelMode = OMX_AUDIO_ChannelModeMono;
}
else if (iAudioEncodeParam.iOutputNumChannels == 2)
{
AacType.eChannelMode = OMX_AUDIO_ChannelModeStereo;
}
CONFIG_SIZE_AND_VERSION(AacType);
AacType.nPortIndex = iOutputPortIndex;
Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamAudioAac, &AacType);
if (Err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetAACEncoderParameters - Problem setting AAC parameters in output port %d ", iNodeTypeId, iOutputPortIndex));
return false;
}
return true;
}
bool PVMFOMXEncNode::SetDefaultCapabilityFlags()
{
iIsOMXComponentMultiThreaded = true;
iOMXComponentSupportsExternalOutputBufferAlloc = false;
iOMXComponentSupportsExternalInputBufferAlloc = false;
iOMXComponentSupportsMovableInputBuffers = false;
iOMXComponentUsesNALStartCodes = true;
iOMXComponentSupportsPartialFrames = false;
iOMXComponentCanHandleIncompleteFrames = false;
iOMXComponentUsesFullAVCFrames = false;
return true;
}
bool PVMFOMXEncNode::SendEOSBufferToOMXComponent()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SendEOSBufferToOMXComponent() In", iNodeTypeId));
// first of all, check if the component is running. EOS could be sent prior to component/encoder
// even being initialized
// returning false will ensure that the EOS will be sent downstream anyway without waiting for the
// Component to respond
if (iCurrentEncoderState != OMX_StateExecuting)
return false;
// get an input buffer. Without a buffer, no point in proceeding
InputBufCtrlStruct *input_buf = NULL;
int32 errcode = 0;
// we already checked that the number of buffers is OK, so we don't expect problems
// try to get input buffer header
OSCL_TRY(errcode, input_buf = (InputBufCtrlStruct *) iInBufMemoryPool->allocate(iInputAllocSize));
if (errcode != 0)
{
if (errcode == OsclErrNoResources)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger,
PVLOGMSG_DEBUG, (0, "PVMFOMXEncNode-%s::SendEOSBufferToOMXComponent() No more buffers in the mempool - unexpected", iNodeTypeId));
iInBufMemoryPool->notifyfreechunkavailable(*this, (OsclAny*) iInBufMemoryPool); // To signal when next deallocate() is called on mempool
return false;
}
else
{
// Memory allocation for the pool failed
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SendEOSBufferToOMXComponent() Input mempool error", iNodeTypeId));
SetState(EPVMFNodeError);
ReportErrorEvent(PVMFErrNoMemory);
return false;
}
}
// keep track of buffers. When buffer is deallocated/released, the counter will be decremented
iInBufMemoryPool->notifyfreechunkavailable(*this, (OsclAny*) iInBufMemoryPool);
iNumOutstandingInputBuffers++;
// in this case, no need to use input msg refcounter. Make sure its unbound
(input_buf->pMediaData).Unbind();
// THIS IS AN EMPTY BUFFER. FLAGS ARE THE ONLY IMPORTANT THING
input_buf->pBufHdr->nFilledLen = 0;
input_buf->pBufHdr->nOffset = 0;
iInputTimestampClock.update_clock(iEndOfDataTimestamp); // this will also take into consideration the rollover
// convert TS in input timescale into OMX_TICKS
iOMXTicksTimestamp = ConvertTimestampIntoOMXTicks(iInputTimestampClock);
input_buf->pBufHdr->nTimeStamp = iOMXTicksTimestamp;
// set ptr to input_buf structure for Context (for when the buffer is returned)
input_buf->pBufHdr->pAppPrivate = (OMX_PTR) input_buf;
// do not use Mark here (but init to NULL to prevent problems)
input_buf->pBufHdr->hMarkTargetComponent = NULL;
input_buf->pBufHdr->pMarkData = NULL;
// init buffer flags
input_buf->pBufHdr->nFlags = 0;
input_buf->pBufHdr->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
// most importantly, set the EOS flag:
input_buf->pBufHdr->nFlags |= OMX_BUFFERFLAG_EOS;
// send buffer to component
OMX_EmptyThisBuffer(iOMXEncoder, input_buf->pBufHdr);
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SendEOSBufferToOMXComponent() Out", iNodeTypeId));
return true;
}
bool PVMFOMXEncNode::SendInputBufferToOMXComponent()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SendInputBufferToOMXComponent() In", iNodeTypeId));
// first of all , get an input buffer. Without a buffer, no point in proceeding
InputBufCtrlStruct *input_buf = NULL;
int32 errcode = 0;
uint32 ii;
do
{
// do loop to loop over all fragments
// try to get input buffer header
InputBufCtrlStruct *temp = NULL;
OSCL_TRY(errcode, temp = (InputBufCtrlStruct *) iInBufMemoryPool->allocate(iInputAllocSize));
//input_buf = temp; //JJDBG
if (errcode != 0)
{
if (errcode == OsclErrNoResources)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger,
PVLOGMSG_DEBUG, (0, "PVMFOMXEncNode-%s::SendInputBufferToOMXComponent() No more buffers in the mempool", iNodeTypeId));
iInBufMemoryPool->notifyfreechunkavailable(*this, (OsclAny*) iInBufMemoryPool); // To signal when next deallocate() is called on mempool
return false;
}
else
{
// Memory allocation for the pool failed
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SendInputBufferToOMXComponent() Input mempool error", iNodeTypeId));
SetState(EPVMFNodeError);
ReportErrorEvent(PVMFErrNoMemory);
return false;
}
}
input_buf = new(temp)InputBufCtrlStruct ; //JJDBG
// keep track of buffers. When buffer is deallocated/released, the counter will be decremented
iInBufMemoryPool->notifyfreechunkavailable(*this, (OsclAny*) iInBufMemoryPool);
iNumOutstandingInputBuffers++;
for (ii = 0; ii < iNumInputBuffers; ii++)
{
if (input_buf == in_ctrl_struct_ptr[ii])
{
break;
}
}
if (ii == iNumInputBuffers)
return false;
input_buf->pBufHdr = (OMX_BUFFERHEADERTYPE *)in_buff_hdr_ptr[ii];
// Now we have the buffer header (i.e. a buffer) to send to component:
// Depending on OMX component capabilities, either pass the input msg fragment(s) directly
// into OMX component without copying (and update the input msg refcount)
// or memcopy the content of input msg memfrag(s) into OMX component allocated buffers
// if this is the first fragment in a new message, extract some info:
if (iCurrFragNum == 0)
{
// NOTE: SeqNum differ in Codec and in Node because of the fact that
// one msg can contain multiple fragments that are sent to the codec as
// separate buffers. Node tracks msgs and codec tracks even separate fragments
iCodecSeqNum += (iDataIn->getSeqNum() - iInPacketSeqNum); // increment the codec seq. # by the same
// amount that the input seq. number increased
iInPacketSeqNum = iDataIn->getSeqNum(); // remember input sequence number
iInTimestamp = iDataIn->getTimestamp();
iInDuration = iDataIn->getDuration();
iInNumFrags = iDataIn->getNumFragments();
iCurrentMsgMarkerBit = iDataIn->getMarkerInfo() & PVMF_MEDIA_DATA_MARKER_INFO_M_BIT;
// logging info:
if (iDataIn->getNumFragments() > 1)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SendInputBufferToOMXComponent() - New msg has MULTI-FRAGMENTS", iNodeTypeId));
}
if (!(iDataIn->getMarkerInfo() & PVMF_MEDIA_DATA_MARKER_INFO_M_BIT))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SendInputBufferToOMXComponent() - New msg has NO MARKER BIT", iNodeTypeId));
}
}
// get a memfrag from the message
OsclRefCounterMemFrag frag;
iDataIn->getMediaFragment(iCurrFragNum, frag);
if (iOMXComponentSupportsMovableInputBuffers)
{
// no copying required
// increment the RefCounter of the message associated with the mem fragment/buffer
// when sending this buffer to OMX component. (When getting the buffer back, the refcounter
// will be decremented. Thus, when the last fragment is returned, the input mssage is finally released
iDataIn.GetRefCounter()->addRef();
// associate the buffer ctrl structure with the message ref counter and ptr
input_buf->pMediaData = PVMFSharedMediaDataPtr(iDataIn.GetRep(), iDataIn.GetRefCounter());
// set pointer to the data, length, offset
input_buf->pBufHdr->pBuffer = (uint8 *)frag.getMemFragPtr();
input_buf->pBufHdr->nFilledLen = frag.getMemFragSize();
{//TODO: check whether addRef() is needed for fsi
OsclRefCounterMemFrag fsifrag;
iDataIn->getFormatSpecificInfo(fsifrag);
if(sizeof(OsclAny*) != fsifrag.getMemFrag().len )
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SendInputBufferToOMXComponent() - ERROR buffer size %d", iNodeTypeId, fsifrag.getMemFrag().len ));
return false;
}
oscl_memcpy(&(input_buf->pBufHdr->pPlatformPrivate), fsifrag.getMemFragPtr(), sizeof(OsclAny*) ); // restore ptr data from fsi
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SendInputBufferToOMXComponent() - Buffer 0x%x of size %d, %d frag out of tot. %d, TS=%d, Ticks=%L", iNodeTypeId, input_buf->pBufHdr->pBuffer, frag.getMemFragSize(), iCurrFragNum + 1, iDataIn->getNumFragments(), iInTimestamp, iOMXTicksTimestamp));
iCurrFragNum++; // increment fragment number and move on to the next
}
else
{
// in this case, no need to use input msg refcounter, each buffer fragment is copied over and treated separately
(input_buf->pMediaData).Unbind();
// init variables
iCopyPosition = 0;
iFragmentSizeRemainingToCopy = frag.getMemFragSize();
// can the remaining fragment fit into the buffer?
if (iFragmentSizeRemainingToCopy <= (input_buf->pBufHdr->nAllocLen))
{
oscl_memcpy(input_buf->pBufHdr->pBuffer,
(void *)((uint8 *)frag.getMemFragPtr() + iCopyPosition),
iFragmentSizeRemainingToCopy);
input_buf->pBufHdr->nFilledLen = iFragmentSizeRemainingToCopy;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SendInputBufferToOMXComponent() - Copied %d bytes of fragment %d out of %d into buffer 0x%x of size %d, TS=%d, Ticks=%L ", iNodeTypeId, iFragmentSizeRemainingToCopy, iCurrFragNum + 1, iDataIn->getNumFragments(), input_buf->pBufHdr->pBuffer, input_buf->pBufHdr->nFilledLen, iInTimestamp, iOMXTicksTimestamp));
iCopyPosition += iFragmentSizeRemainingToCopy;
iFragmentSizeRemainingToCopy = 0;
}
else
{
// copy as much as you can of the current fragment into the current buffer
oscl_memcpy(input_buf->pBufHdr->pBuffer,
(void *)((uint8 *)frag.getMemFragPtr() + iCopyPosition),
input_buf->pBufHdr->nAllocLen);
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SendInputBufferToOMXComponent() - Frame cannot fit into input buffer ! Copied %d bytes of fragment %d out of %d into buffer 0x%x of size %d, TS=%d, Ticks=%L", iNodeTypeId, input_buf->pBufHdr->nAllocLen, iCurrFragNum + 1, iDataIn->getNumFragments(), input_buf->pBufHdr->pBuffer, input_buf->pBufHdr->nFilledLen, iInTimestamp, iOMXTicksTimestamp));
input_buf->pBufHdr->nFilledLen = input_buf->pBufHdr->nAllocLen;
iCopyPosition += input_buf->pBufHdr->nAllocLen; // move current position within fragment forward
iFragmentSizeRemainingToCopy -= input_buf->pBufHdr->nAllocLen;
}
// proceed to the next fragment regardless of input buffer size
iCurrFragNum++;
}
// set buffer fields (this is the same regardless of whether the input is movable or not
input_buf->pBufHdr->nOffset = 0;
iInputTimestampClock.update_clock(iInTimestamp); // this will also take into consideration the timestamp rollover
// convert TS in input timescale into OMX_TICKS
iOMXTicksTimestamp = ConvertTimestampIntoOMXTicks(iInputTimestampClock);
input_buf->pBufHdr->nTimeStamp = iOMXTicksTimestamp;
// set ptr to input_buf structure for Context (for when the buffer is returned)
input_buf->pBufHdr->pAppPrivate = (OMX_PTR) input_buf;
// do not use Mark here (but init to NULL to prevent problems)
input_buf->pBufHdr->hMarkTargetComponent = NULL;
input_buf->pBufHdr->pMarkData = NULL;
// init buffer flags
input_buf->pBufHdr->nFlags = 0;
// set the key frame flag if necessary (mark every fragment that belongs to it)
if (iDataIn->getMarkerInfo() & PVMF_MEDIA_DATA_MARKER_INFO_RANDOM_ACCESS_POINT_BIT)
input_buf->pBufHdr->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
// in case of encoder, all input frames should be marked
input_buf->pBufHdr->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
OMX_ERRORTYPE myret = OMX_EmptyThisBuffer(iOMXEncoder, input_buf->pBufHdr);
if(OMX_ErrorNone != myret )
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SendInputBufferToOMXComponent() OMX_EmptyThisBuffer ERROR %d", iNodeTypeId, myret));
return false;
}
// if we sent all fragments to OMX component, decouple the input message from iDataIn
// Input message is "decoupled", so that we can get a new message for processing into iDataIn
// However, the actual message is released completely to upstream mempool once all of its fragments
// are returned by the OMX component
if (iCurrFragNum == iDataIn->getNumFragments())
{
iDataIn.Unbind();
}
}
while (iCurrFragNum < iInNumFrags); //iDataIn->getNumFragments());
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SendInputBufferToOMXComponent() Out", iNodeTypeId));
return true;
}
/////////////////////////////////////////////////////////////////////////////
bool PVMFOMXEncNode::CreateOutMemPool(uint32 num_buffers)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::CreateOutMemPool() start", iNodeTypeId));
// In the case OMX component wants to allocate its own buffers,
// mempool only contains OutputBufCtrlStructures (i.e. ptrs to buffer headers)
// In case OMX component uses pre-allocated buffers (here),
// mempool allocates OutputBufCtrlStructure (i.e. ptrs to buffer hdrs), followed by actual buffers
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::CreateOutMemPool() Allocating output buffer header pointers", iNodeTypeId));
iOutputAllocSize = oscl_mem_aligned_size((uint32)sizeof(OutputBufCtrlStruct));
if (iOMXComponentSupportsExternalOutputBufferAlloc)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::CreateOutMemPool() Allocating output buffers of size %d as well", iNodeTypeId, iOMXComponentOutputBufferSize));
//pre-negotiated output buffer size
iOutputAllocSize += iOMXComponentOutputBufferSize;
}
// ENCODER SPECIFIC FOR AVC RAW (BYTESTREAM) FORMAT
if ((iOutFormat == PVMF_MIME_H264_VIDEO_RAW) &&
(!iOMXComponentUsesFullAVCFrames) &&
(!iOMXComponentUsesNALStartCodes))
{
iOutputAllocSize += 4; // NAL SYNC WORD SIZE
}
// for media data wrapper
if (iMediaDataMemPool)
{
iMediaDataMemPool->removeRef();
iMediaDataMemPool = NULL;
}
if (iOutBufMemoryPool)
{
iOutBufMemoryPool->removeRef();
iOutBufMemoryPool = NULL;
}
int32 leavecode = 0;
OSCL_TRY(leavecode, iOutBufMemoryPool = OSCL_NEW(OsclMemPoolFixedChunkAllocator, (num_buffers)););
if (leavecode || iOutBufMemoryPool == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger,
PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::CreateOutMemPool() Memory pool structure for output buffers failed to allocate", iNodeTypeId));
return false;
}
// allocate a dummy buffer to actually create the mempool
OsclAny *dummy_alloc = NULL; // this dummy buffer will be released at end of scope
leavecode = 0;
OSCL_TRY(leavecode, dummy_alloc = iOutBufMemoryPool->allocate(iOutputAllocSize));
if (leavecode || dummy_alloc == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger,
PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::CreateOutMemPool() Memory pool for output buffers failed to allocate", iNodeTypeId));
return false;
}
iOutBufMemoryPool->deallocate(dummy_alloc);
// init the counter
iNumOutstandingOutputBuffers = 0;
// allocate mempool for media data message wrapper
leavecode = 0;
OSCL_TRY(leavecode, iMediaDataMemPool = OSCL_NEW(OsclMemPoolFixedChunkAllocator, (num_buffers, PVOMXENC_MEDIADATA_CHUNKSIZE)));
if (leavecode || iMediaDataMemPool == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::CreateOutMemPool() Media Data Buffer pool for output buffers failed to allocate", iNodeTypeId));
return false;
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::CreateOutMemPool() done", iNodeTypeId));
return true;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////// Creates memory pool for input buffer management ///////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
bool PVMFOMXEncNode::CreateInputMemPool(uint32 num_buffers)
{
// 3 cases in order of preference and simplicity
// Case 1 (buffers allocated upstream - no memcpy needed):
// PV OMX Component - We use buffers allocated outside the OMX node (i.e. allocated upstream)
// Mempool contains InputBufCtrlStructures (ptrs to buffer headers and PMVFMediaData ptrs - to keep track of when to unbind input msgs)
// NOTE: in this case, when providing input buffers to OMX component,
// OMX_UseBuffer calls will provide some initial pointers and sizes of buffers, but these
// are dummy values. Actual buffer pointers and filled sizes will be obtained from the input msg fragments.
// The PV OMX component will use the buffers even if the ptrs differ from the ones during initialization
// 3rd party OMX components can also use this case if they are capable of ignoring the actual buffer pointers in
// buffer header field (i.e. if after OMX_UseBuffer(...) call, they allow the ptr to actual buffer data to change at a later time
// CASE 2 (buffers allocated in the node - memcpy needed)
// If 3rd party OMX component can use buffers allocated outside the OMX component, but it cannot
// change buffer ptr allocations dynamically (i.e. after initialization with OMX_UseBuffer call is complete)
// Mempool contains InputBufCtrlStructures (ptrs to buffer headers, PVMFMediaData ptrs to keep track of when to unbind input msgs) +
// actual buffers.
// NOTE: Data must be copied from input message into the local buffer before the buffer is given to the OMX component
// CASE 3 (buffers allocated in the component - memcpy needed)
// If 3rd party OMX component must allocate its own buffers
// Mempool only contains InputBufCtrlStruct (ptrs to buffer headers + PMVFMediaData ptrs to keep track of when to unbind input msgs)
// NOTE: Data must be copied from input message into the local buffer before the buffer is given to the OMX component (like in case 2)
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::CreateInputMemPool() start ", iNodeTypeId));
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::CreateInputMemPool() allocating buffer header pointers and shared media data ptrs ", iNodeTypeId));
iInputAllocSize = oscl_mem_aligned_size((uint32) sizeof(InputBufCtrlStruct)); //aligned_size_buffer_header_ptr+aligned_size_media_data_ptr;
// Need to allocate buffers in the node either if component supports external buffers buffers
// but they are not movable
if ((iOMXComponentSupportsExternalInputBufferAlloc && !iOMXComponentSupportsMovableInputBuffers))
{
//pre-negotiated input buffer size
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::CreateOutMemPool() Allocating input buffers of size %d as well", iNodeTypeId, iOMXComponentInputBufferSize));
iInputAllocSize += iOMXComponentInputBufferSize;
}
if (iInBufMemoryPool)
{
iInBufMemoryPool->removeRef();
iInBufMemoryPool = NULL;
}
int32 leavecode = 0;
OSCL_TRY(leavecode, iInBufMemoryPool = OSCL_NEW(OsclMemPoolFixedChunkAllocator, (num_buffers)););
if (leavecode || iInBufMemoryPool == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger,
PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::CreateInputMemPool() Memory pool structure for input buffers failed to allocate", iNodeTypeId));
return false;
}
// try to allocate a dummy buffer to actually create the mempool and allocate the needed memory
// allocate a dummy buffer to actually create the mempool, this dummy buffer will be released at end of scope of this method
OsclAny *dummy_alloc = NULL;
leavecode = 0;
OSCL_TRY(leavecode, dummy_alloc = iInBufMemoryPool->allocate(iInputAllocSize));
if (leavecode || dummy_alloc == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger,
PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::CreateInputMemPool() Memory pool for input buffers failed to allocate", iNodeTypeId));
return false;
}
// init the counter
iNumOutstandingInputBuffers = 0;
iInputBufferToResendToComponent = NULL; // nothing to resend yet
iInBufMemoryPool->deallocate(dummy_alloc);
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::CreateInputMemPool() done", iNodeTypeId));
return true;
}
////////////////////////////////////////////////////////////////////////////
bool PVMFOMXEncNode::ProvideBuffersToComponent(OsclMemPoolFixedChunkAllocator *aMemPool, // allocator
uint32 aAllocSize, // size to allocate from pool (hdr only or hdr+ buffer)
uint32 aNumBuffers, // number of buffers
uint32 aActualBufferSize, // aactual buffer size
uint32 aPortIndex, // port idx
bool aUseBufferOK, // can component use OMX_UseBuffer or should it use OMX_AllocateBuffer
bool aIsThisInputBuffer // is this input or output
)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::ProvideBuffersToComponent() enter", iNodeTypeId));
uint32 ii = 0;
OMX_ERRORTYPE err = OMX_ErrorNone;
OsclAny **ctrl_struct_ptr = aIsThisInputBuffer ? in_ctrl_struct_ptr : out_ctrl_struct_ptr;
// Now, go through all buffers and tell component to
// either use a buffer, or to allocate its own buffer
for (ii = 0; ii < aNumBuffers; ii++)
{
int32 errcode = 0;
// get the address where the buf hdr ptr will be stored
errcode = MemAllocate(ctrl_struct_ptr[ii], aMemPool, aAllocSize);
if ((errcode != OsclErrNone) || (ctrl_struct_ptr[ii] == NULL))
{
if (errcode == OsclErrNoResources)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::ProvideBuffersToComponent ->allocate() failed for no mempool chunk available", iNodeTypeId));
}
else
{
// General error
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::ProvideBuffersToComponent ->allocate() failed due to some general error", iNodeTypeId));
ReportErrorEvent(PVMFFailure);
ChangeNodeState(EPVMFNodeError);
}
return false;
}
if (aUseBufferOK)
{
// Buffers are already allocated outside OMX component.
// In case of output buffers, the buffer itself is located
// just after the buffer header pointer.
// In case of input buffers, the buffer header pointer is followed by a MediaDataSharedPtr
// which is used to ensure proper unbinding of the input messages. The buffer itself is either:
// a) allocated upstream (and the ptr to the buffer
// is a dummy pointer to which the component does not pay attention - PV OMX component)
// b) located just after the buffer header pointer and MediaDataSharedPtr
uint8 *pB = ((uint8*) ctrl_struct_ptr[ii]);
// in case of input buffers, initialize also MediaDataSharedPtr structure
if (aIsThisInputBuffer)
{
InputBufCtrlStruct *temp = (InputBufCtrlStruct *) ctrl_struct_ptr[ii];
oscl_memset(&(temp->pMediaData), 0, sizeof(PVMFSharedMediaDataPtr));
temp->pMediaData = PVMFSharedMediaDataPtr(NULL, NULL);
// advance ptr to skip the structure
pB += oscl_mem_aligned_size(sizeof(InputBufCtrlStruct));
err = OMX_UseBuffer(iOMXEncoder, // hComponent
&(temp->pBufHdr), // address where ptr to buffer header will be stored
aPortIndex, // port index (for port for which buffer is provided)
ctrl_struct_ptr[ii], // App. private data = pointer to beginning of allocated data
// to have a context when component returns with a callback (i.e. to know
// what to free etc.
(OMX_U32)aActualBufferSize, // buffer size
pB); // buffer data ptr
in_buff_hdr_ptr[ii] = temp->pBufHdr;
}
else
{
OutputBufCtrlStruct *temp = (OutputBufCtrlStruct *) ctrl_struct_ptr[ii];
// advance buffer ptr to skip the structure
pB += oscl_mem_aligned_size(sizeof(OutputBufCtrlStruct));
if ((iOutFormat == PVMF_MIME_H264_VIDEO_RAW) &&
!iOMXComponentUsesFullAVCFrames &&
!iOMXComponentUsesNALStartCodes)
{
// write out NAL sync word at the beginning of the buffer
pB[0] = 0;
pB[1] = 0;
pB[2] = 0;
pB[3] = 1;
pB += 4;
// THe buffer that the component knows is always the same
// The node will move the ptr -4 when it needs teh sync word
}
err = OMX_UseBuffer(iOMXEncoder, // hComponent
&(temp->pBufHdr), // address where ptr to buffer header will be stored
aPortIndex, // port index (for port for which buffer is provided)
ctrl_struct_ptr[ii], // App. private data = pointer to beginning of allocated data
// to have a context when component returns with a callback (i.e. to know
// what to free etc.
(OMX_U32)aActualBufferSize, // buffer size
pB); // buffer data ptr
out_buff_hdr_ptr[ii] = temp->pBufHdr;
}
}
else
{
// the component must allocate its own buffers.
if (aIsThisInputBuffer)
{
InputBufCtrlStruct *temp = (InputBufCtrlStruct *) ctrl_struct_ptr[ii];
// initialize the media data field to 0 //TODO cleanup work started in another record. JJ 05/12/09
oscl_memset(&(temp->pMediaData), 0, sizeof(PVMFSharedMediaDataPtr));
temp->pMediaData = PVMFSharedMediaDataPtr(NULL, NULL);
err = OMX_AllocateBuffer(iOMXEncoder,
&(temp->pBufHdr),
aPortIndex,
ctrl_struct_ptr[ii],
(OMX_U32)aActualBufferSize);
in_buff_hdr_ptr[ii] = temp->pBufHdr;
}
else
{
OutputBufCtrlStruct *temp = (OutputBufCtrlStruct *) ctrl_struct_ptr[ii];
err = OMX_AllocateBuffer(iOMXEncoder,
&(temp->pBufHdr),
aPortIndex,
ctrl_struct_ptr[ii],
(OMX_U32)aActualBufferSize);
out_buff_hdr_ptr[ii] = temp->pBufHdr;
}
}
if (err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::ProvideBuffersToComponent() Problem using/allocating a buffer", iNodeTypeId));
return false;
}
}
for (ii = 0; ii < aNumBuffers; ii++)
{
// after initializing the buffer hdr ptrs, return them
// to the mempool
aMemPool->deallocate((OsclAny*) ctrl_struct_ptr[ii]);
}
// set the flags
if (aIsThisInputBuffer)
{
iInputBuffersFreed = false;
}
else
{
iOutputBuffersFreed = false;
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::ProvideBuffersToComponent() done", iNodeTypeId));
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool PVMFOMXEncNode::FreeBuffersFromComponent(OsclMemPoolFixedChunkAllocator *aMemPool, // allocator
uint32 aAllocSize, // size to allocate from pool (hdr only or hdr+ buffer)
uint32 aNumBuffers, // number of buffers
uint32 aPortIndex, // port idx
bool aIsThisInputBuffer // is this input or output
)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::FreeBuffersToComponent() enter", iNodeTypeId));
uint32 ii = 0;
OMX_ERRORTYPE err = OMX_ErrorNone;
OsclAny **ctrl_struct_ptr = aIsThisInputBuffer ? in_ctrl_struct_ptr : out_ctrl_struct_ptr;
// Now, go through all buffers and tell component to free them
for (ii = 0; ii < aNumBuffers; ii++)
{
int32 errcode = 0;
// get the address where the buf hdr ptr will be stored
errcode = MemAllocate(ctrl_struct_ptr[ii], aMemPool, aAllocSize);
if ((errcode != OsclErrNone) || (ctrl_struct_ptr[ii] == NULL))
{
if (errcode == OsclErrNoResources)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::FreeBuffersFromComponent ->allocate() failed for no mempool chunk available", iNodeTypeId));
}
else
{
// General error
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::FreeBuffersFromComponent ->allocate() failed due to some general error", iNodeTypeId));
ReportErrorEvent(PVMFFailure);
ChangeNodeState(EPVMFNodeError);
}
return false;
}
// to maintain correct count
aMemPool->notifyfreechunkavailable((*this), (OsclAny*) aMemPool);
if (aIsThisInputBuffer)
{
iNumOutstandingInputBuffers++;
// get the buf hdr pointer
InputBufCtrlStruct *temp = (InputBufCtrlStruct *) ctrl_struct_ptr[ii];
if(ipExternalInputBufferAllocatorInterface && ipFixedSizeBufferAlloc)
{
ipFixedSizeBufferAlloc->deallocate((OsclAny*) temp->pBufHdr->pBuffer);
}
err = OMX_FreeBuffer(iOMXEncoder,
aPortIndex,
temp->pBufHdr);
}
else
{
iNumOutstandingOutputBuffers++;
OutputBufCtrlStruct *temp = (OutputBufCtrlStruct *) ctrl_struct_ptr[ii];
err = OMX_FreeBuffer(iOMXEncoder,
aPortIndex,
temp->pBufHdr);
}
if (err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::FreeBuffersFromComponent() Problem freeing a buffer", iNodeTypeId));
return false;
}
}
for (ii = 0; ii < aNumBuffers; ii++)
{
// after freeing the buffer hdr ptrs, return them
// to the mempool (which will itself then be deleted promptly)
aMemPool->deallocate((OsclAny*) ctrl_struct_ptr[ii]);
}
// mark buffers as freed (so as not to do it twice)
if (aIsThisInputBuffer)
{
oscl_free(in_ctrl_struct_ptr);
oscl_free(in_buff_hdr_ptr);
in_ctrl_struct_ptr = NULL;
in_buff_hdr_ptr = NULL;
iInputBuffersFreed = true;
if(ipExternalInputBufferAllocatorInterface)
{
ipExternalInputBufferAllocatorInterface->removeRef();
ipExternalInputBufferAllocatorInterface = NULL;
}
}
else
{
oscl_free(out_ctrl_struct_ptr);
oscl_free(out_buff_hdr_ptr);
out_ctrl_struct_ptr = NULL;
out_buff_hdr_ptr = NULL;
iOutputBuffersFreed = true;
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::FreeBuffersFromComponent() done", iNodeTypeId));
return true;
}
/////////////////////////////////////////////////////////////////////////////
////////////////////// CALLBACK PROCESSING FOR EVENT HANDLER
/////////////////////////////////////////////////////////////////////////////
OMX_ERRORTYPE PVMFOMXEncNode::EventHandlerProcessing(OMX_OUT OMX_HANDLETYPE aComponent,
OMX_OUT OMX_PTR aAppData,
OMX_OUT OMX_EVENTTYPE aEvent,
OMX_OUT OMX_U32 aData1,
OMX_OUT OMX_U32 aData2,
OMX_OUT OMX_PTR aEventData)
{
OSCL_UNUSED_ARG(aComponent);
OSCL_UNUSED_ARG(aAppData);
OSCL_UNUSED_ARG(aEventData);
switch (aEvent)
{
case OMX_EventCmdComplete:
{
switch (aData1)
{
case OMX_CommandStateSet:
{
HandleComponentStateChange(aData2);
break;
}
case OMX_CommandFlush: //not supported
// nothing to do here yet
break;
case OMX_CommandPortDisable:
{
// if port disable command is done, we can re-allocate the buffers and re-enable the port
iProcessingState = EPVMFOMXEncNodeProcessingState_PortReEnable;
iPortIndexForDynamicReconfig = aData2;
RunIfNotReady();
break;
}
case OMX_CommandPortEnable:
// port enable command is done. Check if the other port also reported change.
// If not, we can start data flow. Otherwise, must start dynamic reconfig procedure for
// the other port as well.
{
if (iSecondPortReportedChange)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::EventHandlerProcessing: OMX_CommandPortEnable - completed on port %d, dynamic reconfiguration needed on port %d", iNodeTypeId, aData2, iSecondPortToReconfig));
iProcessingState = EPVMFOMXEncNodeProcessingState_PortReconfig;
iPortIndexForDynamicReconfig = iSecondPortToReconfig;
iSecondPortReportedChange = false;
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::EventHandlerProcessing: OMX_CommandPortEnable - completed on port %d, resuming normal data flow", iNodeTypeId, aData2));
iProcessingState = EPVMFOMXEncNodeProcessingState_ReadyToEncode;
iDynamicReconfigInProgress = false;
}
RunIfNotReady();
break;
}
case OMX_CommandMarkBuffer:
// nothing to do here yet;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::EventHandlerProcessing: OMX_CommandMarkBuffer - completed - no action taken", iNodeTypeId));
break;
default:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::EventHandlerProcessing: Unsupported event", iNodeTypeId));
break;
}
}//end of switch (aData1)
break;
}//end of case OMX_EventCmdComplete
case OMX_EventError:
{
LOGE("Ln %d OMX_EventError nData1 %d nData2 %d", __LINE__, aData1, aData2);
if (aData1 == (OMX_U32) OMX_ErrorStreamCorrupt)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::EventHandlerProcessing: OMX_EventError - Bitstream corrupt error", iNodeTypeId));
// Errors from corrupt bitstream are reported as info events
ReportInfoEvent(PVMFInfoProcessingFailure, NULL);
}
else if (aData1 == (OMX_U32) OMX_ErrorInvalidState)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::EventHandlerProcessing: OMX_EventError - OMX_ErrorInvalidState", iNodeTypeId));
HandleComponentStateChange(OMX_StateInvalid);
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::EventHandlerProcessing: OMX_EventError", iNodeTypeId));
// for now, any error from the component will be reported as error
ReportErrorEvent(PVMFErrProcessing, NULL, NULL);
SetState(EPVMFNodeError);
}
break;
}
case OMX_EventBufferFlag:
{
// the component is reporting it encountered end of stream flag
// we'll send eos when we get the actual last buffer with marked eos
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::EventHandlerProcessing: OMX_EventBufferFlag (EOS) flag returned from OMX component", iNodeTypeId));
RunIfNotReady();
break;
}//end of case OMX_EventBufferFlag
case OMX_EventMark:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::EventHandlerProcessing: OMX_EventMark returned from OMX component - no action taken", iNodeTypeId));
RunIfNotReady();
break;
}//end of case OMX_EventMark
case OMX_EventPortSettingsChanged:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::EventHandlerProcessing: OMX_EventPortSettingsChanged returned from OMX component", iNodeTypeId));
// first check if dynamic reconfiguration is already in progress,
// if so, wait until this is completed, and then initiate the 2nd reconfiguration
if (iDynamicReconfigInProgress)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::EventHandlerProcessing: OMX_EventPortSettingsChanged returned for port %d, dynamic reconfig already in progress", iNodeTypeId, aData1));
iSecondPortToReconfig = aData1;
iSecondPortReportedChange = true;
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::EventHandlerProcessing: OMX_EventPortSettingsChanged returned for port %d", iNodeTypeId, aData1));
iProcessingState = EPVMFOMXEncNodeProcessingState_PortReconfig;
iPortIndexForDynamicReconfig = aData1;
iDynamicReconfigInProgress = true;
}
RunIfNotReady();
break;
}//end of case OMX_PortSettingsChanged
case OMX_EventResourcesAcquired: //not supported
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::EventHandlerProcessing: OMX_EventResourcesAcquired returned from OMX component - no action taken", iNodeTypeId));
RunIfNotReady();
break;
}
default:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::EventHandlerProcessing: Unknown Event returned from OMX component - no action taken", iNodeTypeId));
break;
}
}//end of switch (eEvent)
return OMX_ErrorNone;
}
/////////////////////////////////////////////////////////////////////////////
// This function handles the event of OMX component state change
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::HandleComponentStateChange(OMX_U32 encoder_state)
{
switch (encoder_state)
{
case OMX_StateIdle:
{
iCurrentEncoderState = OMX_StateIdle;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::HandleComponentStateChange: OMX_StateIdle reached", iNodeTypeId));
// this state can be reached either going from OMX_Loaded->OMX_Idle (preparing)
// or going from OMX_Executing->OMX_Idle (stopping)
if ((iCurrentCommand.size() > 0) &&
(iCurrentCommand.front().iCmd == PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_PREPARE))
{
iProcessingState = EPVMFOMXEncNodeProcessingState_ReadyToEncode;
SetState(EPVMFNodePrepared);
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess);
RunIfNotReady();
}
else if ((iCurrentCommand.size() > 0) &&
(iCurrentCommand.front().iCmd == PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_STOP))
{
// if we are stopped, we won't start until the node gets DoStart command.
// in this case, we are ready to start sending buffers
if (iProcessingState == EPVMFOMXEncNodeProcessingState_Stopping)
iProcessingState = EPVMFOMXEncNodeProcessingState_ReadyToEncode;
// if the processing state was not stopping, leave the state as it was (continue port reconfiguration)
SetState(EPVMFNodePrepared);
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess);
RunIfNotReady();
}
else if ((iCurrentCommand.size() > 0) &&
(iCurrentCommand.front().iCmd == PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_FLUSH))
{
// if there is a flush, similar to the case of stop, we won't start until the node gets
// DoStart command. In this case, we'll be ready
if (iProcessingState == EPVMFOMXEncNodeProcessingState_Stopping)
iProcessingState = EPVMFOMXEncNodeProcessingState_ReadyToEncode;
//Flush is complete. Go to prepared state.
SetState(EPVMFNodePrepared);
//resume port input (if possible) so the ports can be re-started.
if (iInPort)
{
iInPort->ResumeInput();
}
if (iOutPort)
{
iOutPort->ResumeInput();
}
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess);
RunIfNotReady();
}
else if ((iCurrentCommand.size() > 0) &&
(iCurrentCommand.front().iCmd == PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_RESET))
{
// State change to Idle was initiated due to Reset. First need to reach idle, and then loaded
// Once Idle is reached, we need to initiate idle->loaded transition
iStopInResetMsgSent = false;
RunIfNotReady();
}
break;
}//end of case OMX_StateIdle
case OMX_StateExecuting:
{
iCurrentEncoderState = OMX_StateExecuting;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::HandleComponentStateChange: OMX_StateExecuting reached", iNodeTypeId));
// this state can be reached going from OMX_Idle -> OMX_Executing (preparing)
// or going from OMX_Pause -> OMX_Executing (coming from pause)
// either way, this is a response to "DoStart" command
if ((iCurrentCommand.size() > 0) &&
(iCurrentCommand.front().iCmd == PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_START))
{
SetState(EPVMFNodeStarted);
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess);
RunIfNotReady();
}
break;
}//end of case OMX_StateExecuting
case OMX_StatePause:
{
iCurrentEncoderState = OMX_StatePause;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::HandleComponentStateChange: OMX_StatePause reached", iNodeTypeId));
// This state can be reached going from OMX_Executing-> OMX_Pause
if ((iCurrentCommand.size() > 0) &&
(iCurrentCommand.front().iCmd == PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_PAUSE))
{
SetState(EPVMFNodePaused);
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess);
RunIfNotReady();
}
break;
}//end of case OMX_StatePause
case OMX_StateLoaded:
{
iCurrentEncoderState = OMX_StateLoaded;
// this state can be reached only going from OMX_Idle ->OMX_Loaded (stopped to reset)
//
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::HandleComponentStateChange: OMX_StateLoaded reached", iNodeTypeId));
//Check if command's responce is pending
if ((iCurrentCommand.size() > 0) &&
(iCurrentCommand.front().iCmd == PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_RESET))
{
// move this here
if (iInPort)
{
OSCL_DELETE(((PVMFOMXEncPort*)iInPort));
iInPort = NULL;
}
if (iOutPort)
{
OSCL_DELETE(((PVMFOMXEncPort*)iOutPort));
iOutPort = NULL;
}
iDataIn.Unbind();
// Reset the metadata key list
iAvailableMetadataKeys.clear();
iProcessingState = EPVMFOMXEncNodeProcessingState_Idle;
//logoff & go back to Created state.
SetState(EPVMFNodeIdle);
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess);
iResetInProgress = false;
iResetMsgSent = false;
}
break;
}//end of case OMX_StateLoaded
case OMX_StateInvalid:
default:
{
iCurrentEncoderState = OMX_StateInvalid;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::HandleComponentStateChange: OMX_StateInvalid reached", iNodeTypeId));
//Clearup encoder
DeleteOMXEncoder();
if (iCurrentCommand.size() > 0)
{//can NOT be CANCEL or CANCEL_ALL. Just to cmd completion for the rest
if (iCurrentCommand.front().iCmd == PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_RESET)
{
//delete all ports and notify observer.
if (iInPort)
{
OSCL_DELETE(((PVMFOMXEncPort*)iInPort));
iInPort = NULL;
}
if (iOutPort)
{
OSCL_DELETE(((PVMFOMXEncPort*)iOutPort));
iOutPort = NULL;
}
iDataIn.Unbind();
// Reset the metadata key list
iAvailableMetadataKeys.clear();
iEndOfDataReached = false;
iIsEOSSentToComponent = false;
iIsEOSReceivedFromComponent = false;
iProcessingState = EPVMFOMXEncNodeProcessingState_Idle;
//logoff & go back to Created state.
SetState(EPVMFNodeIdle);
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess);
}
else
{
SetState(EPVMFNodeError);
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFErrResource);
}
}
break;
}//end of case OMX_StateInvalid
}//end of switch(encoder_state)
}
/////////////////////////////////////////////////////////////////////////////
////////////////////// CALLBACK PROCESSING FOR EMPTY BUFFER DONE - input buffer was consumed
/////////////////////////////////////////////////////////////////////////////
OMX_ERRORTYPE PVMFOMXEncNode::EmptyBufferDoneProcessing(OMX_OUT OMX_HANDLETYPE aComponent,
OMX_OUT OMX_PTR aAppData,
OMX_OUT OMX_BUFFERHEADERTYPE* aBuffer)
{
OSCL_UNUSED_ARG(aComponent);
OSCL_UNUSED_ARG(aAppData);
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::EmptyBufferDoneProcessing: In", iNodeTypeId));
OSCL_ASSERT((void*) aComponent == (void*) iOMXEncoder); // component should match the component
OSCL_ASSERT(aAppData == (OMX_PTR)(this)); // AppData should represent this node ptr
// first, get the buffer "context", i.e. pointer to application private data that contains the
// address of the mempool buffer (so that it can be released)
InputBufCtrlStruct *pContext = (InputBufCtrlStruct *)(aBuffer->pAppPrivate);
// if a buffer is not empty, log a msg, but release anyway
if ((aBuffer->nFilledLen > 0) && (iDoNotSaveInputBuffersFlag == false))
// if dynamic port reconfig is in progress for input port, don't keep the buffer
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::EmptyBufferDoneProcessing: Input buffer returned non-empty with %d bytes still in it", iNodeTypeId, aBuffer->nFilledLen));
}
iInputBufferToResendToComponent = NULL;
// input buffer is to be released,
// refcount needs to be decremented (possibly - the input msg associated with the buffer will be unbound)
// NOTE: in case of "moveable" input buffers (passed into component without copying), unbinding decrements a refcount which eventually results
// in input message being released back to upstream mempool once all its fragments are returned
// in case of input buffers passed into component by copying, unbinding has no effect
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::EmptyBufferDoneProcessing: Release input buffer (with %d refcount remaining of input message)", iNodeTypeId, (pContext->pMediaData).get_count() - 1));
(pContext->pMediaData).Unbind();
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::EmptyBufferDoneProcessing: Release input buffer %x back to mempool", iNodeTypeId, pContext));
iInBufMemoryPool->deallocate((OsclAny *) pContext);
// the OMX spec says that no error is to be returned
return OMX_ErrorNone;
}
/////////////////////////////////////////////////////////////////////////////
////////////////////// CALLBACK PROCESSING FOR FILL BUFFER DONE - output buffer is ready
/////////////////////////////////////////////////////////////////////////////
OMX_ERRORTYPE PVMFOMXEncNode::FillBufferDoneProcessing(OMX_OUT OMX_HANDLETYPE aComponent,
OMX_OUT OMX_PTR aAppData,
OMX_OUT OMX_BUFFERHEADERTYPE* aBuffer)
{
OSCL_UNUSED_ARG(aComponent);
OSCL_UNUSED_ARG(aAppData);
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::FillBufferDoneProcessing: In", iNodeTypeId));
OSCL_ASSERT((void*) aComponent == (void*) iOMXEncoder); // component should match the component
OSCL_ASSERT(aAppData == (OMX_PTR)(this)); // AppData should represent this node ptr
// first, get the buffer "context", i.e. pointer to application private data that contains the
// address of the mempool buffer (so that it can be released)
OsclAny *pContext = (OsclAny*) aBuffer->pAppPrivate;
// check for EOS flag
if ((aBuffer->nFlags & OMX_BUFFERFLAG_EOS))
{
// EOS received - enable sending EOS msg
iIsEOSReceivedFromComponent = true;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::FillBufferDoneProcessing: Output buffer has EOS set", iNodeTypeId));
}
if (((iOutFormat == PVMF_MIME_H264_VIDEO_MP4) || (iOutFormat == PVMF_MIME_H264_VIDEO_RAW))
&& (iOMXComponentUsesNALStartCodes))
{
// find size of first start code, since it can be either 3 or 4 bytes
uint8* pData = (uint8*)aBuffer->pBuffer + aBuffer->nOffset;
uint8* pTemp;
uint32 size = aBuffer->nFilledLen;
if (AVCAnnexBGetNALUnit(pData, &pTemp, (int32*)&size, true))
{
iFirstNALStartCodeSize = (uint32)pTemp - (uint32)pData;
}
else
{
iFirstNALStartCodeSize = 0;
}
}
/* the case in which a buffer simply containing a start code is sent */
if (aBuffer->nFilledLen <= iFirstNALStartCodeSize && iOMXComponentUsesNALStartCodes)
{
aBuffer->nFilledLen = 0;
}
// if a buffer is empty, or if it should not be sent downstream (say, due to state change)
// release the buffer back to the pool
if ((aBuffer->nFilledLen == 0) || (iDoNotSendOutputBuffersDownstreamFlag == true))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::FillBufferDoneProcessing: Release output buffer %x back to mempool - buffer empty or not to be sent downstream", iNodeTypeId, pContext));
iOutBufMemoryPool->deallocate(pContext);
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::FillBufferDoneProcessing: Output frame %d received", iNodeTypeId, iFrameCounter));
iFrameCounter++;
// get pointer to actual buffer data
uint8 *pBufdata = ((uint8*) aBuffer->pBuffer);
// move the data pointer based on offset info
pBufdata += aBuffer->nOffset;
uint32 bufLen = (uint32) aBuffer->nFilledLen;
// in case of mp4 streaming and the very 1st buffer, save vol header separately
if ((iOutFormat == PVMF_MIME_M4V) && (iFrameCounter == 1))
{
// save the first buffer since this is the VOL header
uint refCounterSize = oscl_mem_aligned_size(sizeof(OsclRefCounterDA));
OsclMemoryFragment volHeader;
int vol_len = aBuffer->nFilledLen;
bool frameInVolHdr = CheckM4vVopStartCode(pBufdata, &vol_len);
volHeader.ptr = NULL;
volHeader.len = vol_len;
uint8* memBuffer = (uint8*)iAlloc.allocate(refCounterSize + volHeader.len);
oscl_memset(memBuffer, 0, refCounterSize + volHeader.len);
OsclRefCounter* refCounter = OSCL_PLACEMENT_NEW(memBuffer, OsclRefCounterDA(memBuffer, (OsclDestructDealloc*) & iAlloc));
memBuffer += refCounterSize;
volHeader.ptr = (OsclAny*)memBuffer;
// copy the vol header from OMX buffer
oscl_memcpy(volHeader.ptr, pBufdata, volHeader.len);
// save in class variable
iVolHeader = OsclRefCounterMemFrag(volHeader, refCounter, volHeader.len);
if (frameInVolHdr == false)
{
// release the OMX buffer
iOutBufMemoryPool->deallocate(pContext);
return OMX_ErrorNone;
}
else // there is a frame in this buffer, update the pointer and continue to process it.
{
pBufdata += vol_len;
bufLen -= vol_len;
}
}
if (iFrameCounter == 1)
{
if ((iOutFormat == PVMF_MIME_ADTS)
|| (iOutFormat == PVMF_MIME_ADIF)
|| (iOutFormat == PVMF_MIME_MPEG4_AUDIO)
|| (iOutFormat == PVMF_MIME_WMA)
|| (iOutFormat == PVMF_MIME_WMV)
)
{
// save the first buffer since this is the config header and needs to be sent separately
uint refCounterSize = oscl_mem_aligned_size(sizeof(OsclRefCounterDA));
OsclMemoryFragment configHeader;
configHeader.ptr = NULL;
configHeader.len = aBuffer->nFilledLen;
uint8* memBuffer = (uint8*)iAlloc.allocate(refCounterSize + configHeader.len);
oscl_memset(memBuffer, 0, refCounterSize + configHeader.len);
OsclRefCounter* refCounter = OSCL_PLACEMENT_NEW(memBuffer, OsclRefCounterDA(memBuffer, (OsclDestructDealloc*) & iAlloc));
memBuffer += refCounterSize;
configHeader.ptr = (OsclAny*)memBuffer;
// copy the vol header from OMX buffer
oscl_memcpy(configHeader.ptr, pBufdata, configHeader.len);
// save in class variable
iConfigHeader = OsclRefCounterMemFrag(configHeader, refCounter, configHeader.len);
// release the OMX buffer
iOutBufMemoryPool->deallocate(pContext);
return OMX_ErrorNone;
}
}
// in case of avc mp4, need to save sps/pps sequences
if ((iOutFormat == PVMF_MIME_H264_VIDEO_MP4) && (!iSpsPpsSequenceOver))
{
if (iOMXComponentUsesNALStartCodes)
{
// remove the start code from these single NAL frames
pBufdata += iFirstNALStartCodeSize;
bufLen -= iFirstNALStartCodeSize;
}
// detect nal type
uint8 *bitstream = pBufdata;
int nal_type;
// adjust the pointers in the iParamSet memfragment
uint8 *destptr = (uint8*) iParamSet.getMemFragPtr();
uint32 length = iParamSet.getMemFrag().len;
uint32 capacity = iParamSet.getCapacity();
destptr += length;
nal_type = bitstream[0] & 0x1F;
if (nal_type == 0x07) // SPS type NAL
{
int32 nal_size = aBuffer->nFilledLen;
AVCAnnexBGetNALUnit(aBuffer->pBuffer, &bitstream, (int32*)&nal_size, false);
// can the SPS fit into the buffer
if (aBuffer->nFilledLen <= (capacity - length))
{
iSPSs[iNumSPSs].ptr = destptr;
iSPSs[iNumSPSs++].len = nal_size;
oscl_memcpy(destptr, pBufdata, nal_size); // copy SPS into iParamSet memfragment
length += nal_size;
iParamSet.getMemFrag().len = length; // update length
destptr += nal_size;
if (nal_size < aBuffer->nFilledLen) {
LOGD("SPS and PPS are located within a single output buffer");
uint8* pData = (uint8*)aBuffer->pBuffer + nal_size +iFirstNALStartCodeSize;
uint32 size = aBuffer->nFilledLen -(nal_size +iFirstNALStartCodeSize);
AVCAnnexBGetNALUnit(pData, &bitstream, (int32*)&size, false);
nal_size = size;
nal_type = bitstream[0] & 0x1F;
if (nal_type == 0x08) // PPS type NAL
{
if (aBuffer->nFilledLen <= (capacity - length))
{
iPPSs[iNumPPSs].ptr = destptr;
iPPSs[iNumPPSs++].len = nal_size;
oscl_memcpy(destptr, bitstream, nal_size); // copy PPS into iParamSet memfragment$
length += nal_size;
iParamSet.getMemFrag().len = length; // update length
}
}
}
}
// release the OMX buffer
iOutBufMemoryPool->deallocate(pContext);
return OMX_ErrorNone;
}
else if (nal_type == 0x08) // PPS type NAL
{
LOGD("SPS and PPS are located in separate output buffers");
// can the PPS fit into the buffer?
if (aBuffer->nFilledLen <= (capacity - length))
{
iPPSs[iNumPPSs].ptr = destptr;
iPPSs[iNumPPSs++].len = aBuffer->nFilledLen;
oscl_memcpy(destptr, pBufdata, aBuffer->nFilledLen); // copy PPS into iParamSet memfragment
length += aBuffer->nFilledLen;
iParamSet.getMemFrag().len = length; // update length
}
// release the OMX buffer
iOutBufMemoryPool->deallocate(pContext);
return OMX_ErrorNone;
}
else
{
if (iOMXComponentUsesNALStartCodes)
{
// bring start code back since it's not a SPS or PPS
pBufdata -= iFirstNALStartCodeSize;
bufLen += iFirstNALStartCodeSize;
}
// this is neither SPS nor PPS
// stop recording SPS/PPS
iSpsPpsSequenceOver = true;
iFirstNAL = true; // set indicator of first NAL
// send out SPS/PPS recorded so far
if (((PVMFOMXEncPort*)iOutPort))
{
((PVMFOMXEncPort*)iOutPort)->SendSPS_PPS(iSPSs, iNumSPSs, iPPSs, iNumPPSs);
}
}
}
if (iOMXComponentUsesFullAVCFrames && iOutFormat == PVMF_MIME_H264_VIDEO_MP4)
{
// do not parse fo PVMF_MIME_H264_VIDEO_RAW, since this data is just written raw, and knowing
// the NAL boundaries isn't necessary
if (!ParseFullAVCFramesIntoNALs(aBuffer))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::FillBufferDoneProcessing: Problem parsing NALs in buffer %x of size %d - releasing the buffer", iNodeTypeId, pBufdata, aBuffer->nFilledLen));
iOutBufMemoryPool->deallocate(pContext);
}
}
// adjust ptr to data to expose the NAL sync word if necessary
if ((iOutFormat == PVMF_MIME_H264_VIDEO_RAW) &&
(iOMXComponentSupportsExternalOutputBufferAlloc) &&
(!iOMXComponentUsesFullAVCFrames) &&
(!iOMXComponentUsesNALStartCodes) &&
((iFirstNAL == true) || (iEndOfNALFlagPrevious != 0))
)
{
pBufdata -= 4;
bufLen += 4;
}
// otherwise, queue output buffer
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::FillBufferDoneProcessing: Wrapping buffer %x of size %d", iNodeTypeId, pBufdata, aBuffer->nFilledLen));
// wrap the buffer into the MediaDataImpl wrapper, and queue it for sending downstream
// wrapping will create a refcounter. When refcounter goes to 0 i.e. when media data
// is released in downstream components, the custom deallocator will automatically release the buffer back to the
// mempool. To do that, the deallocator needs to have info about Context
// NOTE: we had to wait until now to wrap the buffer data because we only know
// now where the actual data is located (based on buffer offset)
OsclSharedPtr<PVMFMediaDataImpl> MediaDataCurr = WrapOutputBuffer(pBufdata, bufLen, pContext);
// if you can't get the MediaDataCurr, release the buffer back to the pool
if (MediaDataCurr.GetRep() == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::FillBufferDoneProcessing: Problem wrapping buffer %x of size %d - releasing the buffer", iNodeTypeId, pBufdata, aBuffer->nFilledLen));
iOutBufMemoryPool->deallocate(pContext);
}
else
{
OsclSharedPtr<PVMFMediaDataImpl> MediaDataOut;
//DV - NOTE:
//In case of AVC, OMX_EndOfFrameFlag is used to mark the end of NAL
// End of frame is determined by comparing timestamps
// As a consequence, there is a lag of one buffer
// i.e. we send/queue the previous buffer and keep the current one so that
// When the next buffer arrives, we can compare timestamps etc.
// In case of MP4, OMX_EndOFFrameFlag is used to mark end of frame and there is no lag
if ((iOutFormat == PVMF_MIME_H264_VIDEO_MP4) || (iOutFormat == PVMF_MIME_H264_VIDEO_RAW))
{
MediaDataOut = iPreviousMediaData; // send out previous media data
// copy data to be attached with outgoing media data from previous buffer
iTimeStampOut = iTimeStampPrevious;
iKeyFrameFlagOut = iKeyFrameFlagPrevious;
iEndOfNALFlagOut = iEndOfNALFlagPrevious;
// figure out if we need to set end of frame based on TS
if (aBuffer->nTimeStamp != iTimeStampPrevious)
iEndOfFrameFlagOut = 1;
else
iEndOfFrameFlagOut = 0;
iBufferLenOut = iBufferLenPrevious;
// now read the info for the current data
iPreviousMediaData = MediaDataCurr;
// record timestamp, flags etc.
iTimeStampPrevious = aBuffer->nTimeStamp;
// check for Key Frame
iKeyFrameFlagPrevious = (aBuffer->nFlags & OMX_BUFFERFLAG_SYNCFRAME);
// for avc, ENDOFFRAMEFLAG is used to delimit NALs
iEndOfNALFlagPrevious = (aBuffer->nFlags & OMX_BUFFERFLAG_ENDOFFRAME);
iBufferLenPrevious = bufLen;
}
else // MP4 case
{
MediaDataOut = MediaDataCurr;
// record timestamp, flags etc.
iTimeStampOut = aBuffer->nTimeStamp;
// check for Key Frame
iKeyFrameFlagOut = (aBuffer->nFlags & OMX_BUFFERFLAG_SYNCFRAME);
iEndOfNALFlagOut = 0; // set this to 0 for mp4
//check for END OF FRAME FLAG
iEndOfFrameFlagOut = (aBuffer->nFlags & OMX_BUFFERFLAG_ENDOFFRAME);
iBufferLenOut = aBuffer->nFilledLen;
}
// if there's a problem queuing output buffer, MediaDataCurr will expire at end of scope and
// release buffer back to the pool, (this should not be the case)
// queue only if not the first NAL
if (!iFirstNAL)
{
if (QueueOutputBuffer(MediaDataOut, iBufferLenOut))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::FillBufferDoneProcessing: Buffer %x of size %d queued - reschedule the node to send out", iNodeTypeId, pBufdata, aBuffer->nFilledLen));
// if queing went OK,
// re-schedule the node so that outgoing queue can be emptied (unless the outgoing port is busy)
if ((iOutPort) && !(iOutPort->IsConnectedPortBusy()))
RunIfNotReady();
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::FillBufferDoneProcessing: Problem queing buffer %x of size %d - releasing the buffer", iNodeTypeId, pBufdata, aBuffer->nFilledLen));
}
}
else
{
iFirstNAL = false;
}
// if EOS and AVC (with a lag), queue also the last buffer
if ((aBuffer->nFlags & OMX_BUFFERFLAG_EOS) &&
((iOutFormat == PVMF_MIME_H264_VIDEO_MP4) || (iOutFormat == PVMF_MIME_H264_VIDEO_RAW))
)
{
MediaDataOut = iPreviousMediaData; // send out previous media data
// copy data to be attached with outgoing media data from previous buffer
iTimeStampOut = iTimeStampPrevious;
iKeyFrameFlagOut = iKeyFrameFlagPrevious;
iEndOfNALFlagOut = 1;
iEndOfFrameFlagOut = 1;
iBufferLenOut = iBufferLenPrevious;
if (QueueOutputBuffer(MediaDataOut, iBufferLenOut))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::FillBufferDoneProcessing: Buffer %x of size %d queued - reschedule the node to send out", iNodeTypeId, pBufdata, aBuffer->nFilledLen));
// if queing went OK,
// re-schedule the node so that outgoing queue can be emptied (unless the outgoing port is busy)
if ((iOutPort) && !(iOutPort->IsConnectedPortBusy()))
RunIfNotReady();
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::FillBufferDoneProcessing: Problem queing buffer %x of size %d - releasing the buffer", iNodeTypeId, pBufdata, aBuffer->nFilledLen));
}
}
}
}
// the OMX spec says that no error is to be returned
return OMX_ErrorNone;
}
////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////// Put output buffer in outgoing queue //////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
bool PVMFOMXEncNode::QueueOutputBuffer(OsclSharedPtr<PVMFMediaDataImpl> &mediadataimplout, uint32 aDataLen)
{
bool status = true;
PVMFSharedMediaDataPtr mediaDataOut;
int32 leavecode = 0;
// NOTE: ASSUMPTION IS THAT OUTGOING QUEUE IS BIG ENOUGH TO QUEUE ALL THE OUTPUT BUFFERS
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::QueueOutputFrame: In", iNodeTypeId));
// Check if the port is still connected
if (iOutPort == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "PVMFOMXEncNode-%s::QueueOutputFrame() OutgoingQueue Out Port is disconnected"));
return false;
}
// First check if we can put outgoing msg. into the queue
if (iOutPort->IsOutgoingQueueBusy())
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "PVMFOMXEncNode-%s::QueueOutputFrame() OutgoingQueue is busy", iNodeTypeId));
return false;
}
OSCL_TRY(leavecode,
mediaDataOut = PVMFMediaData::createMediaData(mediadataimplout, iMediaDataMemPool););
if (leavecode == 0)
{
uint32 marker_bits = mediaDataOut->getMarkerInfo();
if (iEndOfFrameFlagOut != 0)
{
marker_bits |= PVMF_MEDIA_DATA_MARKER_INFO_M_BIT;
}
if (iKeyFrameFlagOut != 0)
{
marker_bits |= PVMF_MEDIA_DATA_MARKER_INFO_RANDOM_ACCESS_POINT_BIT;
}
if (iEndOfNALFlagOut != 0)
{
marker_bits |= PVMF_MEDIA_DATA_MARKER_INFO_END_OF_NAL_BIT;
}
// attach marker bit
mediaDataOut->setMarkerInfo(marker_bits);
// Update the filled length of the fragment
mediaDataOut->setMediaFragFilledLen(0, aDataLen);
// Set timestamp
// first convert OMX_TICKS into output timescale
uint32 output_timestamp = ConvertOMXTicksIntoTimestamp(iTimeStampOut);
mediaDataOut->setTimestamp(output_timestamp);
// Set Streamid
mediaDataOut->setStreamID(iStreamID);
// Set sequence number
mediaDataOut->setSeqNum(iSeqNum++);
PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iDataPathLogger, PVLOGMSG_INFO, (0, ":PVMFOMXEncNode-%s::QueueOutputFrame(): - SeqNum=%d, Ticks=%l TS=%d", iNodeTypeId, iSeqNum, iTimeStampOut, output_timestamp));
// Check if Fsi needs to be sent (VOL header)
if (sendYuvFsi)
{
if (iOutFormat == PVMF_MIME_M4V)
{
mediaDataOut->setFormatSpecificInfo(iVolHeader);
}
else if ((iOutFormat == PVMF_MIME_ADTS)
|| (iOutFormat == PVMF_MIME_ADIF)
|| (iOutFormat == PVMF_MIME_MPEG4_AUDIO)
|| (iOutFormat == PVMF_MIME_WMA)
|| (iOutFormat == PVMF_MIME_WMV))
{
mediaDataOut->setFormatSpecificInfo(iConfigHeader);
}
sendYuvFsi = false;
}
// Send frame to downstream node
PVMFSharedMediaMsgPtr mediaMsgOut;
convertToPVMFMediaMsg(mediaMsgOut, mediaDataOut);
if (iOutPort && (iOutPort->QueueOutgoingMsg(mediaMsgOut) == PVMFSuccess))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_INFO,
(0, "PVMFOMXEncNode-%s::QueueOutputFrame(): Queued frame OK ", iNodeTypeId));
}
else
{
// we should not get here because we always check for whether queue is busy or not
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::QueueOutputFrame(): Send frame failed", iNodeTypeId));
return false;
}
}//end of if (leavecode==0)
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::QueueOutputFrame() call PVMFMediaData::createMediaData is failed", iNodeTypeId));
return false;
}
return status;
}
//////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////// Attach a MediaDataImpl wrapper (refcount, deallocator etc.)
/////////////////////////////// to the output buffer /////////////////////////////////////////
OsclSharedPtr<PVMFMediaDataImpl> PVMFOMXEncNode::WrapOutputBuffer(uint8 *pData, uint32 aDataLen, OsclAny *pContext)
{
// wrap output buffer into a mediadataimpl
uint32 aligned_cleanup_size = oscl_mem_aligned_size(sizeof(PVOMXEncBufferSharedPtrWrapperCombinedCleanupDA));
uint32 aligned_refcnt_size = oscl_mem_aligned_size(sizeof(OsclRefCounterDA));
uint8 *my_ptr = (uint8*) oscl_malloc(aligned_cleanup_size + aligned_refcnt_size);
if (my_ptr == NULL)
{
OsclSharedPtr<PVMFMediaDataImpl> null_buff(NULL, NULL);
return null_buff;
}
// create a deallocator and pass the buffer_allocator to it as well as pointer to data that needs to be returned to the mempool
PVOMXEncBufferSharedPtrWrapperCombinedCleanupDA *cleanup_ptr =
OSCL_PLACEMENT_NEW(my_ptr + aligned_refcnt_size, PVOMXEncBufferSharedPtrWrapperCombinedCleanupDA(iOutBufMemoryPool, pContext));
// create the ref counter after the cleanup object (refcount is set to 1 at creation)
OsclRefCounterDA *my_refcnt;
PVMFMediaDataImpl* media_data_ptr;
if (iOMXComponentUsesFullAVCFrames && iNumNALs > 0)
{
uint32 ii;
media_data_ptr = OSCL_NEW(PVMFMediaFragGroup<OsclMemAllocator>, (iNumNALs));
my_refcnt = OSCL_PLACEMENT_NEW(my_ptr, OsclRefCounterDA(media_data_ptr, cleanup_ptr));
// loop through and assign a create a media fragment for each NAL
for (ii = 0; ii < iNumNALs; ii++)
{
OsclMemoryFragment memFrag;
if (iOMXComponentUsesNALStartCodes)
{
// need to get NAL ptr from stored array, since start codes can be 3 or 4 bytes,
// and the only way to know is by parsing the buffer (which we should have done by now and stored in the array)
memFrag.ptr = iNALPtrArray[ii];
}
else
{
memFrag.ptr = pData;
pData += iNALSizeArray[ii];
}
memFrag.len = iNALSizeArray[ii];
OsclRefCounterMemFrag refCountMemFragOut(memFrag, my_refcnt, memFrag.len);
media_data_ptr->appendMediaFragment(refCountMemFragOut);
}
oscl_memset((void *) iNALSizeArray, 0, sizeof(uint32) * iNumNALs);
iNumNALs = 0;
}
else
{
media_data_ptr = OSCL_NEW(PVMFMediaFragGroup<OsclMemAllocator>, (1));
my_refcnt = OSCL_PLACEMENT_NEW(my_ptr, OsclRefCounterDA(media_data_ptr, cleanup_ptr));
OsclMemoryFragment memFrag;
if (iOMXComponentUsesNALStartCodes && (iOutFormat != PVMF_MIME_H264_VIDEO_RAW))
{
// skip start code
pData += iFirstNALStartCodeSize;
aDataLen -= iFirstNALStartCodeSize;
}
memFrag.ptr = pData;
memFrag.len = aDataLen;
OsclRefCounterMemFrag refCountMemFragOut(memFrag, my_refcnt, memFrag.len);
media_data_ptr->appendMediaFragment(refCountMemFragOut);
}
OsclSharedPtr<PVMFMediaDataImpl> MediaDataImplOut(media_data_ptr, my_refcnt);
return MediaDataImplOut;
}
//////////////////////////////////////////////////////////////////////////////
bool PVMFOMXEncNode::SendBeginOfMediaStreamCommand()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SendBeginOfMediaStreamCommand() In", iNodeTypeId));
PVMFSharedMediaCmdPtr sharedMediaCmdPtr = PVMFMediaCmd::createMediaCmd();
// Set the formatID, timestamp, sequenceNumber and streamID for the media message
sharedMediaCmdPtr->setFormatID(PVMF_MEDIA_CMD_BOS_FORMAT_ID);
sharedMediaCmdPtr->setTimestamp(iBOSTimestamp);
//reset the sequence number
uint32 seqNum = 0;
sharedMediaCmdPtr->setSeqNum(seqNum);
sharedMediaCmdPtr->setStreamID(iStreamID);
PVMFSharedMediaMsgPtr mediaMsgOut;
convertToPVMFMediaCmdMsg(mediaMsgOut, sharedMediaCmdPtr);
if (iOutPort->QueueOutgoingMsg(mediaMsgOut) != PVMFSuccess)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SendBeginOfMediaStreamCommand() Outgoing queue busy", iNodeTypeId));
return false;
}
iSendBOS = false;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SendBeginOfMediaStreamCommand() BOS Sent StreamID %d", iNodeTypeId, iStreamID));
return true;
}
////////////////////////////////////
bool PVMFOMXEncNode::SendEndOfTrackCommand(void)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SendEndOfTrackCommand() In", iNodeTypeId));
PVMFSharedMediaCmdPtr sharedMediaCmdPtr = PVMFMediaCmd::createMediaCmd();
sharedMediaCmdPtr->setFormatID(PVMF_MEDIA_CMD_EOS_FORMAT_ID);
// Set the timestamp
sharedMediaCmdPtr->setTimestamp(iEndOfDataTimestamp);
// Set Streamid
sharedMediaCmdPtr->setStreamID(iStreamID);
// Set the sequence number
sharedMediaCmdPtr->setSeqNum(iSeqNum++);
PVMFSharedMediaMsgPtr mediaMsgOut;
convertToPVMFMediaCmdMsg(mediaMsgOut, sharedMediaCmdPtr);
if (iOutPort->QueueOutgoingMsg(mediaMsgOut) != PVMFSuccess)
{
// this should not happen because we check for queue busy before calling this function
return false;
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SendEndOfTrackCommand() Out", iNodeTypeId));
return true;
}
/////////////////////////////////////////////////////////////////////////////
//The various command handlers call this routine when a command is complete.
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::CommandComplete(PVMFOMXEncNodeCmdQ& aCmdQ, PVMFOMXEncNodeCommand& aCmd, PVMFStatus aStatus, OsclAny* aEventData)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::CommandComplete Id %d Cmd %d Status %d Context %d Data %d", iNodeTypeId
, aCmd.iId, aCmd.iCmd, aStatus, aCmd.iContext, aEventData));
//create response
PVMFCmdResp resp(aCmd.iId, aCmd.iContext, aStatus, aEventData);
PVMFSessionId session = aCmd.iSession;
//Erase the command from the queue.
aCmdQ.Erase(&aCmd);
//Report completion to the session observer.
ReportCmdCompleteEvent(session, resp);
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::DoInit(PVMFOMXEncNodeCommand& aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::DoInit() In", iNodeTypeId));
switch (iInterfaceState)
{
case EPVMFNodeIdle:
{
SetState(EPVMFNodeInitialized);
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
break;
}
default:
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
break;
}
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::DoPrepare(PVMFOMXEncNodeCommand& aCmd)
{
OMX_ERRORTYPE err = OMX_ErrorNone;
OMX_STRING Role = NULL;
switch (iInterfaceState)
{
case EPVMFNodeInitialized:
{
if (NULL == iInPort)
{
CommandComplete(iInputCommands, aCmd, PVMFFailure);
}
// by now the encode parameters have been set
if (iOutFormat == PVMF_MIME_H2631998 ||
iOutFormat == PVMF_MIME_H2632000)
{
Role = (OMX_STRING)"video_encoder.h263";
iNodeTypeId = LOG_ID_VIDEO_H263;
}
else if (iOutFormat == PVMF_MIME_M4V)
{
Role = (OMX_STRING)"video_encoder.mpeg4";
iNodeTypeId = LOG_ID_VIDEO_M4V;
}
else if (iOutFormat == PVMF_MIME_H264_VIDEO_RAW ||
iOutFormat == PVMF_MIME_H264_VIDEO_MP4)
{
Role = (OMX_STRING)"video_encoder.avc";
iNodeTypeId = LOG_ID_VIDEO_AVC;
iFirstNAL = true; // set this flag to prevent node from queueing the first
// buffer
}
else if ((iOutFormat == PVMF_MIME_AMR_IETF) ||
(iOutFormat == PVMF_MIME_AMR_IF2))
{
Role = (OMX_STRING)"audio_encoder.amrnb";
iNodeTypeId = LOG_ID_AUDIO_AMRNB;
}
else if (iOutFormat == PVMF_MIME_AMRWB_IETF)
{
Role = (OMX_STRING)"audio_encoder.amrwb";
iNodeTypeId = LOG_ID_AUDIO_AMRWB;
}
else if (iOutFormat == PVMF_MIME_ADTS ||
iOutFormat == PVMF_MIME_ADIF ||
iOutFormat == PVMF_MIME_MPEG4_AUDIO)
{
Role = (OMX_STRING)"audio_encoder.aac";
iNodeTypeId = LOG_ID_AUDIO_AAC;
}
else
{
// Illegal codec specified.
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::DoPrepare() Input port format other then codec type", iNodeTypeId));
CommandComplete(iInputCommands, aCmd, PVMFErrArgument);
return;
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "PVMFOMXEncNode-%s::Initializing OMX component and encoder for role %s", iNodeTypeId, Role));
/* Set callback structure */
iCallbacks.EventHandler = CallbackEventHandlerEnc; //event_handler;
iCallbacks.EmptyBufferDone = CallbackEmptyBufferDoneEnc; //empty_buffer_done;
iCallbacks.FillBufferDone = CallbackFillBufferDoneEnc; //fill_buffer_done;
// determine components which can fit the role
// then, create the component. If multiple components fit the role,
// the first one registered will be selected. If that one fails to
// be created, the second one in the list is selected etc.
OMX_U32 num_comps = 0;
OMX_STRING *CompOfRole;
OMX_S8 CompName[PV_OMX_MAX_COMPONENT_NAME_LENGTH];
// call once to find out the number of components that can fit the role
OMX_MasterGetComponentsOfRole(Role, &num_comps, NULL);
uint32 ii;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "PVMFOMXEncNode-%s::DoPrepare(): There are %d components of role %s ", iNodeTypeId, num_comps, Role));
if (num_comps > 0)
{
CompOfRole = (OMX_STRING *)oscl_malloc(num_comps * sizeof(OMX_STRING));
for (ii = 0; ii < num_comps; ii++)
CompOfRole[ii] = (OMX_STRING) oscl_malloc(PV_OMX_MAX_COMPONENT_NAME_LENGTH * sizeof(OMX_U8));
// call 2nd time to get the component names
OMX_MasterGetComponentsOfRole(Role, &num_comps, (OMX_U8 **)CompOfRole);
for (ii = 0; ii < num_comps; ii++)
{
// try to create component
err = OMX_MasterGetHandle(&iOMXEncoder, (OMX_STRING) CompOfRole[ii], (OMX_PTR) this, (OMX_CALLBACKTYPE *) & iCallbacks);
if ((err == OMX_ErrorNone) && (iOMXEncoder != NULL))
{
oscl_strncpy((OMX_STRING)CompName, (OMX_STRING) CompOfRole[ii], PV_OMX_MAX_COMPONENT_NAME_LENGTH);
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "PVMFOMXEncNode-%s::DoPrepare(): Got Component %s handle ", iNodeTypeId, CompOfRole[ii]));
LOGE("PVMFOMXEncNode-%s::DoPrepare(): Got Component %s handle ", iNodeTypeId, CompOfRole[ii]);
if ((CheckComponentForMultRoles((OMX_STRING)CompName, (OMX_STRING)CompOfRole[ii])) &&
(CheckComponentCapabilities(&iOutFormat)))
{
// Found a component and it passed all tests. Break out of the loop
break;
}
}
// Component failed negotiations
if (iOMXEncoder != NULL)
{
OMX_MasterFreeHandle(iOMXEncoder);
iOMXEncoder = NULL;
}
}
// whether successful or not, need to free CompOfRoles
for (ii = 0; ii < num_comps; ii++)
{
oscl_free(CompOfRole[ii]);
CompOfRole[ii] = NULL;
}
oscl_free(CompOfRole);
// check if there was a problem
if ((err != OMX_ErrorNone) || (iOMXEncoder == NULL))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::Can't get handle for encoder!", iNodeTypeId));
iOMXEncoder = NULL;
CommandComplete(iInputCommands, aCmd, PVMFErrResource);
return;
}
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::No component can handle role %s !", iNodeTypeId, Role));
iOMXEncoder = NULL;
CommandComplete(iInputCommands, aCmd, PVMFErrResource);
return;
}
if (!iOMXEncoder)
{
CommandComplete(iInputCommands, aCmd, PVMFErrNoResources);
return;
}
// create active objects to handle callbacks in case of multithreaded implementation
// NOTE: CREATE THE THREADSAFE CALLBACK AOs REGARDLESS OF WHETHER MULTITHREADED COMPONENT OR NOT
// If it is not multithreaded, we won't use them
// The Flag iIsComponentMultiThreaded decides which mechanism is used for callbacks.
// This flag is set by looking at component capabilities (or to true by default)
if (iThreadSafeHandlerEventHandler)
{
OSCL_DELETE(iThreadSafeHandlerEventHandler);
iThreadSafeHandlerEventHandler = NULL;
}
// substitute default parameters: observer(this node),queuedepth(3),nameAO for logging
// Get the priority of the encoder node, and set the threadsafe callback AO priority to 1 higher
iThreadSafeHandlerEventHandler = OSCL_NEW(EventHandlerThreadSafeCallbackAOEnc, (this, 10, "EventHandlerAO", Priority() + 2));
if (iThreadSafeHandlerEmptyBufferDone)
{
OSCL_DELETE(iThreadSafeHandlerEmptyBufferDone);
iThreadSafeHandlerEmptyBufferDone = NULL;
}
// use queue depth of iNumInputBuffers to prevent deadlock
iThreadSafeHandlerEmptyBufferDone = OSCL_NEW(EmptyBufferDoneThreadSafeCallbackAOEnc, (this, iNumInputBuffers, "EmptyBufferDoneAO", Priority() + 1));
if (iThreadSafeHandlerFillBufferDone)
{
OSCL_DELETE(iThreadSafeHandlerFillBufferDone);
iThreadSafeHandlerFillBufferDone = NULL;
}
// use queue depth of iNumOutputBuffers to prevent deadlock
iThreadSafeHandlerFillBufferDone = OSCL_NEW(FillBufferDoneThreadSafeCallbackAOEnc, (this, iNumOutputBuffers, "FillBufferDoneAO", Priority() + 1));
if ((iThreadSafeHandlerEventHandler == NULL) ||
(iThreadSafeHandlerEmptyBufferDone == NULL) ||
(iThreadSafeHandlerFillBufferDone == NULL)
)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::Can't get threadsafe callbacks for encoder!", iNodeTypeId));
iOMXEncoder = NULL;
}
// Init Encoder
iCurrentEncoderState = OMX_StateLoaded;
/* Change state to OMX_StateIdle from OMX_StateLoaded. */
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "PVMFOMXEncNode-%s::DoPrepare(): Changing Component state Loaded -> Idle ", iNodeTypeId));
err = OMX_SendCommand(iOMXEncoder, OMX_CommandStateSet, OMX_StateIdle, NULL);
if (err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoPrepare() Can't send StateSet command!", iNodeTypeId));
CommandComplete(iInputCommands, aCmd, PVMFErrNoResources);
return;
}
/* Allocate input buffers */
if (!CreateInputMemPool(iNumInputBuffers))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoPrepare() Can't allocate mempool for input buffers!", iNodeTypeId));
CommandComplete(iInputCommands, aCmd, PVMFErrNoResources);
return;
}
if (in_ctrl_struct_ptr)
{
oscl_free(in_ctrl_struct_ptr);
in_ctrl_struct_ptr = NULL;
}
if (in_buff_hdr_ptr)
{
oscl_free(in_buff_hdr_ptr);
in_buff_hdr_ptr = NULL;
}
in_ctrl_struct_ptr = (OsclAny **) oscl_malloc(iNumInputBuffers * sizeof(OsclAny *));
if (in_ctrl_struct_ptr == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::DoPreapare in_ctrl_struct_ptr == NULL", iNodeTypeId));
CommandComplete(iInputCommands, aCmd, PVMFErrNoResources);
return ;
}
in_buff_hdr_ptr = (OsclAny **) oscl_malloc(iNumInputBuffers * sizeof(OsclAny *));
if (in_buff_hdr_ptr == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::DoPreapare in_buff_hdr_ptr == NULL", iNodeTypeId));
CommandComplete(iInputCommands, aCmd, PVMFErrNoResources);
return ;
}
if (!ProvideBuffersToComponent(iInBufMemoryPool, // allocator
iInputAllocSize, // size to allocate from pool (hdr only or hdr+ buffer)
iNumInputBuffers, // number of buffers
iOMXComponentInputBufferSize, // actual buffer size
iInputPortIndex, // port idx
iOMXComponentSupportsExternalInputBufferAlloc, // can component use OMX_UseBuffer
true // this is input
))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoPrepare() Component can't use input buffers!", iNodeTypeId));
CommandComplete(iInputCommands, aCmd, PVMFErrNoResources);
return;
}
/* Allocate output buffers */
if (!CreateOutMemPool(iNumOutputBuffers))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoPrepare() Can't allocate mempool for output buffers!", iNodeTypeId));
CommandComplete(iInputCommands, aCmd, PVMFErrNoResources);
return;
}
if (out_ctrl_struct_ptr)
{
oscl_free(out_ctrl_struct_ptr);
out_ctrl_struct_ptr = NULL;
}
if (out_buff_hdr_ptr)
{
oscl_free(out_buff_hdr_ptr);
out_buff_hdr_ptr = NULL;
}
out_ctrl_struct_ptr = (OsclAny **) oscl_malloc(iNumOutputBuffers * sizeof(OsclAny *));
if (out_ctrl_struct_ptr == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::DoPreapare out_ctrl_struct_ptr == NULL", iNodeTypeId));
CommandComplete(iInputCommands, aCmd, PVMFErrNoResources);
return ;
}
out_buff_hdr_ptr = (OsclAny **) oscl_malloc(iNumOutputBuffers * sizeof(OsclAny *));
if (out_buff_hdr_ptr == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::DoPreapare out_buff_hdr_ptr == NULL", iNodeTypeId));
CommandComplete(iInputCommands, aCmd, PVMFErrNoResources);
return ;
}
if (!ProvideBuffersToComponent(iOutBufMemoryPool, // allocator
iOutputAllocSize, // size to allocate from pool (hdr only or hdr+ buffer)
iNumOutputBuffers, // number of buffers
iOMXComponentOutputBufferSize, // actual buffer size
iOutputPortIndex, // port idx
iOMXComponentSupportsExternalOutputBufferAlloc, // can component use OMX_UseBuffer
false // this is not input
))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoPrepare() Component can't use output buffers!", iNodeTypeId));
CommandComplete(iInputCommands, aCmd, PVMFErrNoResources);
return;
}
//this command is asynchronous. move the command from
//the input command queue to the current command, where
//it will remain until it completes. We have to wait for
// OMX component state transition to complete
int32 err;
OSCL_TRY(err, iCurrentCommand.StoreL(aCmd););
if (err != OsclErrNone)
{
CommandComplete(iInputCommands, aCmd, PVMFErrNoMemory);
return;
}
iInputCommands.Erase(&aCmd);
}
break;
case EPVMFNodePrepared:
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
break;
default:
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
break;
}
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::DoStart(PVMFOMXEncNodeCommand& aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::DoStart() In", iNodeTypeId));
iDiagnosticsLogged = false;
PVMFStatus status = PVMFSuccess;
OMX_ERRORTYPE err;
OMX_STATETYPE sState;
#ifdef _TEST_AE_ERROR_HANDLING
if (FAIL_NODE_CMD_START == iErrorNodeCmd)
{
iInterfaceState = EPVMFNodeError;
}
#endif
switch (iInterfaceState)
{
case EPVMFNodePrepared:
case EPVMFNodePaused:
{
//Get state of OpenMAX encoder
err = OMX_GetState(iOMXEncoder, &sState);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoStart(): Can't get State of encoder!", iNodeTypeId));
sState = OMX_StateInvalid;
}
#ifdef _TEST_AE_ERROR_HANDLING
if (iErrorHandlingInit)
{
//some random state ,we want Init to fail
sState = OMX_StateInvalid;
}
#endif
if ((sState == OMX_StateIdle) || (sState == OMX_StatePause))
{
/* Change state to OMX_StateExecuting form OMX_StateIdle. */
// init the flag
iDoNotSendOutputBuffersDownstreamFlag = false; // or if output was not being sent downstream due to state changes
// re-anable sending output
iDoNotSaveInputBuffersFlag = false;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::DoStart() Changing Component state Idle->Executing", iNodeTypeId));
err = OMX_SendCommand(iOMXEncoder, OMX_CommandStateSet, OMX_StateExecuting, NULL);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoStart(): Can't send StateSet command to encoder!", iNodeTypeId));
status = PVMFErrInvalidState;
}
}
else
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoStart(): Encoder is not in the Idle or Pause state!", iNodeTypeId));
status = PVMFErrInvalidState;
}
}
break;
default:
status = PVMFErrInvalidState;
break;
}
if (status == PVMFErrInvalidState)
{
CommandComplete(iInputCommands, aCmd, status);
}
else
{
//this command is asynchronous. move the command from
//the input command queue to the current command, where
//it will remain until it completes.
int32 err;
OSCL_TRY(err, iCurrentCommand.StoreL(aCmd););
if (err != OsclErrNone)
{
CommandComplete(iInputCommands, aCmd, PVMFErrNoMemory);
}
iInputCommands.Erase(&aCmd);
}
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::DoStop(PVMFOMXEncNodeCommand& aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::DoStop() In", iNodeTypeId));
LogDiagnostics();
OMX_ERRORTYPE err;
OMX_STATETYPE sState;
#ifdef _TEST_AE_ERROR_HANDLING
if (FAIL_NODE_CMD_STOP == iErrorNodeCmd)
{
iInterfaceState = EPVMFNodeError;
}
#endif
switch (iInterfaceState)
{
case EPVMFNodeStarted:
case EPVMFNodePaused:
case EPVMFNodePrepared:
// Stop data source
// This will also prevent execution of HandleProcessingState
iDataIn.Unbind();
iPreviousMediaData.Unbind();
if ((iOutFormat == PVMF_MIME_H264_VIDEO_MP4) || (iOutFormat == PVMF_MIME_H264_VIDEO_RAW))
{
// prepare for next start (if it comes)
iFirstNAL = true;
}
// Clear queued messages in ports
if (iInPort)
{
iInPort->ClearMsgQueues();
}
if (iOutPort)
{
iOutPort->ClearMsgQueues();
}
// Clear the data flags
iEndOfDataReached = false;
iIsEOSSentToComponent = false;
iIsEOSReceivedFromComponent = false;
iDoNotSendOutputBuffersDownstreamFlag = true; // stop sending output buffers downstream
iDoNotSaveInputBuffersFlag = true;
//Get state of OpenMAX encoder
err = OMX_GetState(iOMXEncoder, &sState);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoStop(): Can't get State of encoder!", iNodeTypeId));
sState = OMX_StateInvalid;
}
if ((sState == OMX_StateExecuting) || (sState == OMX_StatePause))
{
/* Change state to OMX_StateIdle from OMX_StateExecuting or OMX_StatePause. */
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::DoStop() Changing Component State Executing->Idle or Pause->Idle", iNodeTypeId));
err = OMX_SendCommand(iOMXEncoder, OMX_CommandStateSet, OMX_StateIdle, NULL);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoStop(): Can't send StateSet command to encoder!", iNodeTypeId));
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
break;
}
// prevent the node from sending more buffers etc.
// if port reconfiguration is in process, let the state remain one of the port config states
// if there is a start command, we can do it seemlessly (by continuing the port reconfig)
if (iProcessingState == EPVMFOMXEncNodeProcessingState_ReadyToEncode)
iProcessingState = EPVMFOMXEncNodeProcessingState_Stopping;
}
else
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoStop(): Encoder is not in the Executing or Pause state!", iNodeTypeId));
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
break;
}
//this command is asynchronous. move the command from
//the input command queue to the current command, where
//it will remain until it completes.
int32 err;
OSCL_TRY(err, iCurrentCommand.StoreL(aCmd););
if (err != OsclErrNone)
{
CommandComplete(iInputCommands, aCmd, PVMFErrNoMemory);
return;
}
iInputCommands.Erase(&aCmd);
break;
default:
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
break;
}
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::DoFlush(PVMFOMXEncNodeCommand& aCmd)
{
#ifdef _TEST_AE_ERROR_HANDLING
if (FAIL_NODE_CMD_FLUSH == iErrorNodeCmd)
{
iInterfaceState = EPVMFNodeError;
}
#endif
switch (iInterfaceState)
{
case EPVMFNodeStarted:
case EPVMFNodePaused:
//the flush is asynchronous. move the command from
//the input command queue to the current command, where
//it will remain until the flush completes.
int32 err;
OSCL_TRY(err, iCurrentCommand.StoreL(aCmd););
if (err != OsclErrNone)
{
CommandComplete(iInputCommands, aCmd, PVMFErrNoMemory);
return;
}
iInputCommands.Erase(&aCmd);
//Notify all ports to suspend their input
if (iInPort)
{
iInPort->SuspendInput();
}
RunIfNotReady();
if (iOutPort)
{
iOutPort->SuspendInput();
}
// Stop data source
// DV: Sending "OMX_CommandFlush" to the encoder;
// Not used because PV Flush command expects data to be processed before getting out
iDoNotSendOutputBuffersDownstreamFlag = true; // collect output buffers
break;
default:
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
break;
}
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::DoPause(PVMFOMXEncNodeCommand& aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::DoPause() In", iNodeTypeId));
OMX_ERRORTYPE err;
OMX_STATETYPE sState;
#ifdef _TEST_AE_ERROR_HANDLING
if (FAIL_NODE_CMD_PAUSE == iErrorNodeCmd)
{
iInterfaceState = EPVMFNodeError;
}
#endif
switch (iInterfaceState)
{
case EPVMFNodeStarted:
//Get state of OpenMAX encoder
err = OMX_GetState(iOMXEncoder, &sState);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoPause(): Can't get State of encoder!", iNodeTypeId));
sState = OMX_StateInvalid;
}
if (sState == OMX_StateExecuting)
{
/* Change state to OMX_StatePause from OMX_StateExecuting. */
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::DoPause() Changing Component State Executing->Idle", iNodeTypeId));
err = OMX_SendCommand(iOMXEncoder, OMX_CommandStateSet, OMX_StatePause, NULL);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoPause(): Can't send StateSet command to encoder!", iNodeTypeId));
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
break;
}
}
else
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoPause(): Encoder is not in the Executing state!", iNodeTypeId));
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
break;
}
//this command is asynchronous. move the command from
//the input command queue to the current command, where
//it will remain until it completes.
int32 err;
OSCL_TRY(err, iCurrentCommand.StoreL(aCmd););
if (err != OsclErrNone)
{
CommandComplete(iInputCommands, aCmd, PVMFErrNoMemory);
return;
}
iInputCommands.Erase(&aCmd);
break;
default:
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
break;
}
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::DoReset(PVMFOMXEncNodeCommand& aCmd)
{
OMX_ERRORTYPE err;
OMX_STATETYPE sState;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::DoReset() In", iNodeTypeId));
LogDiagnostics();
switch (iInterfaceState)
{
case EPVMFNodeIdle:
case EPVMFNodeInitialized:
case EPVMFNodePrepared:
case EPVMFNodeStarted:
case EPVMFNodePaused:
case EPVMFNodeError:
{
//Check if encoder is initilized
if (iOMXEncoder != NULL)
{
//Get state of OpenMAX encoder
err = OMX_GetState(iOMXEncoder, &sState);
if (err != OMX_ErrorNone)
{
sState = OMX_StateInvalid;
}
if (sState == OMX_StateLoaded)
{
// this is a value obtained by synchronous call to component. Either the component was
// already in this state without node issuing any commands,
// or perhaps we started the Reset, but the callback notification has not yet arrived.
if (iResetInProgress)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::DoReset() OMX comp is in loaded state. Wait for official callback to change variables etc.", iNodeTypeId));
return;
}
}
else if (sState == OMX_StateIdle)
{
//this command is asynchronous. move the command from
//the input command queue to the current command, where
//it will remain until it is completed.
if (!iResetInProgress)
{
int32 err;
OSCL_TRY(err, iCurrentCommand.StoreL(aCmd););
if (err != OsclErrNone)
{
CommandComplete(iInputCommands, aCmd, PVMFErrNoMemory);
return;
}
iInputCommands.Erase(&aCmd);
iResetInProgress = true;
}
// if buffers aren't all back (due to timing issues with different callback AOs
// state change can be reported before all buffers are returned)
if (iNumOutstandingInputBuffers > 0 || iNumOutstandingOutputBuffers > 0)
{
LOGE("PVMFOMXEncNode-%s::DoReset() Waiting for %d input and-or %d output buffers", iNodeTypeId, iNumOutstandingInputBuffers, iNumOutstandingOutputBuffers);
return;
}
if (!iResetMsgSent)
{
// We can come here only if all buffers are already back
// Don't repeat any of this twice.
/* Change state to OMX_StateLoaded form OMX_StateIdle. */
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::DoReset() Changing Component State Idle->Loaded", iNodeTypeId));
err = OMX_SendCommand(iOMXEncoder, OMX_CommandStateSet, OMX_StateLoaded, NULL);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoReset(): Can't send StateSet command to encoder!", iNodeTypeId));
}
iResetMsgSent = true;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::DoReset() freeing output buffers", iNodeTypeId));
if (false == iOutputBuffersFreed)
{
if (!FreeBuffersFromComponent(iOutBufMemoryPool, // allocator
iOutputAllocSize, // size to allocate from pool (hdr only or hdr+ buffer)
iNumOutputBuffers, // number of buffers
iOutputPortIndex, // port idx
false // this is not input
))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoReset() Cannot free output buffers ", iNodeTypeId));
if (iResetInProgress)
{
iResetInProgress = false;
if ((iCurrentCommand.size() > 0) &&
(iCurrentCommand.front().iCmd == PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_RESET)
)
{
CommandComplete(iCurrentCommand, iCurrentCommand.front() , PVMFErrResource);
}
}
}
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::DoReset() freeing input buffers ", iNodeTypeId));
if (false == iInputBuffersFreed)
{
if (!FreeBuffersFromComponent(iInBufMemoryPool, // allocator
iInputAllocSize, // size to allocate from pool (hdr only or hdr+ buffer)
iNumInputBuffers, // number of buffers
iInputPortIndex, // port idx
true // this is input
))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoReset() Cannot free input buffers ", iNodeTypeId));
if (iResetInProgress)
{
iResetInProgress = false;
if ((iCurrentCommand.size() > 0) &&
(iCurrentCommand.front().iCmd == PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_RESET)
)
{
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFErrResource);
}
}
}
}
iEndOfDataReached = false;
iIsEOSSentToComponent = false;
iIsEOSReceivedFromComponent = false;
// also, perform Port deletion when the component replies with the command
// complete, not right here
} // end of if(iResetMsgSent)
return;
}
else if ((sState == OMX_StateExecuting) || (sState == OMX_StatePause))
{
//this command is asynchronous. move the command from
//the input command queue to the current command, where
//it will remain until it is completed.
if (!iResetInProgress)
{
int32 err;
OSCL_TRY(err, iCurrentCommand.StoreL(aCmd););
if (err != OsclErrNone)
{
CommandComplete(iInputCommands, aCmd, PVMFErrNoMemory);
return;
}
iInputCommands.Erase(&aCmd);
iResetInProgress = true;
}
/* Change state to OMX_StateIdle from OMX_StateExecuting or OMX_StatePause. */
if (!iStopInResetMsgSent)
{
// don't send twice in a row
iDataIn.Unbind();
iPreviousMediaData.Unbind();
if ((iOutFormat == PVMF_MIME_H264_VIDEO_MP4) || (iOutFormat == PVMF_MIME_H264_VIDEO_RAW))
{
// prepare for next start (if it comes)
iFirstNAL = true;
}
// Clear queued messages in ports
if (iInPort)
{
iInPort->ClearMsgQueues();
}
if (iOutPort)
{
iOutPort->ClearMsgQueues();
}
// Clear the data flags
iEndOfDataReached = false;
iIsEOSSentToComponent = false;
iIsEOSReceivedFromComponent = false;
iDoNotSendOutputBuffersDownstreamFlag = true; // stop sending output buffers downstream
iDoNotSaveInputBuffersFlag = true;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::DoReset() Changing Component State Executing->Idle or Pause->Idle", iNodeTypeId));
err = OMX_SendCommand(iOMXEncoder, OMX_CommandStateSet, OMX_StateIdle, NULL);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoReset(): Can't send StateSet command to Encoder!", iNodeTypeId));
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
break;
}
iStopInResetMsgSent = true;
// prevent the node from sending more buffers etc.
// if port reconfiguration is in process, let the state remain one of the port config states
// if there is a start command, we can do it seemlessly (by continuing the port reconfig)
if (iProcessingState == EPVMFOMXEncNodeProcessingState_ReadyToEncode)
iProcessingState = EPVMFOMXEncNodeProcessingState_Stopping;
}
return;
}
else
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoReset(): Encoder is not in the Idle state! %d", iNodeTypeId, sState ));
//do it here rather than relying on DTOR to avoid node reinit problems.
DeleteOMXEncoder();
//still return success.
}//end of if (sState == OMX_StateLoaded)
}//end of if (iOMXEncoder != NULL)
//delete all ports and notify observer.
if (iInPort)
{
OSCL_DELETE(((PVMFOMXEncPort*)iInPort));
iInPort = NULL;
}
if (iOutPort)
{
OSCL_DELETE(((PVMFOMXEncPort*)iOutPort));
iOutPort = NULL;
}
iDataIn.Unbind();
// Reset the metadata key list
iAvailableMetadataKeys.clear();
iEndOfDataReached = false;
iIsEOSSentToComponent = false;
iIsEOSReceivedFromComponent = false;
iProcessingState = EPVMFOMXEncNodeProcessingState_Idle;
//logoff & go back to Created state.
SetState(EPVMFNodeIdle);
if (iResetInProgress)
{
iResetInProgress = false;
if ((iCurrentCommand.size() > 0) &&
(iCurrentCommand.front().iCmd == PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_RESET)
)
{
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess);
}
}
else
{
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
}
}
break;
default:
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
break;
}
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::DoRequestPort(PVMFOMXEncNodeCommand& aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::DoRequestPort() In", iNodeTypeId));
//This node supports port request from any state
//retrieve port tag.
int32 tag;
OSCL_String* portconfig;
aCmd.PVMFOMXEncNodeCommandBase::Parse(tag, portconfig);
PVMFPortInterface* port = NULL;
int32 leavecode = 0;
//validate the tag...
switch (tag)
{
case PVMF_OMX_ENC_NODE_PORT_TYPE_INPUT:
if (iInPort)
{
CommandComplete(iInputCommands, aCmd, PVMFFailure);
break;
}
OSCL_TRY(leavecode, iInPort = OSCL_NEW(PVMFOMXEncPort, ((int32)tag, this, "OMXEncIn")););
if (leavecode || iInPort == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoRequestPort: Error - Input port instantiation failed", iNodeTypeId));
CommandComplete(iInputCommands, aCmd, PVMFErrArgument);
return;
}
// if format was provided in mimestring, set it now.
if (portconfig)
{
PVMFFormatType format = portconfig->get_str();
if (((PVMFOMXEncPort*)iInPort)->IsFormatSupported(format))
{
((PVMFOMXEncPort*)iInPort)->iFormat = format;
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoRequestPort: Error - Input port does not support format %s", iNodeTypeId, format.getMIMEStrPtr()));
OSCL_DELETE(((PVMFOMXEncPort*)iInPort));
iInPort = NULL;
CommandComplete(iInputCommands, aCmd, PVMFErrArgument);
return;
}
}
port = iInPort;
break;
case PVMF_OMX_ENC_NODE_PORT_TYPE_OUTPUT:
if (iOutPort)
{
CommandComplete(iInputCommands, aCmd, PVMFFailure);
break;
}
OSCL_TRY(leavecode, iOutPort = OSCL_NEW(PVMFOMXEncPort, ((int32)tag, this, "OMXEncOut")));
if (leavecode || iOutPort == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoRequestPort: Error - Output port instantiation failed", iNodeTypeId));
CommandComplete(iInputCommands, aCmd, PVMFErrArgument);
return;
}
// if format was provided in mimestring, set it now.
if (portconfig)
{
PVMFFormatType format = portconfig->get_str();
if (((PVMFOMXEncPort*)iOutPort)->IsFormatSupported(format) && (SetCodecType(format) == PVMFSuccess))
{
((PVMFOMXEncPort*)iOutPort)->iFormat = format;
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoRequestPort: Error - Output port does not support format %s", iNodeTypeId, format.getMIMEStrPtr()));
OSCL_DELETE(((PVMFOMXEncPort*)iOutPort));
iOutPort = NULL;
CommandComplete(iInputCommands, aCmd, PVMFErrArgument);
return;
}
}
port = iOutPort;
break;
default:
//bad port tag
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoRequestPort: Error - Invalid port tag", iNodeTypeId));
CommandComplete(iInputCommands, aCmd, PVMFErrArgument);
return;
}
//Return the port pointer to the caller.
CommandComplete(iInputCommands, aCmd, PVMFSuccess, (OsclAny*)port);
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::DoReleasePort(PVMFOMXEncNodeCommand& aCmd)
{
PVMFPortInterface* temp;
aCmd.PVMFOMXEncNodeCommandBase::Parse(temp);
PVMFOMXEncPort* port = (PVMFOMXEncPort*) temp;
#ifdef _TEST_AE_ERROR_HANDLING
if (FAIL_NODE_CMD_RELEASE_PORT == iErrorNodeCmd)
{
port = NULL;
}
#endif
if (port != NULL && (port == iInPort || port == iOutPort))
{
if (port == iInPort)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::DoReleasePort Input port released", iNodeTypeId));
OSCL_DELETE(((PVMFOMXEncPort*)iInPort));
iInPort = NULL;
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::DoReleasePort Output port released", iNodeTypeId));
OSCL_DELETE(((PVMFOMXEncPort*)iOutPort));
iOutPort = NULL;
}
//delete the port.
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
}
else
{
//port not found.
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoReleasePort ERROR unknown port cannot be released", iNodeTypeId));
CommandComplete(iInputCommands, aCmd, PVMFFailure);
}
}
/////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFOMXEncNode::DoGetNodeMetadataKey(PVMFOMXEncNodeCommand& aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::DoGetNodeMetadataKey() In", iNodeTypeId));
PVMFMetadataList* keylistptr = NULL;
uint32 starting_index;
int32 max_entries;
char* query_key;
aCmd.PVMFOMXEncNodeCommand::Parse(keylistptr, starting_index, max_entries, query_key);
// Check parameters
if (keylistptr == NULL)
{
// The list pointer is invalid
return PVMFErrArgument;
}
// Update the available metadata keys
iAvailableMetadataKeys.clear();
int32 leavecode = 0;
leavecode = Push_Back_MetadataKeys(PVOMXENCMETADATA_CODECINFO_VIDEO_FORMAT_KEY);
if (iYUVWidth > 0 && iYUVHeight > 0)
{
leavecode = 0;
leavecode = Push_Back_MetadataKeys(PVOMXENCMETADATA_CODECINFO_VIDEO_WIDTH_KEY);
if (0 == leavecode)
leavecode = Push_Back_MetadataKeys(PVOMXENCMETADATA_CODECINFO_VIDEO_HEIGHT_KEY);
}
// add the profile, level and avgbitrate
PVMF_MPEGVideoProfileType aProfile;
PVMF_MPEGVideoLevelType aLevel;
if (GetProfileAndLevel(aProfile, aLevel) == PVMFSuccess)
{
// For H263 this metadata will be available only after first frame decoding
leavecode = 0;
leavecode = Push_Back_MetadataKeys(PVOMXENCMETADATA_CODECINFO_VIDEO_PROFILE_KEY);
if (0 == leavecode)
leavecode = Push_Back_MetadataKeys(PVOMXENCMETADATA_CODECINFO_VIDEO_LEVEL_KEY);
}
if (0 == leavecode)
leavecode = Push_Back_MetadataKeys(PVOMXENCMETADATA_CODECINFO_VIDEO_AVGBITRATE_KEY);
if ((starting_index > (iAvailableMetadataKeys.size() - 1)) || max_entries == 0)
{
// Invalid starting index and/or max entries
return PVMFErrArgument;
}
// Copy the requested keys
uint32 num_entries = 0;
int32 num_added = 0;
for (uint32 lcv = 0; lcv < iAvailableMetadataKeys.size(); lcv++)
{
if (query_key == NULL)
{
// No query key so this key is counted
++num_entries;
if (num_entries > starting_index)
{
// Past the starting index so copy the key
leavecode = 0;
leavecode = Push_Back_MetadataKeys(keylistptr, lcv);
OSCL_FIRST_CATCH_ANY(leavecode,
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DoGetNodeMetadataKey() Memory allocation failure when copying metadata key", iNodeTypeId));
return PVMFErrNoMemory);
num_added++;
}
}
else
{
// Check if the key matche the query key
if (pv_mime_strcmp(iAvailableMetadataKeys[lcv].get_cstr(), query_key) >= 0)
{
// This key is counted
++num_entries;
if (num_entries > starting_index)
{
// Past the starting index so copy the key
leavecode = 0;
leavecode = Push_Back_MetadataKeys(keylistptr, lcv);
OSCL_FIRST_CATCH_ANY(leavecode,
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::DoGetNodeMetadataKey() Memory allocation failure when copying metadata key", iNodeTypeId));
return PVMFErrNoMemory);
num_added++;
}
}
}
// Check if max number of entries have been copied
if (max_entries > 0 && num_added >= max_entries)
{
break;
}
}
return PVMFSuccess;
}
/////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFOMXEncNode::DoGetNodeMetadataValue(PVMFOMXEncNodeCommand& aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::DoGetNodeMetadataValue() In", iNodeTypeId));
PVMFMetadataList* keylistptr = NULL;
Oscl_Vector<PvmiKvp, OsclMemAllocator>* valuelistptr = NULL;
uint32 starting_index;
int32 max_entries;
aCmd.PVMFOMXEncNodeCommand::Parse(keylistptr, valuelistptr, starting_index, max_entries);
// Check the parameters
if (keylistptr == NULL || valuelistptr == NULL)
{
return PVMFErrArgument;
}
uint32 numkeys = keylistptr->size();
if (starting_index > (numkeys - 1) || numkeys <= 0 || max_entries == 0)
{
// Don't do anything
return PVMFErrArgument;
}
uint32 numvalentries = 0;
int32 numentriesadded = 0;
for (uint32 lcv = 0; lcv < numkeys; lcv++)
{
int32 leavecode = 0;
PvmiKvp KeyVal;
KeyVal.key = NULL;
uint32 KeyLen = 0;
if ((oscl_strcmp((*keylistptr)[lcv].get_cstr(), PVOMXENCMETADATA_CODECINFO_VIDEO_WIDTH_KEY) == 0) &&
iYUVWidth > 0)
{
// Video width
// Increment the counter for the number of values found so far
++numvalentries;
// Create a value entry if past the starting index
if (numvalentries > starting_index)
{
KeyLen = oscl_strlen(PVOMXENCMETADATA_CODECINFO_VIDEO_WIDTH_KEY) + 1; // for "codec-info/video/width;"
KeyLen += oscl_strlen(PVMI_KVPVALTYPE_STRING_CONSTCHAR); // for "valtype="
KeyLen += oscl_strlen(PVMI_KVPVALTYPE_UINT32_STRING_CONSTCHAR) + 1; // for "uint32" and NULL terminator
// Allocate memory for the string
leavecode = 0;
leavecode = CreateNewArray(KeyVal.key, KeyLen);
if (leavecode == 0)
{
// Copy the key string
oscl_strncpy(KeyVal.key, PVOMXENCMETADATA_CODECINFO_VIDEO_WIDTH_KEY, oscl_strlen(PVOMXENCMETADATA_CODECINFO_VIDEO_WIDTH_KEY) + 1);
oscl_strncat(KeyVal.key, PVOMXENCMETADATA_SEMICOLON, oscl_strlen(PVOMXENCMETADATA_SEMICOLON));
oscl_strncat(KeyVal.key, PVMI_KVPVALTYPE_STRING_CONSTCHAR, oscl_strlen(PVMI_KVPVALTYPE_STRING_CONSTCHAR));
oscl_strncat(KeyVal.key, PVMI_KVPVALTYPE_UINT32_STRING_CONSTCHAR, oscl_strlen(PVMI_KVPVALTYPE_UINT32_STRING_CONSTCHAR));
KeyVal.key[KeyLen-1] = NULL_TERM_CHAR;
// Copy the value
KeyVal.value.uint32_value = iYUVWidth;
// Set the length and capacity
KeyVal.length = 1;
KeyVal.capacity = 1;
}
else
{
// Memory allocation failed
KeyVal.key = NULL;
break;
}
}
}
else if ((oscl_strcmp((*keylistptr)[lcv].get_cstr(), PVOMXENCMETADATA_CODECINFO_VIDEO_HEIGHT_KEY) == 0) &&
iYUVHeight > 0)
{
// Video height
// Increment the counter for the number of values found so far
++numvalentries;
// Create a value entry if past the starting index
if (numvalentries > starting_index)
{
KeyLen = oscl_strlen(PVOMXENCMETADATA_CODECINFO_VIDEO_HEIGHT_KEY) + 1; // for "codec-info/video/height;"
KeyLen += oscl_strlen(PVMI_KVPVALTYPE_STRING_CONSTCHAR); // for "valtype="
KeyLen += oscl_strlen(PVMI_KVPVALTYPE_UINT32_STRING_CONSTCHAR) + 1; // for "uint32" and NULL terminator
// Allocate memory for the string
leavecode = 0;
leavecode = CreateNewArray(KeyVal.key, KeyLen);
if (leavecode == 0)
{
// Copy the key string
oscl_strncpy(KeyVal.key, PVOMXENCMETADATA_CODECINFO_VIDEO_HEIGHT_KEY, oscl_strlen(PVOMXENCMETADATA_CODECINFO_VIDEO_HEIGHT_KEY) + 1);
oscl_strncat(KeyVal.key, PVOMXENCMETADATA_SEMICOLON, oscl_strlen(PVOMXENCMETADATA_SEMICOLON));
oscl_strncat(KeyVal.key, PVMI_KVPVALTYPE_STRING_CONSTCHAR, oscl_strlen(PVMI_KVPVALTYPE_STRING_CONSTCHAR));
oscl_strncat(KeyVal.key, PVMI_KVPVALTYPE_UINT32_STRING_CONSTCHAR, oscl_strlen(PVMI_KVPVALTYPE_UINT32_STRING_CONSTCHAR));
KeyVal.key[KeyLen-1] = NULL_TERM_CHAR;
// Copy the value
KeyVal.value.uint32_value = iYUVHeight;
// Set the length and capacity
KeyVal.length = 1;
KeyVal.capacity = 1;
}
else
{
// Memory allocation failed
KeyVal.key = NULL;
break;
}
}
}
else if ((oscl_strcmp((*keylistptr)[lcv].get_cstr(), PVOMXENCMETADATA_CODECINFO_VIDEO_PROFILE_KEY) == 0))
{
// Video profile
// Increment the counter for the number of values found so far
++numvalentries;
// Create a value entry if past the starting index
if (numvalentries > starting_index)
{
KeyLen = oscl_strlen(PVOMXENCMETADATA_CODECINFO_VIDEO_PROFILE_KEY) + 1; // for "codec-info/video/profile;"
KeyLen += oscl_strlen(PVMI_KVPVALTYPE_STRING_CONSTCHAR); // for "valtype="
KeyLen += oscl_strlen(PVMI_KVPVALTYPE_UINT32_STRING_CONSTCHAR) + 1; // for "uint32" and NULL terminator
// Allocate memory for the string
leavecode = 0;
leavecode = CreateNewArray(KeyVal.key, KeyLen);
if (leavecode == 0)
{
PVMF_MPEGVideoProfileType aProfile;
PVMF_MPEGVideoLevelType aLevel;
if (GetProfileAndLevel(aProfile, aLevel) == PVMFSuccess)
{
// Copy the key string
oscl_strncpy(KeyVal.key, PVOMXENCMETADATA_CODECINFO_VIDEO_PROFILE_KEY, oscl_strlen(PVOMXENCMETADATA_CODECINFO_VIDEO_PROFILE_KEY) + 1);
oscl_strncat(KeyVal.key, PVOMXENCMETADATA_SEMICOLON, oscl_strlen(PVOMXENCMETADATA_SEMICOLON));
oscl_strncat(KeyVal.key, PVMI_KVPVALTYPE_STRING_CONSTCHAR, oscl_strlen(PVMI_KVPVALTYPE_STRING_CONSTCHAR));
oscl_strncat(KeyVal.key, PVMI_KVPVALTYPE_UINT32_STRING_CONSTCHAR, oscl_strlen(PVMI_KVPVALTYPE_UINT32_STRING_CONSTCHAR));
KeyVal.key[KeyLen-1] = NULL_TERM_CHAR;
// Copy the value
KeyVal.value.uint32_value = (uint32)aProfile; // This is to be decided, who will interpret these value
// Set the length and capacity
KeyVal.length = 1;
KeyVal.capacity = 1;
}
else
{
// Memory allocation failed
KeyVal.key = NULL;
break;
}
}
else
{
// Memory allocation failed
KeyVal.key = NULL;
break;
}
}
}
else if ((oscl_strcmp((*keylistptr)[lcv].get_cstr(), PVOMXENCMETADATA_CODECINFO_VIDEO_LEVEL_KEY) == 0))
{
// Video level
// Increment the counter for the number of values found so far
++numvalentries;
// Create a value entry if past the starting index
if (numvalentries > starting_index)
{
KeyLen = oscl_strlen(PVOMXENCMETADATA_CODECINFO_VIDEO_LEVEL_KEY) + 1; // for "codec-info/video/level;"
KeyLen += oscl_strlen(PVMI_KVPVALTYPE_STRING_CONSTCHAR); // for "valtype="
KeyLen += oscl_strlen(PVMI_KVPVALTYPE_UINT32_STRING_CONSTCHAR) + 1; // for "uint32" and NULL terminator
// Allocate memory for the string
leavecode = 0;
leavecode = CreateNewArray(KeyVal.key, KeyLen);
if (leavecode == 0)
{
PVMF_MPEGVideoProfileType aProfile;
PVMF_MPEGVideoLevelType aLevel;
if (GetProfileAndLevel(aProfile, aLevel) == PVMFSuccess)
{
// Copy the key string
oscl_strncpy(KeyVal.key, PVOMXENCMETADATA_CODECINFO_VIDEO_LEVEL_KEY, oscl_strlen(PVOMXENCMETADATA_CODECINFO_VIDEO_LEVEL_KEY) + 1);
oscl_strncat(KeyVal.key, PVOMXENCMETADATA_SEMICOLON, oscl_strlen(PVOMXENCMETADATA_SEMICOLON));
oscl_strncat(KeyVal.key, PVMI_KVPVALTYPE_STRING_CONSTCHAR, oscl_strlen(PVMI_KVPVALTYPE_STRING_CONSTCHAR));
oscl_strncat(KeyVal.key, PVMI_KVPVALTYPE_UINT32_STRING_CONSTCHAR, oscl_strlen(PVMI_KVPVALTYPE_UINT32_STRING_CONSTCHAR));
KeyVal.key[KeyLen-1] = NULL_TERM_CHAR;
// Copy the value
KeyVal.value.uint32_value = (uint32)aLevel; // This is to be decided, who will interpret these value
// Set the length and capacity
KeyVal.length = 1;
KeyVal.capacity = 1;
}
else
{
// Memory allocation failed
KeyVal.key = NULL;
break;
}
}
else
{
// Memory allocation failed
KeyVal.key = NULL;
break;
}
}
}
else if ((oscl_strcmp((*keylistptr)[lcv].get_cstr(), PVOMXENCMETADATA_CODECINFO_VIDEO_AVGBITRATE_KEY) == 0) &&
(iAvgBitrateValue > 0))
{
// Video average bitrate
// Increment the counter for the number of values found so far
++numvalentries;
// Create a value entry if past the starting index
if (numvalentries > starting_index)
{
KeyLen = oscl_strlen(PVOMXENCMETADATA_CODECINFO_VIDEO_AVGBITRATE_KEY) + 1; // for "codec-info/video/avgbitrate;"
KeyLen += oscl_strlen(PVMI_KVPVALTYPE_STRING_CONSTCHAR); // for "valtype="
KeyLen += oscl_strlen(PVMI_KVPVALTYPE_UINT32_STRING_CONSTCHAR) + 1; // for "uint32" and NULL terminator
// Allocate memory for the string
leavecode = 0;
leavecode = CreateNewArray(KeyVal.key, KeyLen);
if (leavecode == 0)
{
// Copy the key string
oscl_strncpy(KeyVal.key, PVOMXENCMETADATA_CODECINFO_VIDEO_AVGBITRATE_KEY, oscl_strlen(PVOMXENCMETADATA_CODECINFO_VIDEO_AVGBITRATE_KEY) + 1);
oscl_strncat(KeyVal.key, PVOMXENCMETADATA_SEMICOLON, oscl_strlen(PVOMXENCMETADATA_SEMICOLON));
oscl_strncat(KeyVal.key, PVMI_KVPVALTYPE_STRING_CONSTCHAR, oscl_strlen(PVMI_KVPVALTYPE_STRING_CONSTCHAR));
oscl_strncat(KeyVal.key, PVMI_KVPVALTYPE_UINT32_STRING_CONSTCHAR, oscl_strlen(PVMI_KVPVALTYPE_UINT32_STRING_CONSTCHAR));
KeyVal.key[KeyLen-1] = NULL_TERM_CHAR;
// Copy the value
KeyVal.value.uint32_value = iAvgBitrateValue;
// Set the length and capacity
KeyVal.length = 1;
KeyVal.capacity = 1;
}
else
{
// Memory allocation failed
KeyVal.key = NULL;
break;
}
}
}
else if ((oscl_strcmp((*keylistptr)[lcv].get_cstr(), PVOMXENCMETADATA_CODECINFO_VIDEO_FORMAT_KEY) == 0) &&
(((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H2631998 || ((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H2632000 || ((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_M4V ||
((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H264_VIDEO || ((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H264_VIDEO_MP4 ||
((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H264_VIDEO_RAW || ((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_WMV))
{
// Format
// Increment the counter for the number of values found so far
++numvalentries;
// Create a value entry if past the starting index
if (numvalentries > starting_index)
{
KeyLen = oscl_strlen(PVOMXENCMETADATA_CODECINFO_VIDEO_FORMAT_KEY) + 1; // for "codec-info/video/format;"
KeyLen += oscl_strlen(PVMI_KVPVALTYPE_STRING_CONSTCHAR); // for "valtype="
KeyLen += oscl_strlen(PVMI_KVPVALTYPE_CHARPTR_STRING_CONSTCHAR) + 1; // for "char*" and NULL terminator
uint32 valuelen = 0;
if (((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H264_VIDEO)
{
valuelen = oscl_strlen(_STRLIT_CHAR(PVMF_MIME_H264_VIDEO)) + 1; // Value string plus one for NULL terminator
}
else if (((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H264_VIDEO_MP4)
{
valuelen = oscl_strlen(_STRLIT_CHAR(PVMF_MIME_H264_VIDEO_MP4)) + 1; // Value string plus one for NULL terminator
}
else if (((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H264_VIDEO_RAW)
{
valuelen = oscl_strlen(_STRLIT_CHAR(PVMF_MIME_H264_VIDEO_RAW)) + 1; // Value string plus one for NULL terminator
}
else if (((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_M4V)
{
valuelen = oscl_strlen(_STRLIT_CHAR(PVMF_MIME_M4V)) + 1; // Value string plus one for NULL terminator
}
else if (((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H2631998)
{
valuelen = oscl_strlen(_STRLIT_CHAR(PVMF_MIME_H2631998)) + 1; // Value string plus one for NULL terminator
}
else if (((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H2632000)
{
oscl_strncpy(KeyVal.value.pChar_value, _STRLIT_CHAR(PVMF_MIME_H2632000), valuelen);
}
else if (((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_WMV)
{
valuelen = oscl_strlen(_STRLIT_CHAR(PVMF_MIME_WMV)) + 1; // Value string plus one for NULL terminator
}
else
{
// Should not enter here
OSCL_ASSERT(false);
valuelen = 1;
}
// Allocate memory for the strings
leavecode = 0;
leavecode = CreateNewArray(KeyVal.key, KeyLen);
if (0 == leavecode)
{
leavecode = CreateNewArray(KeyVal.value.pChar_value , valuelen);
}
if (leavecode == 0)
{
// Copy the key string
oscl_strncpy(KeyVal.key, PVOMXENCMETADATA_CODECINFO_VIDEO_FORMAT_KEY, oscl_strlen(PVOMXENCMETADATA_CODECINFO_VIDEO_FORMAT_KEY) + 1);
oscl_strncat(KeyVal.key, PVOMXENCMETADATA_SEMICOLON, oscl_strlen(PVOMXENCMETADATA_SEMICOLON));
oscl_strncat(KeyVal.key, PVMI_KVPVALTYPE_STRING_CONSTCHAR, oscl_strlen(PVMI_KVPVALTYPE_STRING_CONSTCHAR));
oscl_strncat(KeyVal.key, PVMI_KVPVALTYPE_CHARPTR_STRING_CONSTCHAR, oscl_strlen(PVMI_KVPVALTYPE_CHARPTR_STRING_CONSTCHAR));
KeyVal.key[KeyLen-1] = NULL_TERM_CHAR;
// Copy the value
if (((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H264_VIDEO)
{
oscl_strncpy(KeyVal.value.pChar_value, _STRLIT_CHAR(PVMF_MIME_H264_VIDEO), valuelen);
}
else if (((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H264_VIDEO_MP4)
{
oscl_strncpy(KeyVal.value.pChar_value, _STRLIT_CHAR(PVMF_MIME_H264_VIDEO_MP4), valuelen);
}
else if (((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H264_VIDEO_RAW)
{
oscl_strncpy(KeyVal.value.pChar_value, _STRLIT_CHAR(PVMF_MIME_H264_VIDEO_RAW), valuelen);
}
else if (((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_M4V)
{
oscl_strncpy(KeyVal.value.pChar_value, _STRLIT_CHAR(PVMF_MIME_M4V), valuelen);
}
else if (((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H2631998)
{
oscl_strncpy(KeyVal.value.pChar_value, _STRLIT_CHAR(PVMF_MIME_H2631998), valuelen);
}
else if (((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H2632000)
{
oscl_strncpy(KeyVal.value.pChar_value, _STRLIT_CHAR(PVMF_MIME_H2632000), valuelen);
}
else if (((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_WMV)
{
oscl_strncpy(KeyVal.value.pChar_value, _STRLIT_CHAR(PVMF_MIME_WMV), valuelen);
}
else
{
// Should not enter here
OSCL_ASSERT(false);
valuelen = 1;
}
KeyVal.value.pChar_value[valuelen-1] = NULL_TERM_CHAR;
// Set the length and capacity
KeyVal.length = valuelen;
KeyVal.capacity = valuelen;
}
else
{
// Memory allocation failed so clean up
if (KeyVal.key)
{
OSCL_ARRAY_DELETE(KeyVal.key);
KeyVal.key = NULL;
}
if (KeyVal.value.pChar_value)
{
OSCL_ARRAY_DELETE(KeyVal.value.pChar_value);
}
break;
}
}
}
if (KeyVal.key != NULL)
{
leavecode = 0;
leavecode = PushBackKeyVal(valuelistptr, KeyVal);
if (leavecode != 0)
{
switch (GetValTypeFromKeyString(KeyVal.key))
{
case PVMI_KVPVALTYPE_CHARPTR:
if (KeyVal.value.pChar_value != NULL)
{
OSCL_ARRAY_DELETE(KeyVal.value.pChar_value);
KeyVal.value.pChar_value = NULL;
}
break;
default:
// Add more case statements if other value types are returned
break;
}
OSCL_ARRAY_DELETE(KeyVal.key);
KeyVal.key = NULL;
}
else
{
// Increment the counter for number of value entries added to the list
++numentriesadded;
}
// Check if the max number of value entries were added
if (max_entries > 0 && numentriesadded >= max_entries)
{
break;
}
}
}
return PVMFSuccess;
}
/////////////////////////////////////////////////////////////////////////////
bool PVMFOMXEncNode::ReleaseAllPorts()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::ReleaseAllPorts() In", iNodeTypeId));
if (iInPort)
{
iInPort->ClearMsgQueues();
iInPort->Disconnect();
OSCL_DELETE(((PVMFOMXEncPort*)iInPort));
iInPort = NULL;
}
if (iOutPort)
{
iOutPort->ClearMsgQueues();
iOutPort->Disconnect();
OSCL_DELETE(((PVMFOMXEncPort*)iOutPort));
iOutPort = NULL;
}
return true;
}
/////////////////////////////////////////////////////////////////////////////
// Clean Up Encoder
/////////////////////////////////////////////////////////////////////////////
bool PVMFOMXEncNode::DeleteOMXEncoder()
{
OMX_ERRORTYPE err;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::DeleteOMXEncoder() In", iNodeTypeId));
if (iOMXEncoder != NULL)
{
/* Free Component handle. */
err = OMX_MasterFreeHandle(iOMXEncoder);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::DeleteOMXEncoder(): Can't free encoder's handle!", iNodeTypeId));
}
iOMXEncoder = NULL;
}//end of if (iOMXEncoder != NULL)
return true;
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::ChangeNodeState(TPVMFNodeInterfaceState aNewState)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::ChangeNodeState() Changing state from %d to %d", iNodeTypeId, iInterfaceState, aNewState));
iInterfaceState = aNewState;
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::freechunkavailable(OsclAny *aContext)
{
// check context to see whether input or output buffer was returned to the mempool
if (aContext == (OsclAny *) iInBufMemoryPool)
{
iNumOutstandingInputBuffers--;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::freechunkavailable() Memory chunk in INPUT mempool was deallocated, %d out of %d now available", iNodeTypeId, iNumInputBuffers - iNumOutstandingInputBuffers, iNumInputBuffers));
// notification only works once.
// If there are multiple buffers coming back in a row, make sure to set the notification
// flag in the mempool again, so that next buffer also causes notification
iInBufMemoryPool->notifyfreechunkavailable(*this, aContext);
}
else if (aContext == (OsclAny *) iOutBufMemoryPool)
{
iNumOutstandingOutputBuffers--;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::freechunkavailable() Memory chunk in OUTPUT mempool was deallocated, %d out of %d now available", iNodeTypeId, iNumOutputBuffers - iNumOutstandingOutputBuffers, iNumOutputBuffers));
// notification only works once.
// If there are multiple buffers coming back in a row, make sure to set the notification
// flag in the mempool again, so that next buffer also causes notification
iOutBufMemoryPool->notifyfreechunkavailable(*this, aContext);
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::freechunkavailable() UNKNOWN mempool ", iNodeTypeId));
}
// reschedule
if (IsAdded())
RunIfNotReady();
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::HandlePortActivity(const PVMFPortActivity &aActivity)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "0x%x PVMFOMXEncNode-%s::PortActivity: port=0x%x, type=%d",
this, iNodeTypeId, aActivity.iPort, aActivity.iType));
switch (aActivity.iType)
{
case PVMF_PORT_ACTIVITY_OUTGOING_MSG:
//An outgoing message was queued on this port.
//We only need to queue a port activity event on the
//first message. Additional events will be queued during
//the port processing as needed.
if (aActivity.iPort->OutgoingMsgQueueSize() == 1)
{
//wake up the AO to process the port activity event.
RunIfNotReady();
}
break;
case PVMF_PORT_ACTIVITY_INCOMING_MSG:
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "PVMFOMXEncNode-%s::PortActivity: IncomingMsgQueueSize=%d", iNodeTypeId, aActivity.iPort->IncomingMsgQueueSize()));
if (aActivity.iPort->IncomingMsgQueueSize() == 1)
{
//wake up the AO to process the port activity event.
RunIfNotReady();
}
break;
case PVMF_PORT_ACTIVITY_OUTGOING_QUEUE_READY:
if (iProcessingState == EPVMFOMXEncNodeProcessingState_WaitForOutgoingQueue)
{
iProcessingState = EPVMFOMXEncNodeProcessingState_ReadyToEncode;
RunIfNotReady();
}
break;
case PVMF_PORT_ACTIVITY_CONNECT:
//nothing needed.
break;
case PVMF_PORT_ACTIVITY_DISCONNECT:
//clear the node input data when either port is disconnected.
iDataIn.Unbind();
break;
case PVMF_PORT_ACTIVITY_CONNECTED_PORT_BUSY:
// The connected port has become busy (its incoming queue is
// busy).
// No action is needed here-- the port processing code
// checks for connected port busy during data processing.
break;
case PVMF_PORT_ACTIVITY_CONNECTED_PORT_READY:
// The connected port has transitioned from Busy to Ready to Receive.
// It's time to start processing outgoing messages again.
//iProcessingState should transition from WaitForOutputPort to ReadyToEncode
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "0x%x PVMFOMXEncNode-%s::PortActivity: Connected port is now ready", this, iNodeTypeId));
RunIfNotReady();
break;
default:
break;
}
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::DoCancelAllCommands(PVMFOMXEncNodeCommand& aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::DoCancelAllCommands", iNodeTypeId));
//first cancel the current command if any
{
while (!iCurrentCommand.empty())
{
CommandComplete(iCurrentCommand, iCurrentCommand[0], PVMFErrCancelled);
}
}
//next cancel all queued commands
{
//start at element 1 since this cancel command is element 0.
while (iInputCommands.size() > 1)
{
CommandComplete(iInputCommands, iInputCommands[1], PVMFErrCancelled);
}
}
if (iResetInProgress && !iResetMsgSent)
{
// if reset is started but reset msg has not been sent, we can cancel reset
// as if nothing happened. Otherwise, the callback will set the flag back to false
iResetInProgress = false;
}
//finally, report cancel complete.
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::DoCancelCommand(PVMFOMXEncNodeCommand& aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::DoCancelCommand", iNodeTypeId));
//extract the command ID from the parameters.
PVMFCommandId id;
aCmd.PVMFOMXEncNodeCommandBase::Parse(id);
//first check "current" command if any
{
PVMFOMXEncNodeCommand* cmd = iCurrentCommand.FindById(id);
if (cmd)
{
// if reset is being canceled:
if (cmd->iCmd == PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_RESET)
{
if (iResetInProgress && !iResetMsgSent)
{
// if reset is started but reset msg has not been sent, we can cancel reset
// as if nothing happened. Otherwise, the callback will set the flag back to false
iResetInProgress = false;
}
}
//cancel the queued command
CommandComplete(iCurrentCommand, *cmd, PVMFErrCancelled);
//report cancel success
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
return;
}
}
//next check input queue.
{
//start at element 1 since this cancel command is element 0.
PVMFOMXEncNodeCommand* cmd = iInputCommands.FindById(id, 1);
if (cmd)
{
//cancel the queued command
CommandComplete(iInputCommands, *cmd, PVMFErrCancelled);
//report cancel success
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
return;
}
}
//if we get here the command isn't queued so the cancel fails.
CommandComplete(iInputCommands, aCmd, PVMFErrArgument);
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::DoQueryUuid(PVMFOMXEncNodeCommand& aCmd)
{
//This node supports Query UUID from any state
OSCL_String* mimetype;
Oscl_Vector<PVUuid, OsclMemAllocator> *uuidvec;
bool exactmatch;
aCmd.PVMFOMXEncNodeCommandBase::Parse(mimetype, uuidvec, exactmatch);
//Try to match the input mimetype against any of
//the custom interfaces for this node
//Match against custom interface1...
if (*mimetype == PVMF_OMX_ENC_NODE_CUSTOM1_MIMETYPE
//also match against base mimetypes for custom interface1,
//unless exactmatch is set.
|| (!exactmatch && *mimetype == PVMF_OMX_ENC_NODE_MIMETYPE)
|| (!exactmatch && *mimetype == PVMF_BASEMIMETYPE))
{
PVUuid uuid(PVMF_OMX_ENC_NODE_CUSTOM1_UUID);
uuidvec->push_back(uuid);
}
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::DoQueryInterface(PVMFOMXEncNodeCommand& aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::DoQueryInterface", iNodeTypeId));
PVUuid* uuid;
PVInterface** ptr;
aCmd.PVMFOMXEncNodeCommandBase::Parse(uuid, ptr);
if (*uuid == PVUuid(PVMF_OMX_ENC_NODE_CUSTOM1_UUID))
{
addRef();
*ptr = (PVMFOMXEncNodeExtensionInterface*)this;
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
}
else if (*uuid == PVUuid(KPVMFMetadataExtensionUuid))
{
addRef();
*ptr = (PVMFMetadataExtensionInterface*)this;
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
}
else if (*uuid == PVUuid(PVMI_CAPABILITY_AND_CONFIG_PVUUID))
{
addRef();
*ptr = (PvmiCapabilityAndConfig*)this;
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
}
else if (*uuid == PVMp4H263EncExtensionUUID)
{
addRef();
*ptr = OSCL_STATIC_CAST(PVMp4H263EncExtensionInterface*, this);
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
//iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
}
else if (*uuid == PVAudioEncExtensionUUID)
{
addRef();
*ptr = OSCL_STATIC_CAST(PVAudioEncExtensionInterface*, this);
//iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
}
else
{
//not supported
*ptr = NULL;
CommandComplete(iInputCommands, aCmd, PVMFFailure);
}
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::addRef()
{
++iExtensionRefCount;
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::removeRef()
{
--iExtensionRefCount;
}
/////////////////////////////////////////////////////////////////////////////
bool PVMFOMXEncNode::queryInterface(const PVUuid& uuid, PVInterface*& iface)
{
PVUuid my_uuid(PVMF_OMX_ENC_NODE_CUSTOM1_UUID);
if (uuid == my_uuid)
{
PVMFOMXEncNodeExtensionInterface* myInterface = OSCL_STATIC_CAST(PVMFOMXEncNodeExtensionInterface*, this);
iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
++iExtensionRefCount;
return true;
}
else if (uuid == KPVMFMetadataExtensionUuid)
{
PVMFMetadataExtensionInterface* myInterface = OSCL_STATIC_CAST(PVMFMetadataExtensionInterface*, this);
iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
++iExtensionRefCount;
return true;
}
return false;
}
/////////////////////////////////////////////////////////////////////////////
uint32 PVMFOMXEncNode::GetNumMetadataKeys(char* aQueryKeyString)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::GetNumMetadataKeys() called", iNodeTypeId));
// Update the available metadata keys
iAvailableMetadataKeys.clear();
int32 errcode = 0;
OSCL_TRY(errcode, iAvailableMetadataKeys.push_back(PVOMXENCMETADATA_CODECINFO_VIDEO_FORMAT_KEY));
if (iYUVWidth > 0 && iYUVHeight > 0)
{
errcode = 0;
OSCL_TRY(errcode,
iAvailableMetadataKeys.push_back(PVOMXENCMETADATA_CODECINFO_VIDEO_WIDTH_KEY);
iAvailableMetadataKeys.push_back(PVOMXENCMETADATA_CODECINFO_VIDEO_HEIGHT_KEY));
}
// add the profile, level and avgbitrate
PVMF_MPEGVideoProfileType aProfile;
PVMF_MPEGVideoLevelType aLevel;
if (GetProfileAndLevel(aProfile, aLevel) == PVMFSuccess)
{
// For H263 this metadata will be available only after first frame decoding
errcode = 0;
OSCL_TRY(errcode, iAvailableMetadataKeys.push_back(PVOMXENCMETADATA_CODECINFO_VIDEO_PROFILE_KEY));
errcode = 0;
OSCL_TRY(errcode, iAvailableMetadataKeys.push_back(PVOMXENCMETADATA_CODECINFO_VIDEO_LEVEL_KEY));
}
errcode = 0;
OSCL_TRY(errcode, iAvailableMetadataKeys.push_back(PVOMXENCMETADATA_CODECINFO_VIDEO_AVGBITRATE_KEY));
uint32 num_entries = 0;
if (aQueryKeyString == NULL)
{
num_entries = iAvailableMetadataKeys.size();
}
else
{
for (uint32 i = 0; i < iAvailableMetadataKeys.size(); i++)
{
if (pv_mime_strcmp(iAvailableMetadataKeys[i].get_cstr(), aQueryKeyString) >= 0)
{
num_entries++;
}
}
}
return num_entries; // Number of elements
}
///////////////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::setObserver(PvmiConfigAndCapabilityCmdObserver* aObserver)
{
OSCL_UNUSED_ARG(aObserver);
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::setObserver()", iNodeTypeId));
// This method is not supported so leave
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::setObserver() is not supported!", iNodeTypeId));
OSCL_LEAVE(PVMFErrNotSupported);
}
PVMFStatus PVMFOMXEncNode::getParametersSync(PvmiMIOSession aSession, PvmiKeyType aIdentifier, PvmiKvp*& aParameters, int& aNumParamElements, PvmiCapabilityContext aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::getParametersSync()", iNodeTypeId));
OSCL_UNUSED_ARG(aSession);
return DoCapConfigGetParametersSync(aIdentifier, aParameters, aNumParamElements, aContext);
}
PVMFStatus PVMFOMXEncNode::releaseParameters(PvmiMIOSession aSession, PvmiKvp* aParameters, int aNumElements)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::releaseParameters()", iNodeTypeId));
OSCL_UNUSED_ARG(aSession);
return DoCapConfigReleaseParameters(aParameters, aNumElements);
}
void PVMFOMXEncNode::createContext(PvmiMIOSession aSession, PvmiCapabilityContext& aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::createContext()", iNodeTypeId));
OSCL_UNUSED_ARG(aSession);
OSCL_UNUSED_ARG(aContext);
// This method is not supported so leave
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::createContext() is not supported!", iNodeTypeId));
OSCL_LEAVE(PVMFErrNotSupported);
}
void PVMFOMXEncNode::setContextParameters(PvmiMIOSession aSession, PvmiCapabilityContext& aContext, PvmiKvp* aParameters, int aNumParamElements)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::setContextParameters()", iNodeTypeId));
OSCL_UNUSED_ARG(aSession);
OSCL_UNUSED_ARG(aContext);
OSCL_UNUSED_ARG(aParameters);
OSCL_UNUSED_ARG(aNumParamElements);
// This method is not supported so leave
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::setContextParameters() is not supported!", iNodeTypeId));
OSCL_LEAVE(PVMFErrNotSupported);
}
void PVMFOMXEncNode::DeleteContext(PvmiMIOSession aSession, PvmiCapabilityContext& aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::DeleteContext()", iNodeTypeId));
OSCL_UNUSED_ARG(aSession);
OSCL_UNUSED_ARG(aContext);
// This method is not supported so leave
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::DeleteContext() is not supported!", iNodeTypeId));
OSCL_LEAVE(PVMFErrNotSupported);
}
void PVMFOMXEncNode::setParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters, int aNumElements, PvmiKvp* &aRetKVP)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::setParametersSync()", iNodeTypeId));
OSCL_UNUSED_ARG(aSession);
// Complete the request synchronously
DoCapConfigSetParameters(aParameters, aNumElements, aRetKVP);
}
PVMFCommandId PVMFOMXEncNode::setParametersAsync(PvmiMIOSession aSession, PvmiKvp* aParameters, int aNumElements, PvmiKvp*& aRetKVP, OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::setParametersAsync()", iNodeTypeId));
OSCL_UNUSED_ARG(aSession);
OSCL_UNUSED_ARG(aParameters);
OSCL_UNUSED_ARG(aNumElements);
OSCL_UNUSED_ARG(aRetKVP);
OSCL_UNUSED_ARG(aContext);
// This method is not supported so leave
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::setParametersAsync() is not supported!", iNodeTypeId));
OSCL_LEAVE(PVMFErrNotSupported);
return 0;
}
uint32 PVMFOMXEncNode::getCapabilityMetric(PvmiMIOSession aSession)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::getCapabilityMetric()", iNodeTypeId));
OSCL_UNUSED_ARG(aSession);
// Not supported so return 0
return 0;
}
PVMFStatus PVMFOMXEncNode::verifyParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters, int aNumElements)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::verifyParametersSync()", iNodeTypeId));
OSCL_UNUSED_ARG(aSession);
return DoCapConfigVerifyParameters(aParameters, aNumElements);
}
/////////////////////////////////////////////////////////////////////////////
uint32 PVMFOMXEncNode::GetNumMetadataValues(PVMFMetadataList& aKeyList)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::GetNumMetadataValues() called", iNodeTypeId));
uint32 numkeys = aKeyList.size();
if (numkeys <= 0)
{
// Don't do anything
return 0;
}
// Count the number of value entries for the provided key list
uint32 numvalentries = 0;
PVMF_MPEGVideoProfileType aProfile;
PVMF_MPEGVideoLevelType aLevel;
for (uint32 lcv = 0; lcv < numkeys; lcv++)
{
if ((oscl_strcmp(aKeyList[lcv].get_cstr(), PVOMXENCMETADATA_CODECINFO_VIDEO_WIDTH_KEY) == 0) &&
iYUVWidth > 0)
{
// Video width
++numvalentries;
}
else if ((oscl_strcmp(aKeyList[lcv].get_cstr(), PVOMXENCMETADATA_CODECINFO_VIDEO_HEIGHT_KEY) == 0) &&
iYUVHeight > 0)
{
// Video height
++numvalentries;
}
else if ((oscl_strcmp(aKeyList[lcv].get_cstr(), PVOMXENCMETADATA_CODECINFO_VIDEO_PROFILE_KEY) == 0) &&
(GetProfileAndLevel(aProfile, aLevel) == PVMFSuccess))
{
// Video profile
++numvalentries;
}
else if ((oscl_strcmp(aKeyList[lcv].get_cstr(), PVOMXENCMETADATA_CODECINFO_VIDEO_LEVEL_KEY) == 0) &&
(GetProfileAndLevel(aProfile, aLevel) == PVMFSuccess))
{
// Video level
++numvalentries;
}
else if ((oscl_strcmp(aKeyList[lcv].get_cstr(), PVOMXENCMETADATA_CODECINFO_VIDEO_AVGBITRATE_KEY) == 0) &&
(iAvgBitrateValue > 0))
{
// Video average bitrate
if (iAvgBitrateValue > 0)
++numvalentries;
}
else if ((oscl_strcmp(aKeyList[lcv].get_cstr(), PVOMXENCMETADATA_CODECINFO_VIDEO_FORMAT_KEY) == 0) &&
(((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_WMV || ((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_M4V || ((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H2631998 || ((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H2632000 || ((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H264_VIDEO || ((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H264_VIDEO_MP4 || ((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H264_VIDEO_RAW))
{
// Format
++numvalentries;
}
}
return numvalentries;
}
/////////////////////////////////////////////////////////////////////////////
PVMFCommandId PVMFOMXEncNode::GetNodeMetadataKeys(PVMFSessionId aSessionId, PVMFMetadataList& aKeyList, uint32 starting_index, int32 max_entries, char* query_key, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNodeCommand::GetNodeMetadataKeys() called", iNodeTypeId));
PVMFOMXEncNodeCommand cmd;
cmd.PVMFOMXEncNodeCommand::Construct(aSessionId, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_GETNODEMETADATAKEY, &aKeyList, starting_index, max_entries, query_key, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
PVMFCommandId PVMFOMXEncNode::GetNodeMetadataValues(PVMFSessionId aSessionId, PVMFMetadataList& aKeyList, Oscl_Vector<PvmiKvp, OsclMemAllocator>& aValueList, uint32 starting_index, int32 max_entries, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNodeCommand::GetNodeMetadataValue() called", iNodeTypeId));
PVMFOMXEncNodeCommand cmd;
cmd.PVMFOMXEncNodeCommand::Construct(aSessionId, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_GETNODEMETADATAVALUE, &aKeyList, &aValueList, starting_index, max_entries, aContext);
return QueueCommandL(cmd);
}
// From PVMFMetadataExtensionInterface
/////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFOMXEncNode::ReleaseNodeMetadataKeys(PVMFMetadataList& , uint32 , uint32)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::ReleaseNodeMetadataKeys() called", iNodeTypeId));
//nothing needed-- there's no dynamic allocation in this node's key list
return PVMFSuccess;
}
// From PVMFMetadataExtensionInterface
/////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFOMXEncNode::ReleaseNodeMetadataValues(Oscl_Vector<PvmiKvp, OsclMemAllocator>& aValueList, uint32 start, uint32 end)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::ReleaseNodeMetadataValues() called", iNodeTypeId));
if (aValueList.size() == 0 || start > end)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::ReleaseNodeMetadataValues() Invalid start/end index", iNodeTypeId));
return PVMFErrArgument;
}
if (end >= aValueList.size())
{
end = aValueList.size() - 1;
}
for (uint32 i = start; i <= end; i++)
{
if (aValueList[i].key != NULL)
{
switch (GetValTypeFromKeyString(aValueList[i].key))
{
case PVMI_KVPVALTYPE_CHARPTR:
if (aValueList[i].value.pChar_value != NULL)
{
OSCL_ARRAY_DELETE(aValueList[i].value.pChar_value);
aValueList[i].value.pChar_value = NULL;
}
break;
case PVMI_KVPVALTYPE_UINT32:
case PVMI_KVPVALTYPE_UINT8:
// No memory to free for these valtypes
break;
default:
// Should not get a value that wasn't created from here
break;
}
OSCL_ARRAY_DELETE(aValueList[i].key);
aValueList[i].key = NULL;
}
}
return PVMFSuccess;
}
PVMFStatus PVMFOMXEncNode::GetProfileAndLevel(PVMF_MPEGVideoProfileType& aProfile, PVMF_MPEGVideoLevelType& aLevel)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::GetProfileAndLevel() In", iNodeTypeId));
if (NULL == iOMXEncoder)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::GetProfileAndLevel() iEncoder is Null", iNodeTypeId));
aProfile = PV_MPEG_VIDEO_RESERVED_PROFILE;
aLevel = PV_MPEG_VIDEO_LEVEL_UNKNOWN;
return PVMFFailure;
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::GetProfileAndLevel() iEncoder is Null", iNodeTypeId));
aProfile = PV_MPEG_VIDEO_RESERVED_PROFILE;
aLevel = PV_MPEG_VIDEO_LEVEL_UNKNOWN;
// DV: FOR NOW, JUST RETURN FAILURE, WE DON'T SUPPORT THIS FEATURE YET
return PVMFFailure;
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXEncNode::LogDiagnostics()
{
if (iDiagnosticsLogged == false)
{
iDiagnosticsLogged = true;
PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, iDiagnosticsLogger, PVLOGMSG_INFO, (0, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"));
PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, iDiagnosticsLogger, PVLOGMSG_INFO, (0, "PVMFOMXEncNode-%s - Number of Media Msgs Sent = %d", iNodeTypeId, iSeqNum));
PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, iDiagnosticsLogger, PVLOGMSG_INFO, (0, "PVMFOMXEncNode-%s - TS of last encoded msg = %d", iNodeTypeId, ConvertOMXTicksIntoTimestamp(iTimeStampOut)));
}
}
//////////////////////////////////
/////EXTENSION INTERFACE
////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMFOMXEncNode::SetNumLayers(uint32 aNumLayers)
{
switch (iInterfaceState)
{
case EPVMFNodeStarted:
case EPVMFNodePaused:
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetNumLayers: Error iInterfaceState=%d", iNodeTypeId, iInterfaceState));
return false;
default:
break;
}
if (aNumLayers > MAX_LAYER)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetNumLayers: Error Max num layers is %d", iNodeTypeId, MAX_LAYER));
return false;
}
iVideoEncodeParam.iNumLayer = aNumLayers;
return true;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMFOMXEncNode::SetOutputBitRate(uint32 aLayer, uint32 aBitRate)
{
switch (iInterfaceState)
{
case EPVMFNodeStarted:
case EPVMFNodePaused:
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::SetOutputBitRate: Error iInterfaceState=%d", iInterfaceState));
return false;
default:
break;
}
if ((int32)aLayer >= iVideoEncodeParam.iNumLayer)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetOutputBitRate: Error Invalid layer number", iNodeTypeId));
return false;
}
iVideoEncodeParam.iBitRate[aLayer] = aBitRate;
return true;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMFOMXEncNode::SetOutputFrameSize(uint32 aLayer, uint32 aWidth, uint32 aHeight)
{
switch (iInterfaceState)
{
case EPVMFNodeStarted:
case EPVMFNodePaused:
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetOutputFrameSize: Error iInterfaceState=%d", iNodeTypeId, iInterfaceState));
return false;
default:
break;
}
if ((int32)aLayer >= iVideoEncodeParam.iNumLayer)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetOutputFrameSize: Error Invalid layer number", iNodeTypeId));
return false;
}
iVideoEncodeParam.iFrameWidth[aLayer] = aWidth;
iVideoEncodeParam.iFrameHeight[aLayer] = aHeight;
return true;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMFOMXEncNode::SetOutputFrameRate(uint32 aLayer, OsclFloat aFrameRate)
{
switch (iInterfaceState)
{
case EPVMFNodeStarted:
case EPVMFNodePaused:
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetOutputFrameRate: Error iInterfaceState=%d", iInterfaceState));
return false;
default:
break;
}
if ((int32)aLayer >= iVideoEncodeParam.iNumLayer)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetOutputFrameRate: Error Invalid layer number", iNodeTypeId));
return false;
}
iVideoEncodeParam.iFrameRate[aLayer] = OSCL_STATIC_CAST(float, aFrameRate);
return true;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMFOMXEncNode::SetSegmentTargetSize(uint32 aLayer, uint32 aSizeBytes)
{
OSCL_UNUSED_ARG(aLayer);
switch (iInterfaceState)
{
case EPVMFNodeStarted:
case EPVMFNodePaused:
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetSegmentTargetSize: Error iInterfaceState=%d", iNodeTypeId, iInterfaceState));
return false;
default:
break;
}
iVideoEncodeParam.iPacketSize = aSizeBytes;
return true;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMFOMXEncNode::SetRateControlType(uint32 aLayer, PVMFVENRateControlType aRateControl)
{
OSCL_UNUSED_ARG(aLayer);
switch (iInterfaceState)
{
case EPVMFNodeStarted:
case EPVMFNodePaused:
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetRateControlType: Error iInterfaceState=%d", iNodeTypeId, iInterfaceState));
return false;
default:
break;
}
iVideoEncodeParam.iRateControlType = aRateControl;
return true;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMFOMXEncNode::SetDataPartitioning(bool aDataPartitioning)
{
switch (iInterfaceState)
{
case EPVMFNodeStarted:
case EPVMFNodePaused:
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetDataPartitioning: Error iInterfaceState=%d", iNodeTypeId, iInterfaceState));
return false;
default:
break;
}
iVideoEncodeParam.iDataPartitioning = aDataPartitioning;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "PVMFOMXEncNode-%s::SetDataPartitioning Called", iNodeTypeId));
return true;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMFOMXEncNode::SetIFrameInterval(uint32 aIFrameInterval)
{
switch (iInterfaceState)
{
case EPVMFNodeStarted:
case EPVMFNodePaused:
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetIFrameInterval: Error iInterfaceState=%d", iNodeTypeId, iInterfaceState));
return false;
default:
break;
}
iVideoEncodeParam.iIFrameInterval = aIFrameInterval;
return true;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMFOMXEncNode::SetSceneDetection(bool aSCD)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetSceneDetection to %d", iNodeTypeId, aSCD));
switch (iInterfaceState)
{
case EPVMFNodeStarted:
case EPVMFNodePaused:
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncEncNode-%s::SetIFrameInterval: Error iInterfaceState=%d", iNodeTypeId, iInterfaceState));
return false;
default:
break;
}
iVideoEncodeParam.iSceneDetection = aSCD;
return true;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMFOMXEncNode::SetRVLC(bool aRVLC)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetRVLC", iNodeTypeId));
switch (iInterfaceState)
{
case EPVMFNodeStarted:
case EPVMFNodePaused:
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncEncNode-%s::SetRVLC: Error iInterfaceState=%d", iNodeTypeId, iInterfaceState));
return false;
default:
break;
}
iVideoEncodeParam.iRVLCEnable = aRVLC;
return true;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMFOMXEncNode::GetVolHeader(OsclRefCounterMemFrag& aVolHeader)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::GetVolHeader", iNodeTypeId));
#ifdef _TEST_AE_ERROR_HANDLING
if (iErrorConfigHeader)
{
iInterfaceState = EPVMFNodeError;
}
#endif
switch (iInterfaceState)
{
case EPVMFNodeInitialized:
case EPVMFNodePrepared:
case EPVMFNodeStarted:
case EPVMFNodePaused:
break;
default:
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::GetVolHeader: Error - Wrong state", iNodeTypeId));
return false;
}
if (iOutFormat != PVMF_MIME_M4V)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::GetVolHeader: Error - VOL header only for M4V encode", iNodeTypeId));
return false;
}
uint8 *ptr = (uint8 *) iVolHeader.getMemFragPtr();
//If data partioning mode
if (iVideoEncodeParam.iDataPartitioning == true)
{
ptr[iVolHeader.getMemFragSize() - 1] = 0x8F;
}
//else combined mode
else
{
ptr[iVolHeader.getMemFragSize() - 1] = 0x1F;
}
aVolHeader = iVolHeader;
return true;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMFOMXEncNode::RequestIFrame()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::RequestIFrame", iNodeTypeId));
switch (iInterfaceState)
{
case EPVMFNodeStarted:
case EPVMFNodePaused:
break;
default:
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::RequestIFrame: Error - Wrong state", iNodeTypeId));
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMFOMXEncNode::SetCodec(PVMFFormatType aCodec)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetCodec %s", iNodeTypeId, aCodec.getMIMEStrPtr()));
if (SetCodecType(aCodec) == PVMFSuccess)
{
return true;
}
else
{
return false;
}
}
PVMFStatus PVMFOMXEncNode::SetCodecType(PVMFFormatType aCodec)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetCodecType: aCodec=%s", iNodeTypeId, aCodec.getMIMEStrPtr()));
switch (iInterfaceState)
{
case EPVMFNodeStarted:
case EPVMFNodePaused:
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetCodecType: Error iInterfaceState=%d", iNodeTypeId, iInterfaceState));
return PVMFErrInvalidState;
default:
break;
}
if (aCodec == PVMF_MIME_H2631998)
{
iOutFormat = PVMF_MIME_H2631998;
}
else if (aCodec == PVMF_MIME_H2632000)
{
iOutFormat = PVMF_MIME_H2632000;
}
else if (aCodec == PVMF_MIME_M4V)
{
iOutFormat = PVMF_MIME_M4V;
}
else if (aCodec == PVMF_MIME_H264_VIDEO_RAW ||
aCodec == PVMF_MIME_H264_VIDEO_MP4)
{
iOutFormat = aCodec;
}
else if (aCodec == PVMF_MIME_AMR_IETF ||
aCodec == PVMF_MIME_AMR_IF2 ||
aCodec == PVMF_MIME_AMRWB_IETF)
{
iOutFormat = aCodec;
}
else if (aCodec == PVMF_MIME_ADTS ||
aCodec == PVMF_MIME_ADIF ||
aCodec == PVMF_MIME_MPEG4_AUDIO)
{
iOutFormat = aCodec;
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetCodecType: ERROR Unsupported format aCodec=%s", iNodeTypeId, aCodec.getMIMEStrPtr()));
return PVMFErrNotSupported;
}
return PVMFSuccess;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMFOMXEncNode::SetFSIParam(uint8* aFSIBuff, int aFSIBuffLength)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetFSIParam: Error- NOT IMPLEMENTED", iNodeTypeId));
OSCL_UNUSED_ARG(aFSIBuff);
OSCL_UNUSED_ARG(aFSIBuffLength);
return true;
}
// The input format methods are called from the port
////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFOMXEncNode::SetInputFormat(PVMFFormatType aFormat)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetInputFormat: aFormat=%s", iNodeTypeId, aFormat.getMIMEStrPtr()));
switch (iInterfaceState)
{
case EPVMFNodeStarted:
case EPVMFNodePaused:
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetInputFormat: Error - iInterfaceState=%d", iNodeTypeId, iInterfaceState));
return PVMFErrInvalidState;
default:
break;
}
iInFormat = aFormat;
return PVMFSuccess;
}
////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFOMXEncNode::SetInputFrameSize(uint32 aWidth, uint32 aHeight, uint8 aFrmOrient)
{
switch (iInterfaceState)
{
case EPVMFNodeStarted:
case EPVMFNodePaused:
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetInputFrameSize: Error iInterfaceState=%d", iNodeTypeId, iInterfaceState));
return false;
default:
break;
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetInputFrameSize: aWidth=%d, aHeight=%d, aFrmOrient=%d", iNodeTypeId, aWidth, aHeight, aFrmOrient));
iVideoInputFormat.iFrameWidth = aWidth;
iVideoInputFormat.iFrameHeight = aHeight;
iVideoInputFormat.iFrameOrientation = aFrmOrient;
return true;
}
////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFOMXEncNode::SetInputFrameRate(OsclFloat aFrameRate)
{
switch (iInterfaceState)
{
case EPVMFNodeStarted:
case EPVMFNodePaused:
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetInputFrameRate: Error iInterfaceState=%d", iNodeTypeId, iInterfaceState));
return false;
default:
break;
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetInputFrameRate: aFrameRate=%d", iNodeTypeId, aFrameRate));
iVideoInputFormat.iFrameRate = OSCL_STATIC_CAST(float, aFrameRate);
iVideoEncodeParam.iNoFrameSkip = iVideoEncodeParam.iNoCurrentSkip = false;
return true;
}
////////////////////////////////////////////////////////////////////////////
PVMFFormatType PVMFOMXEncNode::GetCodecType()
{
return iOutFormat;
}
////////////////////////////////////////////////////////////////////////////
// DV: Note - for video - there is an uint32 arg
uint32 PVMFOMXEncNode::GetOutputBitRate(uint32 aLayer)
{
if ((int32)aLayer >= iVideoEncodeParam.iNumLayer)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::GetOutputBitRate: Error - Invalid layer number", iNodeTypeId));
return 0;
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::GetOutputBitRate: =%d", iNodeTypeId, iVideoEncodeParam.iBitRate[aLayer]));
return iVideoEncodeParam.iBitRate[aLayer];
}
////////////////////////////////////////////////////////////////////////////
OsclFloat PVMFOMXEncNode::GetOutputFrameRate(uint32 aLayer)
{
if ((int32)aLayer >= iVideoEncodeParam.iNumLayer)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::GetOutputFrameRate: Error Invalid layer number", iNodeTypeId));
return 0;
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::GetOutputFrameRate: =%f", iNodeTypeId, (OsclFloat) iVideoEncodeParam.iFrameRate[aLayer]));
return (OsclFloat)iVideoEncodeParam.iFrameRate[aLayer];
}
////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFOMXEncNode::GetOutputFrameSize(uint32 aLayer, uint32& aWidth, uint32& aHeight)
{
if ((int32)aLayer >= iVideoEncodeParam.iNumLayer)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::GetOutputFrameSize: Error Invalid layer number", iNodeTypeId));
return PVMFFailure;
}
aWidth = iVideoEncodeParam.iFrameWidth[aLayer];
aHeight = iVideoEncodeParam.iFrameHeight[aLayer];
return PVMFSuccess;
}
////////////////////////////////////////////////////////////////////////////
uint32 PVMFOMXEncNode::GetIFrameInterval()
{
return iVideoEncodeParam.iIFrameInterval;
}
/////////////////////////////////////////////////////////////////////////////
uint32 PVMFOMXEncNode::GetOutputSamplingRate()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::GetOutputSamplingRate: =%d", iNodeTypeId, iAudioEncodeParam.iOutputSamplingRate));
return (uint32) iAudioEncodeParam.iOutputSamplingRate;
}
/////////////////////////////////////////////////////////////////////////////
uint32 PVMFOMXEncNode::GetOutputNumChannels()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::GetOutputNumChannels: =%d", iNodeTypeId, iAudioEncodeParam.iOutputNumChannels));
return (uint32) iAudioEncodeParam.iOutputNumChannels;
}
/////////////////////////AMRENCInterfaceExtension //////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMFOMXEncNode::SetOutputBitRate(PVMF_GSMAMR_Rate aBitRate)
{
// this particular API is used only for AMR (NB or WB)
// do some error checking - make sure that NB (i.e. WB) bitrates correspond to NB (i.e. WB) codec
if ((iOutFormat == PVMF_MIME_AMR_IF2) ||
(iOutFormat == PVMF_MIME_AMR_IETF)
)
{
switch (aBitRate)
{
case GSM_AMR_4_75:
case GSM_AMR_5_15:
case GSM_AMR_5_90:
case GSM_AMR_6_70:
case GSM_AMR_7_40:
case GSM_AMR_7_95:
case GSM_AMR_10_2:
case GSM_AMR_12_2:
iAudioEncodeParam.iAMRBitrate = aBitRate;
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetOutputBitRate() OK - %d", iNodeTypeId, aBitRate));
return PVMFSuccess;
case GSM_AMR_6_60: // AMR WB bitrates start here
case GSM_AMR_8_85:
case GSM_AMR_12_65:
case GSM_AMR_14_25:
case GSM_AMR_15_85:
case GSM_AMR_18_25:
case GSM_AMR_19_85:
case GSM_AMR_23_05:
case GSM_AMR_23_85:
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetOutputBitRate() failed - %d", iNodeTypeId, aBitRate));
return PVMFFailure;
default:
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetOutputBitRate() failed - %d", iNodeTypeId, aBitRate));
return PVMFFailure;
}
}
if (iOutFormat == PVMF_MIME_AMRWB_IETF)
{
switch (aBitRate)
{
case GSM_AMR_4_75:
case GSM_AMR_5_15:
case GSM_AMR_5_90:
case GSM_AMR_6_70:
case GSM_AMR_7_40:
case GSM_AMR_7_95:
case GSM_AMR_10_2:
case GSM_AMR_12_2:
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetOutputBitRate() failed - %d", iNodeTypeId, aBitRate));
return PVMFFailure;
case GSM_AMR_6_60: // AMR WB bitrates start here
case GSM_AMR_8_85:
case GSM_AMR_12_65:
case GSM_AMR_14_25:
case GSM_AMR_15_85:
case GSM_AMR_18_25:
case GSM_AMR_19_85:
case GSM_AMR_23_05:
case GSM_AMR_23_85:
iAudioEncodeParam.iAMRBitrate = aBitRate;
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetOutputBitRate() OK - %d", iNodeTypeId, aBitRate));
return PVMFSuccess;
default:
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetOutputBitRate() failed - %d", iNodeTypeId, aBitRate));
return PVMFFailure;
}
}
return PVMFSuccess;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMFOMXEncNode::SetMaxNumOutputFramesPerBuffer(uint32 aNumOutputFrames)
{
iAudioEncodeParam.iMaxNumOutputFramesPerBuffer = aNumOutputFrames;
return PVMFSuccess;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMFOMXEncNode::SetOutputBitRate(uint32 aBitRate)
{
// this API is used for Non-AMR codecs
iAudioEncodeParam.iOutputBitrate = aBitRate;
return PVMFSuccess;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMFOMXEncNode::SetOutputNumChannel(uint32 aNumChannels)
{
iAudioEncodeParam.iOutputNumChannels = aNumChannels;
return PVMFSuccess;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMFOMXEncNode::SetOutputSamplingRate(uint32 aSamplingRate)
{
iAudioEncodeParam.iOutputSamplingRate = aSamplingRate;
return PVMFSuccess;
}
////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFOMXEncNode::SetInputSamplingRate(uint32 aSamplingRate)
{
// do some error checking - make sure the input sampling rate is 8khz (i.e. 16khz) for AMRNB (i.e. WB)
if (((iOutFormat == PVMF_MIME_AMR_IF2) ||
(iOutFormat == PVMF_MIME_AMR_IETF)) &&
(aSamplingRate != 8000)
)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetInputBitsSamplingRate() failed - %d", iNodeTypeId, aSamplingRate));
return PVMFFailure;
}
if ((iOutFormat == PVMF_MIME_AMRWB_IETF) && (aSamplingRate != 16000))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetInputBitsSamplingRate() failed - %d", iNodeTypeId, aSamplingRate));
return PVMFFailure;
}
iAudioInputFormat.iInputSamplingRate = aSamplingRate;
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetInputBitsSamplingRate() OK setting OutputSamplingRate as well - %d", iNodeTypeId, aSamplingRate));
// set output as well
iAudioEncodeParam.iOutputSamplingRate = aSamplingRate;
return PVMFSuccess;
}
////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFOMXEncNode::SetInputBitsPerSample(uint32 aBitsPerSample)
{
if (aBitsPerSample != 16)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetInputBitsPerSample() failed - %d", iNodeTypeId, aBitsPerSample));
return PVMFErrNotSupported;
}
iAudioInputFormat.iInputBitsPerSample = aBitsPerSample;
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetInputBitsPerSample() OK - %d", iNodeTypeId, aBitsPerSample));
return PVMFSuccess;
}
////////////////////////////////////////////////////////////////////////////
PVMFStatus PVMFOMXEncNode::SetInputNumChannels(uint32 aNumChannels)
{
// do some error checking - make sure the number of INPUT channels is 1 for AMR (NB or WB)
if (((iOutFormat == PVMF_MIME_AMR_IF2) ||
(iOutFormat == PVMF_MIME_AMR_IETF) ||
(iOutFormat == PVMF_MIME_AMRWB_IETF)) &&
(aNumChannels > 1)
)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::SetInputNumChannels() failed - %d", iNodeTypeId, aNumChannels));
return PVMFFailure;
}
iAudioInputFormat.iInputNumChannels = aNumChannels;
//set output as well
iAudioEncodeParam.iOutputNumChannels = aNumChannels;
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFOMXEncNode-%s::SetInputNumChannels() OK - %d", iNodeTypeId, aNumChannels));
return PVMFSuccess;
}
////////////////////////////////////////////////////////////////////////////
uint32 PVMFOMXEncNode::GetOutputBitRate()
{
if ((iOutFormat == PVMF_MIME_AMR_IF2) ||
(iOutFormat == PVMF_MIME_AMR_IETF) ||
(iOutFormat == PVMF_MIME_AMRWB_IETF)
)
{
switch (iAudioEncodeParam.iAMRBitrate)
{
case GSM_AMR_4_75:
return 4750;
case GSM_AMR_5_15:
return 5150;
case GSM_AMR_5_90:
return 5900;
case GSM_AMR_6_70:
return 6700;
case GSM_AMR_7_40:
return 7400;
case GSM_AMR_7_95:
return 7950;
case GSM_AMR_10_2:
return 10200;
case GSM_AMR_12_2:
return 12200;
case GSM_AMR_6_60: // AMR WB bitrates start here
return 6600;
case GSM_AMR_8_85:
return 8850;
case GSM_AMR_12_65:
return 12650;
case GSM_AMR_14_25:
return 14250;
case GSM_AMR_15_85:
return 15850;
case GSM_AMR_18_25:
return 18250;
case GSM_AMR_19_85:
return 19850;
case GSM_AMR_23_05:
return 23050;
case GSM_AMR_23_85:
return 23850;
default:
return 0;
}
}
else
{
return iAudioEncodeParam.iOutputBitrate;
}
}
///////////////////////// FROM CAP CONFIG IN VIDEO ENC NODE ////////////////////
PVMFStatus PVMFOMXEncNode::GetConfigParameter(PvmiKvp*& aParameters, int& aNumParamElements, int32 aIndex, PvmiKvpAttr aReqattr)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::GetConfigParameter() In", iNodeTypeId));
aNumParamElements = 0;
// Allocate memory for the KVP
aParameters = (PvmiKvp*)oscl_malloc(sizeof(PvmiKvp));
if (NULL == aParameters)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::GetConfigParameter() Memory allocation for KVP failed", iNodeTypeId));
return PVMFErrNoMemory;
}
oscl_memset(aParameters, 0, sizeof(PvmiKvp));
// Allocate memory for the key string in KVP
PvmiKeyType memblock = (PvmiKeyType)oscl_malloc(PVOMXENCNODECONFIG_KEYSTRING_SIZE * sizeof(char));
if (NULL == memblock)
{
oscl_free(aParameters);
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::GetConfigParameter() Memory allocation for key string failed", iNodeTypeId));
return PVMFErrNoMemory;
}
oscl_strset(memblock, 0, PVOMXENCNODECONFIG_KEYSTRING_SIZE * sizeof(char));
// Assign the key string buffer to KVP
aParameters[0].key = memblock;
// Copy the key string
if (iInFormat == PVMF_MIME_PCM16)
{
// Copy the key string
oscl_strncat(aParameters[0].key, _STRLIT_CHAR("x-pvmf/encoder/audio/"), 21);
oscl_strncat(aParameters[0].key, PVOMXEncNodeConfigBaseKeys[aIndex].iString, oscl_strlen(PVOMXEncNodeConfigBaseKeys[aIndex].iString));
oscl_strncat(aParameters[0].key, _STRLIT_CHAR(";type=value;valtype="), 20);
}
else
{
oscl_strncat(aParameters[0].key, _STRLIT_CHAR("x-pvmf/encoder/video/"), 21);
oscl_strncat(aParameters[0].key, PVOMXEncNodeConfigBaseKeys[aIndex].iString, oscl_strlen(PVOMXEncNodeConfigBaseKeys[aIndex].iString));
oscl_strncat(aParameters[0].key, _STRLIT_CHAR(";type=value;valtype="), 20);
}
switch (PVOMXEncNodeConfigBaseKeys[aIndex].iValueType)
{
case PVMI_KVPVALTYPE_BITARRAY32:
oscl_strncat(aParameters[0].key, _STRLIT_CHAR(PVMI_KVPVALTYPE_BITARRAY32_STRING), oscl_strlen(PVMI_KVPVALTYPE_BITARRAY32_STRING));
break;
case PVMI_KVPVALTYPE_KSV:
oscl_strncat(aParameters[0].key, _STRLIT_CHAR(PVMI_KVPVALTYPE_KSV_STRING), oscl_strlen(PVMI_KVPVALTYPE_KSV_STRING));
break;
case PVMI_KVPVALTYPE_BOOL:
oscl_strncat(aParameters[0].key, _STRLIT_CHAR(PVMI_KVPVALTYPE_BOOL_STRING), oscl_strlen(PVMI_KVPVALTYPE_BOOL_STRING));
break;
case PVMI_KVPVALTYPE_INT32:
if (PVMI_KVPATTR_CUR == aReqattr)
{
oscl_strncat(aParameters[0].key, _STRLIT_CHAR(PVMI_KVPVALTYPE_INT32_STRING), oscl_strlen(PVMI_KVPVALTYPE_RANGE_UINT32_STRING));
}
break;
case PVMI_KVPVALTYPE_UINT32:
default:
if (PVMI_KVPATTR_CAP == aReqattr)
{
oscl_strncat(aParameters[0].key, _STRLIT_CHAR(PVMI_KVPVALTYPE_RANGE_UINT32_STRING), oscl_strlen(PVMI_KVPVALTYPE_RANGE_UINT32_STRING));
}
else
{
oscl_strncat(aParameters[0].key, _STRLIT_CHAR(PVMI_KVPVALTYPE_UINT32_STRING), oscl_strlen(PVMI_KVPVALTYPE_UINT32_STRING));
}
break;
}
aParameters[0].key[PVOMXENCNODECONFIG_KEYSTRING_SIZE-1] = 0;
// Copy the requested info
switch (aIndex)
{
case SAMPLING_RATE: // "sampling_rate"
if (PVMI_KVPATTR_CUR == aReqattr)
{
// get the parameter here
aParameters[0].value.uint32_value = iAudioInputFormat.iInputSamplingRate;
}
else if (PVMI_KVPATTR_DEF == aReqattr)
{
// Return default
aParameters[0].value.uint32_value = PVMF_AMRENC_DEFAULT_SAMPLING_RATE;
}
else
{
// Return capability
}
break;
case CHANNELS: // "channels"
if (PVMI_KVPATTR_CUR == aReqattr)
{
// get the par
aParameters[0].value.uint32_value = iAudioInputFormat.iInputNumChannels;
}
else if (PVMI_KVPATTR_DEF == aReqattr)
{
// Return default
aParameters[0].value.uint32_value = PVMF_AMRENC_DEFAULT_NUM_CHANNELS;
}
else
{
// Return capability
}
break;
case ENCODING_MODE: // "encoding_mode"
if (PVMI_KVPATTR_CUR == aReqattr)
{
// Return current value
aParameters[0].value.uint32_value = iVideoEncodeParam.iEncMode;
}
else if (PVMI_KVPATTR_DEF == aReqattr)
{
// Return default
aParameters[0].value.uint32_value = EI_ENCMODE_RECORDER;//default setting
}
else
{
// Return capability
}
break;
#ifdef _TEST_AE_ERROR_HANDLING
case ERROR_START_INIT://error_start_init
if (PVMI_KVPATTR_CUR == aReqattr)
{
// Return current value
aParameters[0].value.bool_value = iErrorHandlingInit;
}
else if (PVMI_KVPATTR_DEF == aReqattr)
{
// Return default
aParameters[0].value.bool_value = true;
}
else
{
// Return capability
}
break;
case ERROR_ENCODE://error_encode
if (PVMI_KVPATTR_CUR == aReqattr)
{
// Return current value
aParameters[0].value.uint32_value = iErrorHandlingEncodeCount;
}
else if (PVMI_KVPATTR_DEF == aReqattr)
{
// Return default
aParameters[0].value.uint32_value = 1;
}
else
{
// Return capability
}
break;
#endif
default:
// Invalid index
oscl_free(aParameters[0].key);
oscl_free(aParameters);
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::GetConfigParameter() Invalid index to video enc node parameter", iNodeTypeId));
return PVMFErrNotSupported;
}
aNumParamElements = 1;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::GetConfigParameter() Out", iNodeTypeId));
return PVMFSuccess;
}
PVMFStatus PVMFOMXEncNode::VerifyAndSetConfigParameter(PvmiKvp& aParameter, bool aSetParam)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::VerifyAndSetConfigParameter() In", iNodeTypeId));
// Determine the valtype
PvmiKvpValueType keyvaltype = GetValTypeFromKeyString(aParameter.key);
if (PVMI_KVPVALTYPE_UNKNOWN == keyvaltype)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::VerifyAndSetConfigParameter() Valtype in key string unknown", iNodeTypeId));
return PVMFErrNotSupported;
}
// Retrieve the fourth component from the key string
char* compstr = NULL;
pv_mime_string_extract_type(3, aParameter.key, compstr);
int32 enccomp4ind;
for (enccomp4ind = 0; enccomp4ind < PVOMXENCNODECONFIG_BASE_NUMKEYS; ++enccomp4ind)
{
// Go through each component string at 4th level
if (pv_mime_strcmp(compstr, (char*)(PVOMXEncNodeConfigBaseKeys[enccomp4ind].iString)) >= 0)
{
// Break out of the for loop
break;
}
}
if (PVOMXENCNODECONFIG_BASE_NUMKEYS <= enccomp4ind)
{
// Match couldn't be found or non-leaf node specified
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::VerifyAndSetConfigParameter() Unsupported key or non-leaf node", iNodeTypeId));
return PVMFErrNotSupported;
}
// Verify the valtype
if (keyvaltype != PVOMXEncNodeConfigBaseKeys[enccomp4ind].iValueType)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::VerifyAndSetConfigParameter() Valtype does not match for key", iNodeTypeId));
return PVMFErrNotSupported;
}
switch (enccomp4ind)
{
case SAMPLING_RATE: // "sampling_rate"
// Change the parameter
if (aSetParam)
{
// set the parameter here
iAudioInputFormat.iInputSamplingRate = aParameter.value.uint32_value;
iAudioEncodeParam.iOutputSamplingRate = aParameter.value.uint32_value;
}
break;
case CHANNELS: // "channels"
// change the parameter
if (aSetParam)
{
// set the parameter here
iAudioInputFormat.iInputNumChannels = aParameter.value.uint32_value;
iAudioEncodeParam.iOutputNumChannels = aParameter.value.uint32_value;
}
break;
case ENCODING_MODE: // "encoding_mode"
// change the parameter
if (aSetParam)
{
iVideoEncodeParam.iEncMode = (EncEncodingMode)aParameter.value.uint32_value;
}
break;
#ifdef _TEST_AE_ERROR_HANDLING
case ERROR_START_INIT: // "error_start_init"
// change the parameter
if (aSetParam)
{
iErrorHandlingInit = aParameter.value.bool_value;
}
break;
case ERROR_ENCODE: // "error_avcencode"
// change the parameter
if (aSetParam)
{
char* paramstr = NULL;
OSCL_HeapString<OsclMemAllocator> mode1 = "mode=duration";
OSCL_HeapString<OsclMemAllocator> mode2 = "mode=frames";
if (pv_mime_string_parse_param(aParameter.key, mode1.get_str(), paramstr) > 0)
{
iErrorEncodeFlag = 1;
iErrorHandlingEncodeCount = aParameter.value.uint32_value;
}
else if (pv_mime_string_parse_param(aParameter.key, mode2.get_str(), paramstr) > 0)
{
iErrorEncodeFlag = 2;
iErrorHandlingEncodeCount = aParameter.value.uint32_value;
}
}
break;
case ERROR_NODE_CMD: //"error-node-cmd"
if (aSetParam)
{
iErrorNodeCmd = aParameter.value.uint32_value;
}
break;
case ERROR_CONFIG_HEADER:
if (aSetParam)
{
iErrorConfigHeader = aParameter.value.bool_value;
}
break;
case ERROR_DATAPATH_STALL:
if (aSetParam)
{
iErrorDataPathStall = aParameter.value.uint32_value;
}
break;
#endif
default:
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::VerifyAndSetConfigParameter() Invalid index for video enc node parameter", iNodeTypeId));
return PVMFErrNotSupported;
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::VerifyAndSetConfigParameter() Out", iNodeTypeId));
return PVMFSuccess;
}
//void PVMFOMXEncNode::setParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters, int aNumElements, PvmiKvp*& aRetKVP)
void PVMFOMXEncNode::DoCapConfigSetParameters(PvmiKvp* aParameters, int aNumElements, PvmiKvp*& aRetKVP)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::DoCapConfigSetParameters()", iNodeTypeId));
//OSCL_UNUSED_ARG(aSession);
if (NULL == aParameters || aNumElements < 1)
{
if (aParameters)
{
aRetKVP = aParameters;
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::DoCapConfigSetParameters() Passed in parameter invalid", iNodeTypeId));
return;
}
// Go through each parameter
for (int32 paramind = 0; paramind < aNumElements; ++paramind)
{
// Count the number of components and parameters in the key
int compcount = pv_mime_string_compcnt(aParameters[paramind].key);
// Retrieve the first component from the key string
char* compstr = NULL;
pv_mime_string_extract_type(0, aParameters[paramind].key, compstr);
if ((
(pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf/encoder/video")) < 0) &&
(pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf/encoder/audio")) < 0)
) || (compcount < 4))
{
// First 3 components should be "x-pvmf/encoder/video" or "x-pvmf/encoder/audio" and there must
// be at least 4 components
aRetKVP = &aParameters[paramind];
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::DoCapConfigSetParameters() Unsupported key", iNodeTypeId));
return;
}
// check if audio parameters are asked from video enc instance or vice versa
if (((pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf/encoder/video")) > 0) && (iInFormat == PVMF_MIME_PCM16)) ||
((pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf/encoder/audio")) > 0) && (iInFormat != PVMF_MIME_PCM16))
)
{
aRetKVP = &aParameters[paramind];
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::DoCapConfigSetParameters() Unsupported key", iNodeTypeId));
return;
}
if (4 == compcount)
{
// Verify and set the passed-in video enc node setting
PVMFStatus retval = VerifyAndSetConfigParameter(aParameters[paramind], true);
if (PVMFSuccess != retval)
{
aRetKVP = &aParameters[paramind];
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::DoCapConfigSetParameters() Setting parameter %d failed", iNodeTypeId, paramind));
return;
}
}
else
{
// Do not support more than 4 components right now
aRetKVP = &aParameters[paramind];
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::DoCapConfigSetParameters() Unsupported key", iNodeTypeId));
return;
}
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::DoCapConfigSetParameters() Out", iNodeTypeId));
}
//PVMFStatus PVMFOMXEncNode::getParametersSync(PvmiMIOSession aSession, PvmiKeyType aIdentifier, PvmiKvp*& aParameters, int& aNumParamElements, PvmiCapabilityContext aContext)
PVMFStatus PVMFOMXEncNode::DoCapConfigGetParametersSync(PvmiKeyType aIdentifier, PvmiKvp*& aParameters, int& aNumParamElements, PvmiCapabilityContext aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::DoCapConfigGetParametersSync()", iNodeTypeId));
//OSCL_UNUSED_ARG(aSession);
OSCL_UNUSED_ARG(aContext);
// Initialize the output parameters
aNumParamElements = 0;
aParameters = NULL;
// Count the number of components and parameters in the key
int compcount = pv_mime_string_compcnt(aIdentifier);
// Retrieve the first component from the key string
char* compstr = NULL;
pv_mime_string_extract_type(0, aIdentifier, compstr);
if ((
(pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf/encoder/video")) < 0) &&
(pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf/encoder/audio")) < 0)
) || (compcount < 4))
{
// First 3 components should be "x-pvmf/encoder/video" or "x-pvmf/encoder/audio" and there must
// be at least 4 components
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::DoCapConfigGetParametersSync() Invalid key string", iNodeTypeId));
return PVMFErrNotSupported;
}
// check if audio parameters are asked from video enc instance or vice versa
if (((pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf/encoder/video")) > 0) && (iInFormat == PVMF_MIME_PCM16)) ||
((pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf/encoder/audio")) > 0) && (iInFormat != PVMF_MIME_PCM16))
)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::DoCapConfigGetParameters() Unsupported key", iNodeTypeId));
return PVMFErrNotSupported;
}
// Retrieve the fourth component from the key string
pv_mime_string_extract_type(3, aIdentifier, compstr);
for (int32 enccomp4ind = 0; enccomp4ind < PVOMXENCNODECONFIG_BASE_NUMKEYS; ++enccomp4ind)
{
// Go through each video enc component string at 4th level
if (pv_mime_strcmp(compstr, (char*)(PVOMXEncNodeConfigBaseKeys[enccomp4ind].iString)) >= 0)
{
if (4 == compcount)
{
// Determine what is requested
PvmiKvpAttr reqattr = GetAttrTypeFromKeyString(aIdentifier);
if (PVMI_KVPATTR_UNKNOWN == reqattr)
{
reqattr = PVMI_KVPATTR_CUR;
}
// Return the requested info
PVMFStatus retval = GetConfigParameter(aParameters, aNumParamElements, enccomp4ind, reqattr);
if (PVMFSuccess != retval)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::DoCapConfigGetParametersSync() Retrieving video enc node parameter failed", iNodeTypeId));
return retval;
}
}
else
{
// Right now videoenc node doesn't support more than 4 components
// for this sub-key string so error out
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::DoCapConfigGetParametersSync() Unsupported key", iNodeTypeId));
return PVMFErrNotSupported;
}
}
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::DoCapConfigGetParametersSync() Out", iNodeTypeId));
if (aNumParamElements == 0)
{
// If no one could get the parameter, return error
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::DoCapConfigGetParametersSync() Unsupported key", iNodeTypeId));
return PVMFFailure;
}
else
{
return PVMFSuccess;
}
}
//PVMFStatus PVMFOMXEncNode::releaseParameters(PvmiMIOSession aSession, PvmiKvp* aParameters, int aNumElements)
PVMFStatus PVMFOMXEncNode::DoCapConfigReleaseParameters(PvmiKvp* aParameters, int aNumElements)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::releaseParameters()", iNodeTypeId));
//OSCL_UNUSED_ARG(aSession);
if (aParameters == NULL || aNumElements < 1)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::DoCapConfigReleaseParameters() KVP list is NULL or number of elements is 0", iNodeTypeId));
return PVMFErrArgument;
}
// Count the number of components and parameters in the key
int compcount = pv_mime_string_compcnt(aParameters[0].key);
// Retrieve the first component from the key string
char* compstr = NULL;
pv_mime_string_extract_type(0, aParameters[0].key, compstr);
if ((
(pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf/encoder/video")) < 0) &&
(pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf/encoder/audio")) < 0)
) || (compcount < 3))
{
// First 3 component should be "x-pvmf/encoder/video" or "x-pvmf/encoder/audio" and there must
// be at least three components
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::DoCapConfigReleaseParameters() Unsupported key", iNodeTypeId));
return PVMFErrNotSupported;
}
// check if audio parameters are asked from video enc instance or vice versa
if (((pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf/encoder/video")) > 0) && (iInFormat == PVMF_MIME_PCM16)) ||
((pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf/encoder/audio")) > 0) && (iInFormat != PVMF_MIME_PCM16))
)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::DoCapConfigReleaseParameters() Unsupported key", iNodeTypeId));
return PVMFErrNotSupported;
}
// Retrieve the third component from the key string
pv_mime_string_extract_type(2, aParameters[0].key, compstr);
// Go through each KVP and release memory for value if allocated from heap
for (int32 ii = 0; ii < aNumElements; ++ii)
{
// Next check if it is a value type that allocated memory
PvmiKvpType kvptype = GetTypeFromKeyString(aParameters[ii].key);
if (PVMI_KVPTYPE_VALUE == kvptype || PVMI_KVPTYPE_UNKNOWN == kvptype)
{
PvmiKvpValueType keyvaltype = GetValTypeFromKeyString(aParameters[ii].key);
if (PVMI_KVPVALTYPE_UNKNOWN == keyvaltype)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::DoCapConfigReleaseParameters() Valtype not specified in key string", iNodeTypeId));
return PVMFErrNotSupported;
}
if (PVMI_KVPVALTYPE_CHARPTR == keyvaltype && NULL != aParameters[ii].value.pChar_value)
{
oscl_free(aParameters[ii].value.pChar_value);
aParameters[ii].value.pChar_value = NULL;
}
else if (keyvaltype == PVMI_KVPVALTYPE_KSV && NULL != aParameters[ii].value.key_specific_value)
{
oscl_free(aParameters[ii].value.key_specific_value);
aParameters[ii].value.key_specific_value = NULL;
}
else if (PVMI_KVPVALTYPE_RANGE_UINT32 == keyvaltype && NULL != aParameters[ii].value.key_specific_value)
{
range_uint32* rui32 = (range_uint32*)aParameters[ii].value.key_specific_value;
aParameters[ii].value.key_specific_value = NULL;
oscl_free(rui32);
}
// @TODO Add more types if video enc node starts returning more types
}
}
// Video enc node allocated its key strings in one chunk so just free the first key string ptr
oscl_free(aParameters[0].key);
// Free memory for the parameter list
oscl_free(aParameters);
aParameters = NULL;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::DoCapConfigReleaseParameters() Out", iNodeTypeId));
return PVMFSuccess;
}
//PVMFStatus PVMFOMXEncNode::verifyParametersSync (PvmiMIOSession aSession, PvmiKvp* aParameters, int aNumElements)
PVMFStatus PVMFOMXEncNode::DoCapConfigVerifyParameters(PvmiKvp* aParameters, int aNumElements)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::DoCapConfigVerifyParameters()", iNodeTypeId));
//OSCL_UNUSED_ARG(aSession);
if (NULL == aParameters || aNumElements < 1)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::DoCapConfigVerifyParameters() Passed in parameter invalid", iNodeTypeId));
return PVMFErrArgument;
}
// Go through each parameter
for (int32 paramind = 0; paramind < aNumElements; ++paramind)
{
// Count the number of components and parameters in the key
int compcount = pv_mime_string_compcnt(aParameters[paramind].key);
// Retrieve the first component from the key string
char* compstr = NULL;
pv_mime_string_extract_type(0, aParameters[paramind].key, compstr);
if (
((pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf/encoder/video")) < 0) &&
(pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf/encoder/audio")) < 0)
) || compcount < 3)
{
// First 3 components should be "x-pvmf/encoder/video" or
// "x-pvmf/enoder/audio" and there must
// be at least 3 components
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::DoCapConfigVerifyParameters() Unsupported key", iNodeTypeId));
return PVMFErrNotSupported;
}
// check if audio parameters are asked from video enc instance or vice versa
if (((pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf/encoder/video")) > 0) && (iInFormat == PVMF_MIME_PCM16)) ||
((pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf/encoder/audio")) > 0) && (iInFormat != PVMF_MIME_PCM16))
)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::DoCapConfigVerifyParameters() Unsupported key", iNodeTypeId));
return PVMFErrNotSupported;
}
if (4 == compcount)
{
// Verify and set the passed-in video enc node setting
PVMFStatus retval = VerifyAndSetConfigParameter(aParameters[paramind], false);
if (retval != PVMFSuccess)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::DoCapConfigVerifyParameters() Setting parameter %d failed", iNodeTypeId, paramind));
return retval;
}
}
else
{
// Do not support more than 4 components right now
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXEncNode-%s::DoCapConfigVerifyParameters() Unsupported key", iNodeTypeId));
return PVMFErrNotSupported;
}
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::DoCapConfigVerifyParameters() Out", iNodeTypeId));
return PVMFSuccess;
}
int32 PVMFOMXEncNode::PushBackKeyVal(Oscl_Vector<PvmiKvp, OsclMemAllocator>*& aValueListPtr, PvmiKvp &aKeyVal)
{
int32 leavecode = 0;
OSCL_TRY(leavecode, (*aValueListPtr).push_back(aKeyVal));
return leavecode;
}
int32 PVMFOMXEncNode::Push_Back_MetadataKeys(const char* aMetadataKey)
{
int32 leavecode = 0;
OSCL_TRY(leavecode, iAvailableMetadataKeys.push_back(aMetadataKey));
return leavecode;
}
int32 PVMFOMXEncNode::Push_Back_MetadataKeys(PVMFMetadataList *&aKeylistptr, uint32 aLcv)
{
int32 leavecode = 0;
OSCL_TRY(leavecode, aKeylistptr->push_back(iAvailableMetadataKeys[aLcv]));
return leavecode;
}
int32 PVMFOMXEncNode::CreateNewArray(char*& aPtr, int32 aLen)
{
int32 leavecode = 0;
OSCL_TRY(leavecode,
aPtr = OSCL_ARRAY_NEW(char, aLen););
return leavecode;
}
int32 PVMFOMXEncNode::MemAllocate(OsclAny *&aPtr, OsclMemPoolFixedChunkAllocator *aMemPool, uint32 aAllocSize)
{
uint32 errcode = 0;
OSCL_TRY(errcode, aPtr = (OsclAny *) aMemPool->allocate(aAllocSize));
return errcode;
}
bool PVMFOMXEncNode::ParseFullAVCFramesIntoNALs(OMX_BUFFERHEADERTYPE* aOutputBuffer)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "PVMFOMXEncNode-%s : ParseFullAVCFramesIntoNALs IN", iNodeTypeId));
if (iOMXComponentUsesNALStartCodes && !(aOutputBuffer->nFlags & OMX_BUFFERFLAG_EXTRADATA))
{
OMX_U32 offset = aOutputBuffer->nOffset;
OMX_U32 length = aOutputBuffer->nFilledLen;
OMX_U8* pBuffer = aOutputBuffer->pBuffer + offset;
OMX_U8* pCurrNAL;
OMX_U32 bytesConsumed;
int32 nalSize;
iNumNALs = 0;
while (length > 0)
{
nalSize = length;
if (false == AVCAnnexBGetNALUnit(pBuffer, &pCurrNAL, &nalSize, false))
{
break;
}
bytesConsumed = nalSize + (int32)(pCurrNAL - pBuffer);
length -= bytesConsumed;
pBuffer += bytesConsumed;
if ((iNALSizeArrayMaxElems > iNumNALs) && (iNALSizeArray != NULL))
{
iNALSizeArray[iNumNALs] = nalSize;
iNALPtrArray[iNumNALs] = (uint8*)pCurrNAL; /* need store NAL ptrs since start code can be either 4 bytes or 3 bytes */
iNumNALs++;
}
else
{
iNumNALs++;
// count the number of NALs in the buffer
while (length > 0)
{
nalSize = length;
if (false == AVCAnnexBGetNALUnit(pBuffer, &pCurrNAL, &nalSize, false))
{
break;
}
bytesConsumed = nalSize + (int32)(pCurrNAL - pBuffer);
length -= bytesConsumed;
pBuffer += bytesConsumed;
iNumNALs++;
}
// reassign alloc size to new max.
iNALSizeArrayMaxElems = iNumNALs;
// free memory and then reallocate
if (iNALSizeArray != NULL)
{
oscl_free(iNALSizeArray);
}
iNALSizeArray = (uint32*) oscl_malloc(sizeof(uint32) * iNALSizeArrayMaxElems);
if (iNALPtrArray != NULL)
{
oscl_free(iNALPtrArray);
}
iNALPtrArray = (uint8**) oscl_malloc(sizeof(uint8*) * iNALSizeArrayMaxElems);
// reset parameters and start over
iNumNALs = 0;
length = aOutputBuffer->nFilledLen;
pBuffer = aOutputBuffer->pBuffer + offset;
if (iNALSizeArray == NULL || iNALPtrArray == NULL)
{
iNALSizeArrayMaxElems = 0;
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "PVMFOMXEncNode-%s : ParseFullAVCFramesIntoNALs ERROR - Out of Memory", iNodeTypeId));
return false;
}
}
}
if (iNumNALs <= 0)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "PVMFOMXEncNode-%s : ParseFullAVCFramesIntoNALs ERROR", iNodeTypeId));
return false;
}
}
else if (aOutputBuffer->nFlags & OMX_BUFFERFLAG_EXTRADATA)
{
// get extra data from end of buffer
OMX_OTHER_EXTRADATATYPE *pExtra;
OMX_U32 offset = aOutputBuffer->nOffset + aOutputBuffer->nFilledLen;
OMX_U32 allocLen = aOutputBuffer->nAllocLen;
OMX_U8* pTemp = aOutputBuffer->pBuffer + offset;
// align
pExtra = (OMX_OTHER_EXTRADATATYPE *)(((OMX_U32) pTemp + 3) & ~3);
offset += (OMX_U32) pExtra - (OMX_U32) pTemp;
while (pExtra->eType != OMX_ExtraDataNone)
{
if (pExtra->eType == OMX_ExtraDataNALSizeArray)
{
iNumNALs = pExtra->nDataSize >> 2;
if ((iNALSizeArrayMaxElems > iNumNALs) && (iNALSizeArray != NULL))
{
oscl_memcpy(iNALSizeArray, ((OMX_U8*)pExtra + 20), pExtra->nDataSize); // 20 is the size of the extra data struct (minus data hint)
}
else
{
// reassign alloc size to new max.
iNALSizeArrayMaxElems = iNumNALs;
// free memory and then reallocate
if (iNALSizeArray != NULL)
{
oscl_free(iNALSizeArray);
}
iNALSizeArray = (uint32*) oscl_malloc(sizeof(uint32) * iNALSizeArrayMaxElems);
if (iNALSizeArray == NULL)
{
iNALSizeArrayMaxElems = 0;
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "PVMFOMXEncNode-%s : ParseFullAVCFramesIntoNALs ERROR - Out of Memory", iNodeTypeId));
return false;
}
oscl_memcpy(iNALSizeArray, ((OMX_U8*)pExtra + 20), pExtra->nDataSize); // 20 is the size of the extra data struct (minus data hint)
}
break;
}
offset += pExtra->nSize;
/* 20 is size of extra data struct (minus data hint),
* so if there isn't enough room for there to be a full struct, and we haven't reached an OMX_ExtraDataNone
* the data is corrupt
*/
if (offset > (allocLen - 20))
{
// corrupt data
break;
}
else
{
pExtra = (OMX_OTHER_EXTRADATATYPE *)((OMX_U8*)pExtra + pExtra->nSize);
}
}
if (pExtra->eType != OMX_ExtraDataNALSizeArray)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "PVMFOMXEncNode-%s : ParseFullAVCFramesIntoNALs ERROR", iNodeTypeId));
return false;
}
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "PVMFOMXEncNode-%s : ParseFullAVCFramesIntoNALs ERROR", iNodeTypeId));
return false;
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "PVMFOMXEncNode-%s : ParseFullAVCFramesIntoNALs OUT", iNodeTypeId));
return true;
}
/* utility function copied from the AVC Decoder interface */
bool PVMFOMXEncNode::AVCAnnexBGetNALUnit(uint8 *bitstream, uint8 **nal_unit, int32 *size, bool getPtrOnly)
{
int32 i, j, FoundStartCode = 0;
int32 end;
i = 0;
while (bitstream[i] == 0 && i < *size)
{
i++;
}
if (i >= *size)
{
*nal_unit = bitstream;
return false; /* cannot find any start_code_prefix. */
}
else if (bitstream[i] != 0x1)
{
i = -1; /* start_code_prefix is not at the beginning, continue */
}
i++;
*nal_unit = bitstream + i; /* point to the beginning of the NAL unit */
if (getPtrOnly)
{
// size not needed, just return with ptr
return true;
}
j = end = i;
while (!FoundStartCode)
{
while ((j + 1 < *size) && (bitstream[j] != 0 || bitstream[j+1] != 0)) /* see 2 consecutive zero bytes */
{
j++;
}
end = j; /* stop and check for start code */
while (j + 2 < *size && bitstream[j+2] == 0) /* keep reading for zero byte */
{
j++;
}
if (j + 2 >= *size)
{
*size -= i;
return true; /* cannot find the second start_code_prefix */
}
if (bitstream[j+2] == 0x1)
{
FoundStartCode = 1;
}
else
{
/* could be emulation code 0x3 */
j += 2; /* continue the search */
}
}
*size = end - i;
return true;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool PVMFOMXEncNode::CheckM4vVopStartCode(uint8* data, int* len)
{
int32 count = 0;
int32 i = *len;
if (i < 4) // at least the size of frame header
{
return false;
}
while (--i)
{
if ((count > 1) && (data[0] == 0x01) && (data[1] == 0xB6))
{
i += 2;
break;
}
if (*data++)
count = 0;
else
count++;
}
// i is number of bytes left (including 00 00 01 B6)
if (i > 0)
{
*len = (*len - i - 1); // len before finding VOP start code
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
OMX_TICKS PVMFOMXEncNode::ConvertTimestampIntoOMXTicks(const MediaClockConverter& src)
{
// This is similar to mediaclockconverter set_value method - except without using the modulo for upper part of 64 bits
// Timescale value cannot be zero
OSCL_ASSERT(src.get_timescale() != 0);
if (src.get_timescale() == 0)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::ConvertTimestampIntoOMXTicks Input timescale is 0", iNodeTypeId));
SetState(EPVMFNodeError);
ReportErrorEvent(PVMFErrResourceConfiguration);
return (OMX_TICKS) 0;
}
OSCL_ASSERT(iTimeScale != 0);
if (0 == iTimeScale)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::ConvertTimestampIntoOMXTicks target timescale is 0", iNodeTypeId));
SetState(EPVMFNodeError);
ReportErrorEvent(PVMFErrResourceConfiguration);
return (OMX_TICKS) 0;
}
uint64 value = (uint64(src.get_wrap_count())) << 32;
value += src.get_current_timestamp();
// rounding up
value = (uint64(value) * iTimeScale + uint64(src.get_timescale() - 1)) / src.get_timescale();
return (OMX_TICKS) value;
}
////////////////////////////////////////////////////////////////////////////////////
uint32 PVMFOMXEncNode::ConvertOMXTicksIntoTimestamp(const OMX_TICKS &src)
{
// omx ticks use microsecond timescale (iTimeScale = 1000000)
// This is similar to mediaclockconverter set_value method
// Timescale value cannot be zero
OSCL_ASSERT(iOutTimeScale != 0);
if (0 == iOutTimeScale)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::ConvertOMXTicksIntoTimestamp Output timescale is 0", iNodeTypeId));
SetState(EPVMFNodeError);
ReportErrorEvent(PVMFErrResourceConfiguration);
return (uint32) 0;
}
OSCL_ASSERT(iTimeScale != 0);
if (0 == iTimeScale)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::ConvertOMXTicksIntoTimestamp target timescale is 0", iNodeTypeId));
SetState(EPVMFNodeError);
ReportErrorEvent(PVMFErrResourceConfiguration);
return (uint32) 0;
}
uint32 current_ts;
uint64 value = (uint64) src;
// rounding up
value = (uint64(value) * iOutTimeScale + uint64(iTimeScale - 1)) / iTimeScale;
current_ts = (uint32)(value & 0xFFFFFFFF);
return (uint32) current_ts;
}
////////////////////////////////////////////////////////////////////////////////
bool PVMFOMXEncNode::CheckComponentForMultRoles(OMX_STRING aCompName, OMX_STRING aRole)
{
OMX_ERRORTYPE err = OMX_ErrorNone;
// find out how many roles the component supports
OMX_U32 NumRoles;
err = OMX_MasterGetRolesOfComponent(aCompName, &NumRoles, NULL);
if (err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::CheckComponentForMultRoles() Problem getting component roles", iNodeTypeId));
return false;
}
// if the component supports multiple roles, call OMX_SetParameter
if (NumRoles > 1)
{
OMX_PARAM_COMPONENTROLETYPE RoleParam;
CONFIG_SIZE_AND_VERSION(RoleParam);
oscl_strncpy((OMX_STRING)RoleParam.cRole, aRole, OMX_MAX_STRINGNAME_SIZE);
err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamStandardComponentRole, &RoleParam);
if (err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::CheckComponentForMultRoles() Problem setting component role", iNodeTypeId));
return false;
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
bool PVMFOMXEncNode::CheckComponentCapabilities(PVMFFormatType* aOutFormat)
{
OMX_ERRORTYPE err = OMX_ErrorNone;
// GET CAPABILITY FLAGS FROM PV COMPONENT, IF this fails, use defaults
PV_OMXComponentCapabilityFlagsType Cap_flags;
err = OMX_GetParameter(iOMXEncoder, (OMX_INDEXTYPE) PV_OMX_COMPONENT_CAPABILITY_TYPE_INDEX, &Cap_flags);
if (err != OMX_ErrorNone)
{
SetDefaultCapabilityFlags();
}
else
{
iIsOMXComponentMultiThreaded = (OMX_TRUE == Cap_flags.iIsOMXComponentMultiThreaded) ? true : false;
iOMXComponentSupportsExternalInputBufferAlloc = (OMX_TRUE == Cap_flags.iOMXComponentSupportsExternalInputBufferAlloc) ? true : false;
iOMXComponentSupportsExternalOutputBufferAlloc = (OMX_TRUE == Cap_flags.iOMXComponentSupportsExternalOutputBufferAlloc) ? true : false;
iOMXComponentSupportsMovableInputBuffers = (OMX_TRUE == Cap_flags.iOMXComponentSupportsMovableInputBuffers) ? true : false;
iOMXComponentSupportsPartialFrames = (OMX_TRUE == Cap_flags.iOMXComponentSupportsPartialFrames) ? true : false;
iOMXComponentUsesNALStartCodes = (OMX_TRUE == Cap_flags.iOMXComponentUsesNALStartCodes) ? true : false;
iOMXComponentCanHandleIncompleteFrames = (OMX_TRUE == Cap_flags.iOMXComponentCanHandleIncompleteFrames) ? true : false;
iOMXComponentUsesFullAVCFrames = (OMX_TRUE == Cap_flags.iOMXComponentUsesFullAVCFrames) ? true : false;
}
/* iOMXComponentUsesNALStartCodes: The component inserts start codes before NALs
iOMXComponentUsesFullAVCFrames
&& !iOMXComponentUsesNALStartCodes: The component outputs full frames, and stores NAL start codes using the
OMX ExtraData structure in the output buffer
iOMXComponentUsesFullAVCFrames
&& iOMXComponentUsesNALStartCodes: The component outputs full frames, and delimits NALs by their start codes
aOutFormat == PVMF_MIME_H264_VIDEO_RAW
&& !iOMXComponentUsesNALStartCodes: The node inserts the start codes and hides them / exposes them when needed
aOutFormat == PVMF_MIME_H264_VIDEO_RAW
&& !iOMXComponentUsesNALStartCodes
&& iOMXComponentUsesFullAVCFrames: This is an invalid combination. If the node wants raw output, and the component
uses full frames, and no start codes, then there is no way to detect the
NAL boundaries.
*/
if (*aOutFormat == PVMF_MIME_H264_VIDEO_RAW &&
iOMXComponentUsesFullAVCFrames && !iOMXComponentUsesNALStartCodes)
{
// This is an invalid combination (see above). Therefore, return an error.
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::CheckComponentCapabilities() Component cannot support %s format", iNodeTypeId, PVMF_MIME_H264_VIDEO_RAW));
return false;
}
// find out about parameters
if (aOutFormat->isAudio())
{
if (!NegotiateAudioComponentParameters())
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::CheckComponentCapabilities() Cannot get component parameters", iNodeTypeId));
return false;
}
}
else
{
if (!NegotiateVideoComponentParameters())
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "PVMFOMXEncNode-%s::CheckComponentCapabilities() Cannot get component parameters", iNodeTypeId));
return false;
}
}
return true;
}