blob: fa5864170ff6561fd97da98a6eab00d05579e872 [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_basedec_node.h"
#include "pvlogger.h"
#include "oscl_error_codes.h"
#ifndef OSCL_INT64_UTILS_H_INCLUDED
#include "oscl_int64_utils.h"
#endif
#include "pvmf_omx_basedec_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"
#include "OMX_Core.h"
#include "pvmf_omx_basedec_callbacks.h" //used for thin AO in Decoder's callbacks
#include "pv_omxcore.h"
#include "pv_omx_config_parser.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 PVOMXBASEDEC_MEDIADATA_CHUNKSIZE 128
#if 0
#include <utils/Log.h>
#undef LOG_TAG
#define LOG_TAG "SW_BASE"
#undef PVLOGGER_LOGMSG
#define PVLOGGER_LOGMSG(IL, LOGGER, LEVEL, MESSAGE) JJLOGE MESSAGE
#define JJLOGE(id, ...) LOGE(__VA_ARGS__)
#endif
// 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 CallbackEventHandler(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)
{
PVMFOMXBaseDecNode *Node = (PVMFOMXBaseDecNode *) 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 CallbackEmptyBufferDone(OMX_OUT OMX_HANDLETYPE aComponent,
OMX_OUT OMX_PTR aAppData,
OMX_OUT OMX_BUFFERHEADERTYPE* aBuffer)
{
PVMFOMXBaseDecNode *Node = (PVMFOMXBaseDecNode *) 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 CallbackFillBufferDone(OMX_OUT OMX_HANDLETYPE aComponent,
OMX_OUT OMX_PTR aAppData,
OMX_OUT OMX_BUFFERHEADERTYPE* aBuffer)
{
PVMFOMXBaseDecNode *Node = (PVMFOMXBaseDecNode *) 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
OSCL_EXPORT_REF OsclReturnCode PVMFOMXBaseDecNode::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
OSCL_EXPORT_REF OsclReturnCode PVMFOMXBaseDecNode::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
OSCL_EXPORT_REF OsclReturnCode PVMFOMXBaseDecNode::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
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFOMXBaseDecNode::~PVMFOMXBaseDecNode()
{
LogDiagnostics();
//Clearup decoder
DeleteOMXBaseDecoder();
// 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;
}
if (iInBufMemoryPool)
{
iInBufMemoryPool->removeRef();
iInBufMemoryPool = NULL;
}
//Thread logoff
if (IsAdded())
{
RemoveFromScheduler();
iIsAdded = false;
}
//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);
}
//Release Input buffer
iDataIn.Unbind();
}
/////////////////////////////////////////////////////////////////////////////
// Remove AO from the scheduler
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMFOMXBaseDecNode::ThreadLogoff()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iLogger, PVLOGMSG_INFO, (0, "%s:ThreadLogoff", iName.Str()));
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
}
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMFOMXBaseDecNode::GetCapability(PVMFNodeCapability& aNodeCapability)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::GetCapability() called", iName.Str()));
aNodeCapability = iCapability;
return PVMFSuccess;
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFPortIter* PVMFOMXBaseDecNode::GetPorts(const PVMFPortFilter* aFilter)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::GetPorts() called", iName.Str()));
OSCL_UNUSED_ARG(aFilter);
return NULL;
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMFOMXBaseDecNode::QueueCommandL(PVMFOMXBaseDecNodeCommand& 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;
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMFOMXBaseDecNode::QueryUUID(PVMFSessionId s, const PvmfMimeString& aMimeType,
Oscl_Vector<PVUuid, PVMFOMXBaseDecNodeAllocator>& aUuids,
bool aExactUuidsOnly,
const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::QueryUUID() called", iName.Str()));
PVMFOMXBaseDecNodeCommand cmd;
cmd.PVMFOMXBaseDecNodeCommandBase::Construct(s, PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_QUERYUUID, aMimeType, aUuids, aExactUuidsOnly, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMFOMXBaseDecNode::QueryInterface(PVMFSessionId s, const PVUuid& aUuid,
PVInterface*& aInterfacePtr,
const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::QueryInterface() called", iName.Str()));
PVMFOMXBaseDecNodeCommand cmd;
cmd.PVMFOMXBaseDecNodeCommandBase::Construct(s, PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_QUERYINTERFACE, aUuid, aInterfacePtr, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMFOMXBaseDecNode::RequestPort(PVMFSessionId s, int32 aPortTag, const PvmfMimeString* /* aPortConfig */, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::RequestPort() called", iName.Str()));
PVMFOMXBaseDecNodeCommand cmd;
cmd.PVMFOMXBaseDecNodeCommandBase::Construct(s, PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_REQUESTPORT, aPortTag, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMFOMXBaseDecNode::ReleasePort(PVMFSessionId s, PVMFPortInterface& aPort, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::ReleasePort() called", iName.Str()));
PVMFOMXBaseDecNodeCommand cmd;
cmd.PVMFOMXBaseDecNodeCommandBase::Construct(s, PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_RELEASEPORT, aPort, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMFOMXBaseDecNode::Init(PVMFSessionId s, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::Init() called", iName.Str()));
PVMFOMXBaseDecNodeCommand cmd;
cmd.PVMFOMXBaseDecNodeCommandBase::Construct(s, PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_INIT, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMFOMXBaseDecNode::Prepare(PVMFSessionId s, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::Prepare() called", iName.Str()));
PVMFOMXBaseDecNodeCommand cmd;
cmd.PVMFOMXBaseDecNodeCommandBase::Construct(s, PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_PREPARE, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMFOMXBaseDecNode::Start(PVMFSessionId s, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::Start() called", iName.Str()));
PVMFOMXBaseDecNodeCommand cmd;
cmd.PVMFOMXBaseDecNodeCommandBase::Construct(s, PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_START, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMFOMXBaseDecNode::Stop(PVMFSessionId s, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::Stop() called", iName.Str()));
PVMFOMXBaseDecNodeCommand cmd;
cmd.PVMFOMXBaseDecNodeCommandBase::Construct(s, PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_STOP, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMFOMXBaseDecNode::Flush(PVMFSessionId s, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::Flush() called", iName.Str()));
PVMFOMXBaseDecNodeCommand cmd;
cmd.PVMFOMXBaseDecNodeCommandBase::Construct(s, PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_FLUSH, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMFOMXBaseDecNode::Pause(PVMFSessionId s, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::Pause() called", iName.Str()));
PVMFOMXBaseDecNodeCommand cmd;
cmd.PVMFOMXBaseDecNodeCommandBase::Construct(s, PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_PAUSE, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMFOMXBaseDecNode::Reset(PVMFSessionId s, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::Reset() called", iName.Str()));
PVMFOMXBaseDecNodeCommand cmd;
cmd.PVMFOMXBaseDecNodeCommandBase::Construct(s, PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_RESET, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMFOMXBaseDecNode::CancelAllCommands(PVMFSessionId s, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::CancelAllCommands() called", iName.Str()));
PVMFOMXBaseDecNodeCommand cmd;
cmd.PVMFOMXBaseDecNodeCommandBase::Construct(s, PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_CANCELALL, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMFOMXBaseDecNode::CancelCommand(PVMFSessionId s, PVMFCommandId aCmdId, const OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::CancelCommand() called", iName.Str()));
PVMFOMXBaseDecNodeCommand cmd;
cmd.PVMFOMXBaseDecNodeCommandBase::Construct(s, PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_CANCELCMD, aCmdId, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMFOMXBaseDecNode::SetDecoderNodeConfiguration(PVMFOMXBaseDecNodeConfig& aNodeConfig)
{
iNodeConfig = aNodeConfig;
return PVMFSuccess;
}
/////////////////////
// Private Section //
/////////////////////
/////////////////////////////////////////////////////////////////////////////
// Class Constructor
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFOMXBaseDecNode::PVMFOMXBaseDecNode(int32 aPriority, const char aAOName[], bool accelerated) :
OsclActiveObject(aPriority, aAOName),
iInPort(NULL),
iOutPort(NULL),
iOutBufMemoryPool(NULL),
iMediaDataMemPool(NULL),
iOMXComponentOutputBufferSize(0),
iOutputAllocSize(0),
iProcessingState(EPVMFOMXBaseDecNodeProcessingState_Idle),
iOMXDecoder(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),
iCompactFSISettingSucceeded(false),
bHWAccelerated(accelerated? OMX_TRUE: OMX_FALSE)
{
iThreadSafeHandlerEventHandler = NULL;
iThreadSafeHandlerEmptyBufferDone = NULL;
iThreadSafeHandlerFillBufferDone = NULL;
iInBufMemoryPool = NULL;
iOutBufMemoryPool = NULL;
// init to some value
iOMXComponentOutputBufferSize = 0;
iNumOutputBuffers = 0;
iNumOutstandingOutputBuffers = 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;
iPauseCommandWasSentToComponent = false;
iStopCommandWasSentToComponent = false;
// capability related, set to default values
iOMXComponentSupportsExternalOutputBufferAlloc = false;
iOMXComponentSupportsExternalInputBufferAlloc = false;
iOMXComponentSupportsMovableInputBuffers = false;
iIsOMXComponentMultiThreaded = true;
iOMXComponentSupportsPartialFrames = false;
iOMXComponentUsesNALStartCodes = true;
iOMXComponentUsesFullAVCFrames = false;
iOMXComponentCanHandleIncompleteFrames = true;
// EOS flag init
iIsEOSSentToComponent = false;
iIsEOSReceivedFromComponent = false;
// reset repositioning related flags
iIsRepositioningRequestSentToComponent = false;
iIsRepositionDoneReceivedFromComponent = false;
iIsOutputPortFlushed = false;
iIsInputPortFlushed = false;
// init state of component
iCurrentDecoderState = OMX_StateInvalid;
iOutTimeStamp = 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;
iInputBufferUnderConstruction = NULL; // for partial frame assembly
iFirstPieceOfPartialFrame = true;
iObtainNewInputBuffer = true;
iFirstDataMsgAfterBOS = true;
iKeepDroppingMsgsUntilMarkerBit = false;
}
/////////////////////////////////////////////////////////////////////////////
// Local Run Routine
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PVMFOMXBaseDecNode::Run()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::Run() In", iName.Str()));
// if reset is in progress, call DoReset again until Reset Msg is sent
if ((iResetInProgress == true) &&
(iResetMsgSent == false) &&
(iCurrentCommand.size() > 0) &&
(iCurrentCommand.front().iCmd == PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_RESET)
)
{
DoReset(iCurrentCommand.front());
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "%s::Run() - Calling DoReset", iName.Str()));
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) || (iDynamicReconfigInProgress == true) ||
((iNumOutstandingOutputBuffers < iNumOutputBuffers) &&
(iProcessingState == EPVMFOMXBaseDecNodeProcessingState_ReadyToDecode))
))
{
// reschedule if more data is available, or if port reconfig needs to be finished (even if there is no new data)
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "%s::Run() - rescheduling after process command", iName.Str()));
RunIfNotReady();
}
return;
}
if (!iInputCommands.empty())
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "%s::Run() - rescheduling to process more commands", iName.Str()));
RunIfNotReady();
}
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "%s::Run() - Input commands empty", iName.Str()));
}
if (((iCurrentCommand.size() == 0) && (iInterfaceState != EPVMFNodeStarted)) ||
((iCurrentCommand.size() > 0) && (iCurrentCommand.front().iCmd == PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_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, "%s::Run() - Node not in Started state yet", iName.Str()));
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, "%s::Run() - Outgoing Port Busy, cannot send more msgs", iName.Str()));
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) &&
(!iDynamicReconfigInProgress) &&
(!iIsRepositioningRequestSentToComponent)
)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "%s::Run() - Getting more input", iName.Str()));
if (!ProcessIncomingMsg(iInPort))
{
//Re-schedule
RunIfNotReady();
return;
}
}
if (iSendBOS)
{
// this routine may be re-entered multiple times in multiple Run's before the component goes through cycle execute->idle->execute
if (!HandleRepositioning())
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "%s::Run() - Repositioning not done yet", iName.Str()));
return;
}
SendBeginOfMediaStreamCommand();
}
// If in init or ready to decode 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 == EPVMFOMXBaseDecNodeProcessingState_ReadyToDecode) &&
(iResetMsgSent == false)) ||
((iDynamicReconfigInProgress == true) && (iResetMsgSent == false))
)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "%s::Run() - Calling HandleProcessingState", iName.Str()));
// input data is available, that means there is input data to be decoded
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, "%s::Run() - HandleProcessingState did not return Success", iName.Str()));
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, "%s::Run() - LoopCount = %d, Time spent in loop(in ms) = %d, iNumOutstandingInputBuffers = %d, iNumOutstandingOutputBuffers = %d ",
iName.Str(), 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, "%s::Run() - Sending EOS marked buffer To Component ", iName.Str()));
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 != EPVMFOMXBaseDecNodeProcessingState_ReadyToDecode)
{
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, "%s::Run() - Received EOS from component, Sending EOS msg downstream ", iName.Str()));
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, "%s::Run() - - EOS cannot be sent downstream, outgoing queue busy - wait", iName.Str()));
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, "%s::Run() - EOS was queued to be sent downstream", iName.Str()));
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
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 == PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_FLUSH) &&
(iInPort->IncomingMsgQueueSize() == 0) &&
(iOutPort->OutgoingMsgQueueSize() == 0) &&
(iDataIn.GetRep() == NULL))
{
//flush command is complited
//Debug check-- all the port queues should be empty at this point.
OSCL_ASSERT(iInPort->IncomingMsgQueueSize() == 0 && iOutPort->OutgoingMsgQueueSize() == 0);
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "%s::Run() - Flush pending", iName.Str()));
iEndOfDataReached = false;
iIsEOSSentToComponent = false;
iIsEOSReceivedFromComponent = false;
//Flush is complete. Go to initialized state.
SetState(EPVMFNodePrepared);
//resume port input so the ports can be re-started.
iInPort->ResumeInput();
iOutPort->ResumeInput();
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess);
RunIfNotReady();
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::Run() Out", iName.Str()));
}
/////////////////////////////////////////////////////////////////////////////
// This routine will dispatch recived commands
/////////////////////////////////////////////////////////////////////////////
bool PVMFOMXBaseDecNode::ProcessCommand(PVMFOMXBaseDecNodeCommand& 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 PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_QUERYUUID:
DoQueryUuid(aCmd);
break;
case PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_QUERYINTERFACE:
DoQueryInterface(aCmd);
break;
case PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_REQUESTPORT:
DoRequestPort(aCmd);
break;
case PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_RELEASEPORT:
DoReleasePort(aCmd);
break;
case PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_INIT:
DoInit(aCmd);
break;
case PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_PREPARE:
DoPrepare(aCmd);
break;
case PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_START:
DoStart(aCmd);
break;
case PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_STOP:
DoStop(aCmd);
break;
case PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_FLUSH:
DoFlush(aCmd);
break;
case PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_PAUSE:
DoPause(aCmd);
break;
case PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_RESET:
DoReset(aCmd);
break;
case PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_CANCELCMD:
DoCancelCommand(aCmd);
break;
case PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_CANCELALL:
DoCancelAllCommands(aCmd);
break;
case PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_GETNODEMETADATAKEY:
{
PVMFStatus retval = DoGetNodeMetadataKey(aCmd);
CommandComplete(iInputCommands, aCmd, retval);
}
break;
case PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_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
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMFOMXBaseDecNode::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 %s::ProcessIncomingMsg: aPort=0x%x", this, iName.Str(), aPort));
PVMFStatus status = PVMFFailure;
//#define SIMULATE_BOS
#ifdef SIMULATE_BOS
if (((PVMFOMXDecPort*)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;
((PVMFOMXDecPort*)aPort)->iNumFramesConsumed++;
return true;
}
#endif
//#define SIMULATE_PREMATURE_EOS
#ifdef SIMULATE_PREMATURE_EOS
if (((PVMFOMXDecPort*)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);
((PVMFOMXDecPort*)aPort)->iNumFramesConsumed++;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::ProcessIncomingMsg: SIMULATED EOS", iName.Str()));
// 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 %s::ProcessIncomingMsg: Error - DequeueIncomingMsg failed", this, iName.Str()));
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();
iSendBOS = true;
// 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);
// if new BOS arrives, and
//if we're in the middle of a partial frame assembly
// abandon it and start fresh
if (iObtainNewInputBuffer == false)
{
if (iInputBufferUnderConstruction != NULL)
{
if (iInBufMemoryPool != NULL)
{
iInBufMemoryPool->deallocate((OsclAny *)iInputBufferUnderConstruction);
}
iInputBufferUnderConstruction = NULL;
}
iObtainNewInputBuffer = true;
}
// needed to init the sequence numbers and timestamp for partial frame assembly
iFirstDataMsgAfterBOS = true;
iKeepDroppingMsgsUntilMarkerBit = false;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::ProcessIncomingMsg: Received BOS stream %d, timestamp %d", iName.Str(), iStreamID, iBOSTimestamp));
((PVMFOMXDecPort*)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, "%s::ProcessIncomingMsg: Received EOS", iName.Str()));
((PVMFOMXDecPort*)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
iIsNewDataFragment = true;
((PVMFOMXDecPort*)aPort)->iNumFramesConsumed++;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::ProcessIncomingMsg() Received %d frames", iName.Str(), ((PVMFOMXDecPort*)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 PVMFOMXBaseDecNode::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 %s::ProcessOutgoingMsg: aPort=0x%x", this, iName.Str(), aPort));
PVMFStatus status = aPort->Send();
if (status == PVMFErrBusy)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "0x%x %s::ProcessOutgoingMsg: Connected port goes into busy state", this, iName.Str()));
}
//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 %s::Run: Error - ProcessPortActivity failed. port=0x%x, type=%d",
this, iName.Str(), 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 PVMFOMXBaseDecNode::HandleProcessingState()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::HandleProcessingState() In", iName.Str()));
PVMFStatus status = PVMFSuccess;
switch (iProcessingState)
{
case EPVMFOMXBaseDecNodeProcessingState_InitDecoder:
{
// do init only if input data is available
if (iDataIn.GetRep() != NULL)
{
if (!InitDecoder(iDataIn))
{
// Decoder initialization failed. Fatal error
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::HandleProcessingState() Decoder initialization failed", iName.Str()));
ReportErrorEvent(PVMFErrResourceConfiguration);
ChangeNodeState(EPVMFNodeError);
break;
}
// if a callback already happened, continue to decoding. If not, wait
// it is also possible that port settings changed event may occur.
//DV: temp
//if(iProcessingState != EPVMFOMXBaseDecNodeProcessingState_ReadyToDecode)
// iProcessingState = EPVMFOMXBaseDecNodeProcessingState_WaitForInitCompletion;
iProcessingState = EPVMFOMXBaseDecNodeProcessingState_ReadyToDecode;
// spin once to send output buffers
RunIfNotReady();
status = PVMFSuccess; // allow rescheduling
}
break;
}
case EPVMFOMXBaseDecNodeProcessingState_WaitForInitCompletion:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleProcessingState() WaitForInitCompletion -> wait for config buffer to return", iName.Str()));
status = PVMFPending; // prevent rescheduling
break;
}
// The FOLLOWING 4 states handle Dynamic Port Reconfiguration
#if 0 //QCOM WORKAROUND JJDBG. Disable this QCOM workaround as i) it has side effects; ii) QCOM HW decoder is NOT used for m4v and h263 in Cupcake. JJ 03/25/09
case EPVMFOMXBaseDecNodeProcessingState_PortReconfig:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleProcessingState() Port Reconfiguration -> Sending Flush Command", iName.Str()));
// port reconfiguration is required. Only one port at a time is disabled and then re-enabled after buffer resizing
OMX_SendCommand(iOMXDecoder, 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;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleProcessingState() Port Reconfiguration -> Output Port", iName.Str()));
}
else if (iPortIndexForDynamicReconfig == iInputPortIndex)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleProcessingState() Port Reconfiguration -> Input Port", iName.Str()));
iDoNotSaveInputBuffersFlag = true;
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleProcessingState() Port Reconfiguration -> UNKNOWN PORT", iName.Str()));
//sState = OMX_StateInvalid;
ReportErrorEvent(PVMFErrResourceConfiguration);
ChangeNodeState(EPVMFNodeError);
status = PVMFFailure;
break;
}
iProcessingState = EPVMFOMXBaseDecNodeProcessingState_WaitForBufferReturn;
// fall through to the next case to check if all buffers are already back
}
case EPVMFOMXBaseDecNodeProcessingState_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, "%s::HandleProcessingState() Port Reconfiguration -> WaitForBufferReturn ", iName.Str()));
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s:: Ln %d iPortIndexForDynamicReconfig %d iNumOutstandingInputBuffers %d iNumOutstandingOutputBuffers %d", iName.Str(), __LINE__, iPortIndexForDynamicReconfig, iNumOutstandingInputBuffers , iNumOutstandingOutputBuffers));
// 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, "%s::HandleProcessingState() Port Reconfiguration -> all output buffers are back, free them", iName.Str()));
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, "%s::HandleProcessingState() Port Reconfiguration -> Cannot free output buffers ", iName.Str()));
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 != EPVMFOMXBaseDecNodeProcessingState_PortReEnable)
iProcessingState = EPVMFOMXBaseDecNodeProcessingState_WaitForPortDisable;
status = PVMFSuccess; // allow rescheduling of the node potentially
}
else
status = PVMFPending; // 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, "%s::HandleProcessingState() Port Reconfiguration -> all input buffers are back, free them", iName.Str()));
// port reconfiguration is required. Only one port at a time is disabled and then re-enabled after buffer resizing
OMX_SendCommand(iOMXDecoder, OMX_CommandPortDisable, iPortIndexForDynamicReconfig, NULL);
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, "%s::HandleProcessingState() Port Reconfiguration -> Cannot free input buffers ", iName.Str()));
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 != EPVMFOMXBaseDecNodeProcessingState_PortReEnable)
iProcessingState = EPVMFOMXBaseDecNodeProcessingState_WaitForPortDisable;
status = PVMFSuccess; // allow rescheduling of the node
}
else
status = PVMFPending; // 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;
}
#else
case EPVMFOMXBaseDecNodeProcessingState_PortReconfig:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleProcessingState() Port Reconfiguration -> Sending Flush Command", iName.Str()));
// Collect all buffers first (before starting the portDisable command)
// FIRST send a flush command. This will return all buffers from the component. Any outstanding buffers are in MIO
// Then wait for all buffers to come back from MIO. If we haven't sent port disable, we'll be able to process
// other commands in the copmponent (such as pause, stop etc.)
OMX_ERRORTYPE err = OMX_ErrorNone;
OMX_STATETYPE sState;
// first check the state (if executing or paused, continue)
err = OMX_GetState(iOMXDecoder, &sState);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::HandleProcessingState (): PortReconfig Can't get State of decoder - trying to send port flush request!", iName.Str()));
sState = OMX_StateInvalid;
ReportErrorEvent(PVMFErrResourceConfiguration);
ChangeNodeState(EPVMFNodeError);
status = PVMFFailure;
break;
}
if (((sState != OMX_StateExecuting) && (sState != OMX_StatePause)) || iStopCommandWasSentToComponent)
{
// possibly as a consequence of a previously queued cmd to go to Idle state?
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleProcessingState (): PortReconfig: Component State is not executing or paused, do not proceed with port flush", iName.Str()));
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleProcessingState (): PortReconfig Sending Flush command to component", iName.Str()));
// 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;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleProcessingState() Port Reconfiguration -> Output Port", iName.Str()));
}
else if (iPortIndexForDynamicReconfig == iInputPortIndex)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleProcessingState() Port Reconfiguration -> Input Port", iName.Str()));
iDoNotSaveInputBuffersFlag = true;
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleProcessingState() Port Reconfiguration -> UNKNOWN PORT", iName.Str()));
sState = OMX_StateInvalid;
ReportErrorEvent(PVMFErrResourceConfiguration);
ChangeNodeState(EPVMFNodeError);
status = PVMFFailure;
break;
}
// send command to flush appropriate port
err = OMX_SendCommand(iOMXDecoder, OMX_CommandFlush, iPortIndexForDynamicReconfig, NULL);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::HandleProcessingState (): PortReconfig : Can't send flush command !", iName.Str()));
sState = OMX_StateInvalid;
ReportErrorEvent(PVMFErrResourceConfiguration);
ChangeNodeState(EPVMFNodeError);
status = PVMFFailure;
break;
}
}
// now sit back and wait for buffers to return
// if there is a pause/stop cmd in the meanwhile, component will process it
// and the node will end up in pause/stop state (so this internal state does not matter)
iProcessingState = EPVMFOMXBaseDecNodeProcessingState_WaitForBufferReturn;
// fall through to the next case to check if all buffers are already back
}
case EPVMFOMXBaseDecNodeProcessingState_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, "%s::HandleProcessingState() Port Reconfiguration -> WaitForBufferReturn ", iName.Str()));
// 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, "%s::HandleProcessingState() Port Reconfiguration -> all output buffers are back, free them", iName.Str()));
// port reconfiguration is required. Only one port at a time is disabled and then re-enabled after buffer resizing
OMX_SendCommand(iOMXDecoder, OMX_CommandPortDisable, iPortIndexForDynamicReconfig, NULL);
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, "%s::HandleProcessingState() Port Reconfiguration -> Cannot free output buffers ", iName.Str()));
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 != EPVMFOMXBaseDecNodeProcessingState_PortReEnable)
iProcessingState = EPVMFOMXBaseDecNodeProcessingState_WaitForPortDisable;
status = PVMFSuccess; // allow rescheduling of the node potentially
}
else
status = PVMFPending; // 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, "%s::HandleProcessingState() Port Reconfiguration -> all input buffers are back, free them", iName.Str()));
// port reconfiguration is required. Only one port at a time is disabled and then re-enabled after buffer resizing
OMX_SendCommand(iOMXDecoder, OMX_CommandPortDisable, iPortIndexForDynamicReconfig, NULL);
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, "%s::HandleProcessingState() Port Reconfiguration -> Cannot free input buffers ", iName.Str()));
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 != EPVMFOMXBaseDecNodeProcessingState_PortReEnable)
iProcessingState = EPVMFOMXBaseDecNodeProcessingState_WaitForPortDisable;
status = PVMFSuccess; // allow rescheduling of the node
}
else
status = PVMFPending; // 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;
}
#endif //QCOM WORKAROUND JJDBG
case EPVMFOMXBaseDecNodeProcessingState_WaitForPortDisable:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleProcessingState() Port Reconfiguration -> wait for port disable callback", iName.Str()));
// do nothing. Just wait for the port to become disabled (we'll get event from component, which will
// transition the state to PortReEnable
status = PVMFPending; // prevent Rescheduling the node
break;
}
case EPVMFOMXBaseDecNodeProcessingState_PortReEnable:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleProcessingState() Port Reconfiguration -> Sending reenable port command", iName.Str()));
status = HandlePortReEnable();
break;
}
case EPVMFOMXBaseDecNodeProcessingState_WaitForPortEnable:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleProcessingState() Port Reconfiguration -> wait for port enable callback", iName.Str()));
// do nothing. Just wait for the port to become enabled (we'll get event from component, which will
// transition the state to ReadyToDecode
status = PVMFPending; // prevent ReScheduling
break;
}
// NORMAL DATA FLOW STATE:
case EPVMFOMXBaseDecNodeProcessingState_ReadyToDecode:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleProcessingState() Ready To Decode start", iName.Str()));
// In normal data flow and decoding state
// Send all available output buffers to the decoder
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, "%s::HandleProcessingState() Sending previous - partially consumed input back to the OMX component", iName.Str()));
OMX_EmptyThisBuffer(iOMXDecoder, 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 EPVMFOMXBaseDecNodeProcessingState_Stopping:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleProcessingState() Stopping -> wait for Component to move from Executing->Idle", iName.Str()));
status = PVMFPending; // prevent rescheduling
break;
}
case EPVMFOMXBaseDecNodeProcessingState_Pausing:
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleProcessingState() Pausing -> wait for Component to move from Executing->Pause", iName.Str()));
status = PVMFPending; // prevent rescheduling
break;
}
case EPVMFOMXBaseDecNodeProcessingState_WaitForOutgoingQueue:
status = PVMFPending;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::HandleProcessingState() Do nothing since waiting for output port queue to become available", iName.Str()));
break;
default:
break;
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::HandleProcessingState() Out", iName.Str()));
return status;
}
/////////////////////////////////////////////////////////////////////////////
bool PVMFOMXBaseDecNode::SendOutputBufferToOMXComponent()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendOutputBufferToOMXComponent() In", iName.Str()));
OutputBufCtrlStruct *output_buf = NULL;
int32 errcode = OsclErrNone;
uint32 ii;
// try to get output buffer header
OSCL_TRY(errcode, output_buf = (OutputBufCtrlStruct *) iOutBufMemoryPool->allocate(iOutputAllocSize));
if (OsclErrNone != errcode)
{
if (OsclErrNoResources == errcode)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger,
PVLOGMSG_DEBUG, (0, "%s::SendOutputBufferToOMXComponent() No more output buffers in the mempool", iName.Str()));
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, "%s::SendOutputBufferToOMXComponent() Output mempool error", iName.Str()));
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(iOMXDecoder, output_buf->pBufHdr);
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendOutputBufferToOMXComponent() Out", iName.Str()));
return true;
}
////////////////////////////////////////////////////////////////////////////////
bool PVMFOMXBaseDecNode::SetDefaultCapabilityFlags()
{
iIsOMXComponentMultiThreaded = true;
iOMXComponentSupportsExternalOutputBufferAlloc = false;
iOMXComponentSupportsExternalInputBufferAlloc = false;
iOMXComponentSupportsMovableInputBuffers = false;
iOMXComponentUsesNALStartCodes = true;
iOMXComponentSupportsPartialFrames = false;
iOMXComponentCanHandleIncompleteFrames = true;
iOMXComponentUsesFullAVCFrames = false;
return true;
}
bool PVMFOMXBaseDecNode::SendEOSBufferToOMXComponent()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendEOSBufferToOMXComponent() In", iName.Str()));
// first of all, check if the component is running. EOS could be sent prior to component/decoder
// even being initialized
// returning false will ensure that the EOS will be sent downstream anyway without waiting for the
// Component to respond
if (iCurrentDecoderState != OMX_StateExecuting)
return false;
// get an input buffer. Without a buffer, no point in proceeding
InputBufCtrlStruct *input_buf = NULL;
int32 errcode = OsclErrNone;
// 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 (OsclErrNone != errcode)
{
if (OsclErrNoResources == errcode)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger,
PVLOGMSG_DEBUG, (0, "%s::SendEOSBufferToOMXComponent() No more buffers in the mempool - unexpected", iName.Str()));
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, "%s::SendEOSBufferToOMXComponent() Input mempool error", iName.Str()));
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(iOMXDecoder, input_buf->pBufHdr);
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendEOSBufferToOMXComponent() Out", iName.Str()));
return true;
}
// this method is called under certain conditions only if the node is doing partial frame assembly
OSCL_EXPORT_REF void PVMFOMXBaseDecNode::DropCurrentBufferUnderConstruction()
{
if (iObtainNewInputBuffer == false)
{
if (iInputBufferUnderConstruction != NULL)
{
if (iInBufMemoryPool != NULL)
{
iInBufMemoryPool->deallocate((OsclAny *)iInputBufferUnderConstruction);
}
iInputBufferUnderConstruction = NULL;
}
iObtainNewInputBuffer = true;
}
}
// this method is called under certain conditions only if the node is doing partial frame assembly
OSCL_EXPORT_REF void PVMFOMXBaseDecNode::SendIncompleteBufferUnderConstruction()
{
// this should never be the case, but check anyway
if (iInputBufferUnderConstruction != NULL)
{
// mark as end of frame (the actual end piece is missing)
iInputBufferUnderConstruction->pBufHdr->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendIncompleteBufferUnderConstruction() - Sending Incomplete Buffer 0x%x to OMX Component MARKER field set to %x, TS=%d, Ticks=%L", iName.Str(), iInputBufferUnderConstruction->pBufHdr->pBuffer, iInputBufferUnderConstruction->pBufHdr->nFlags, iInTimestamp, iOMXTicksTimestamp));
OMX_EmptyThisBuffer(iOMXDecoder, iInputBufferUnderConstruction->pBufHdr);
iInputBufferUnderConstruction = NULL;
iObtainNewInputBuffer = true;
}
}
OSCL_EXPORT_REF bool PVMFOMXBaseDecNode::SendInputBufferToOMXComponent()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() In", iName.Str()));
// first need to take care of missing packets if node is assembling partial frames.
// The action depends whether the component (I) can handle incomplete frames/NALs or (II) cannot handle incomplete frames/NALs
if (!iOMXComponentSupportsPartialFrames)
{
// there are 4 cases after receiving a media msg and realizing there were missing packet(s):
// a) TS remains the same - i.e. missing 1 or more pieces in the middle of the same frame
// I) basically ignore - keep assembling the same frame (middle will be missing)
// II) drop current buffer, drop msgs until next msg with marker bit arrives
// b) TS is different than previous frame. Previous frame was sent OK (had marker bit).
// New frame assembly has not started yet. one or more pieces are missing from
// the beginning of the frame
// I) basically ignore - get a new buffer and start assembling new frame (beginning will be missing)
// II) no buffer to drop, but keep dropping msgs until next msg with marker bit arrives
// c) TS is different than previous frame. Frame assembly has started (we were in the middle of a frame)
// but only 1 piece is missing => We know that the missing frame must have had the marker bit
// I) send out current buffer (last piece will be missing), get a new buffer and start assembling new frame (which is OK)
// II) just drop current buffer. Get a new buffer and start assembling new frame (no need to wait for marker bit)
// d) TS is different than previous frame. Frame assembly has started ( we were in the middle of a frame)
// multiple pieces are missing => The last piece of the frame with the marker bit is missing for sure, but
// there could be also other frames missing or the beginning of the next frame is missing etc.
// I) send out current bufer (last piece will be missing). Get a new buffer and start assembling new frame (beginning COULD BE missing as well)
// II) drop current buffer. Keep dropping msgs until next msg with marker bit arrives
// extract info from the media message
uint32 current_msg_seq_num = iDataIn->getSeqNum();
uint32 current_msg_ts = iDataIn->getTimestamp();
uint32 current_msg_marker;
if (iSetMarkerBitForEveryFrag == true) // PV AVC case
{
current_msg_marker = iDataIn->getMarkerInfo() & PVMF_MEDIA_DATA_MARKER_INFO_END_OF_NAL_BIT;
current_msg_marker |= iDataIn->getMarkerInfo() & PVMF_MEDIA_DATA_MARKER_INFO_M_BIT;
}
else
{
current_msg_marker = iDataIn->getMarkerInfo() & PVMF_MEDIA_DATA_MARKER_INFO_M_BIT;
}
//Force marker bit for AMR streaming formats (marker bit may not be set even though full frames are present)
if (iInPort && (
(((PVMFOMXDecPort*)iInPort)->iFormat == PVMF_MIME_AMR) ||
(((PVMFOMXDecPort*)iInPort)->iFormat == PVMF_MIME_AMRWB)
))
{
// FIXME: This could have unintended side effects if other bits in this value are used in the future
current_msg_marker = PVMF_MEDIA_DATA_MARKER_INFO_M_BIT;
}
// check if this is the very first data msg
if (iFirstDataMsgAfterBOS)
{
iFirstDataMsgAfterBOS = false;
//init the sequence number & ts to make sure dropping logic does not kick in
iInPacketSeqNum = current_msg_seq_num - 1;
iInTimestamp = current_msg_ts - 10;
}
// first check if we need to keep dropping msgs
if (iKeepDroppingMsgsUntilMarkerBit)
{
// drop this message
iDataIn.Unbind();
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() Dropping input msg with seqnum %d until marker bit", iName.Str(), current_msg_seq_num));
//if msg has marker bit, stop dropping msgs
if ((current_msg_marker != 0 && !iOMXComponentUsesFullAVCFrames) || // frame or NAL boundaries
((current_msg_marker & PVMF_MEDIA_DATA_MARKER_INFO_M_BIT) && iOMXComponentUsesFullAVCFrames)) // only frame boundaries
{
iKeepDroppingMsgsUntilMarkerBit = false;
// also remember the sequence number & timestamp so that we have reference
iInPacketSeqNum = current_msg_seq_num;
iInTimestamp = current_msg_ts;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() Input msg with seqnum %d has marker bit set. Stop dropping msgs", iName.Str(), current_msg_seq_num));
}
return true;
}
// is there something missing?
// compare current and saved sequence number - difference should be exactly 1
// if it is more, there is something missing
if ((current_msg_seq_num - iInPacketSeqNum) > 1)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - MISSING PACKET DETECTED. Input msg with seqnum %d, TS=%d. Previous seqnum: %d, Previous TS: %d", iName.Str(), current_msg_seq_num, iInPacketSeqNum, current_msg_ts, iInTimestamp));
// find out which case it is by comparing TS
if (current_msg_ts == iInTimestamp)
{
// this is CASE a)
// same ts, i.e. pieces are missing from the middle of the current frame
if (!iOMXComponentCanHandleIncompleteFrames)
{
// drop current buffer, drop msgs until you hit msg with marker bit
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - Drop current buffer under construction. Keep dropping msgs until marker bit", iName.Str()));
DropCurrentBufferUnderConstruction();
iKeepDroppingMsgsUntilMarkerBit = true;
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - Continue processing", iName.Str()));
}
}
else // new ts and old ts are different
{
// are we at the beginning of the new frame assembly?
if (iObtainNewInputBuffer)
{
// CASE b)
// i.e. we sent out previous frame, but have not started assembling a new frame. Pieces are missing from the beginning
if (!iOMXComponentCanHandleIncompleteFrames)
{
// there is no current buffer to drop, but drop msgs until you hit msg with marker bit
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - No current buffer under construction. Keep dropping msgs until marker bit", iName.Str()));
iKeepDroppingMsgsUntilMarkerBit = true;
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - Continue processing", iName.Str()));
}
}
else // no, we are in the middle of a frame assembly, but new ts is different
{
// is only 1 msg missing?
if ((current_msg_seq_num - iInPacketSeqNum) == 2)
{
// CASE c)
// only the last piece of the previous frame is missing
if (iOMXComponentCanHandleIncompleteFrames)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - Send incomplete buffer under construction. Start assembling new frame", iName.Str()));
SendIncompleteBufferUnderConstruction();
}
else
{
// drop current frame only, but no need to wait until next marker bit.
// start assembling new frame
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - Drop current buffer under construction. It's OK to start assembling new frame. Only 1 packet is missing", iName.Str()));
DropCurrentBufferUnderConstruction();
}
}
else
{
// CASE d)
// (multiple) final piece(s) of the previous frame are missing and possibly pieces at the
// beginning of a new frame are also missing
if (iOMXComponentCanHandleIncompleteFrames)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - Send incomplete buffer under construction. Start assembling new frame (potentially damaged)", iName.Str()));
SendIncompleteBufferUnderConstruction();
}
else
{
// drop current frame. start assembling new frame, but first keep dropping
// until you hit msg with marker bit.
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - Drop current buffer under construction. Keep dropping msgs until marker bit", iName.Str()));
DropCurrentBufferUnderConstruction();
iKeepDroppingMsgsUntilMarkerBit = true;
}
}
}// end of if(obtainNewInputBuffer)/else
}// end of if(curr_msg_ts == iInTimestamp)
}//end of if(deltaseqnum>1)/else
// check if we need to keep dropping msgs
if (iKeepDroppingMsgsUntilMarkerBit)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() Dropping input msg with seqnum %d until marker bit", iName.Str(), current_msg_seq_num));
// drop this message
iDataIn.Unbind();
//if msg has marker bit, stop dropping msgs
if ((current_msg_marker != 0 && !iOMXComponentUsesFullAVCFrames) || // frame or NAL boundaries
((current_msg_marker & PVMF_MEDIA_DATA_MARKER_INFO_M_BIT) && iOMXComponentUsesFullAVCFrames)) // only frame boundaries
{
iKeepDroppingMsgsUntilMarkerBit = false;
// also remember the sequence number & timestamp so that we have reference
iInPacketSeqNum = current_msg_seq_num;
iInTimestamp = current_msg_ts;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() Input msg with seqnum %d has marker bit set. Stop dropping msgs", iName.Str(), current_msg_seq_num));
}
return true;
}
}// end of if/else (iOMXSUpportsPartialFrames)
InputBufCtrlStruct *input_buf = NULL;
int32 errcode = OsclErrNone;
uint32 ii;
// NOTE: a) if NAL start codes must be inserted i.e. iOMXComponentUsesNALStartCodess is TRUE, then iOMXComponentSupportsMovableInputBuffers must be set to FALSE.
// b) if iOMXComponentSupportsPartialFrames is FALSE, then iOMXComponentSupportsMovableInputBuffers must be FALSE as well
// c) if iOMXCOmponentSupportsPartialFrames is FALSE, and the input frame/NAL size is larger than the buffer size, the frame/NAL is discarded
do
{
// do loop to loop over all fragments
// first of all , get an input buffer. Without a buffer, no point in proceeding
if (iObtainNewInputBuffer == true) // if partial frames are being reconstructed, we may be copying data into
//existing buffer, so we don't need the new buffer
{
// try to get input buffer header
OsclAny* temp;
errcode = AllocateChunkFromMemPool(temp, iInBufMemoryPool, iInputAllocSize);
input_buf = (InputBufCtrlStruct*) temp;
if (OsclErrNone != errcode)
{
if (OsclErrNoResources == errcode)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger,
PVLOGMSG_DEBUG, (0, "%s::SendInputBufferToOMXComponent() No more buffers in the mempool", iName.Str()));
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, "%s::SendInputBufferToOMXComponent() Input mempool error", iName.Str()));
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++;
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
input_buf->pBufHdr->nFilledLen = 0; // init this for now
// save this in a class member
iInputBufferUnderConstruction = input_buf;
// set flags
if (iOMXComponentSupportsPartialFrames == true)
{
// if partial frames can be sent, then send them
// but we'll always need the new buffer for the new fragment
iObtainNewInputBuffer = true;
}
else
{
// if we need to assemble partial frames, then obtain a new buffer
// only after assembling the partial frame
iObtainNewInputBuffer = false;
}
if (iOMXComponentUsesFullAVCFrames)
{
// reset NAL counters
oscl_memset(iNALSizeArray, 0, sizeof(uint32) * iNALCount);
iNALCount = 0;
}
iIncompleteFrame = false;
iFirstPieceOfPartialFrame = true;
}
else
{
input_buf = iInputBufferUnderConstruction;
}
// When copying content, a special case is when the input fragment is larger than the buffer and has to
// be fragmented here and broken over 2 or more buffers. Potential problem with available buffers etc.
// 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();
if (iSetMarkerBitForEveryFrag == true) // PV AVC case
{
iCurrentMsgMarkerBit = iDataIn->getMarkerInfo() & PVMF_MEDIA_DATA_MARKER_INFO_END_OF_NAL_BIT;
iCurrentMsgMarkerBit |= iDataIn->getMarkerInfo() & PVMF_MEDIA_DATA_MARKER_INFO_M_BIT;
}
else
{
iCurrentMsgMarkerBit = iDataIn->getMarkerInfo() & PVMF_MEDIA_DATA_MARKER_INFO_M_BIT;
}
//Force marker bit for AMR streaming formats (marker bit may not be set even though full frames are present)
if (iInPort && (
(((PVMFOMXDecPort*)iInPort)->iFormat == PVMF_MIME_AMR) ||
(((PVMFOMXDecPort*)iInPort)->iFormat == PVMF_MIME_AMRWB)
))
{
iCurrentMsgMarkerBit = PVMF_MEDIA_DATA_MARKER_INFO_M_BIT;
}
// logging info:
if (iDataIn->getNumFragments() > 1)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - New msg has MULTI-FRAGMENTS", iName.Str()));
}
if (!(iDataIn->getMarkerInfo() & PVMF_MEDIA_DATA_MARKER_INFO_M_BIT) && !(iDataIn->getMarkerInfo() & PVMF_MEDIA_DATA_MARKER_INFO_END_OF_NAL_BIT))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - New msg has NO MARKER BIT", iName.Str()));
}
}
// 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();
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - Buffer 0x%x of size %d, %d frag out of tot. %d, TS=%d", iName.Str(), input_buf->pBufHdr->pBuffer, frag.getMemFragSize(), iCurrFragNum + 1, iDataIn->getNumFragments(), iInTimestamp));
iCurrFragNum++; // increment fragment number and move on to the next
iIsNewDataFragment = true; // update the flag
}
else
{
// in this case, no need to use input msg refcounter, each buffer fragment is copied over and treated separately
(input_buf->pMediaData).Unbind();
if (iOMXComponentUsesNALStartCodes == true && iFirstPieceOfPartialFrame == true)
{
oscl_memcpy(input_buf->pBufHdr->pBuffer + input_buf->pBufHdr->nFilledLen,
(void *) NAL_START_CODE,
NAL_START_CODE_SIZE);
input_buf->pBufHdr->nFilledLen += NAL_START_CODE_SIZE;
iFirstPieceOfPartialFrame = false;
}
// is this a new data fragment or are we still working on separating the old one?
if (iIsNewDataFragment == true)
{
// if fragment size is larger than the buffer size,
// need to break up the fragment even further into smaller chunks
// init variables needed for fragment separation
iCopyPosition = 0;
iFragmentSizeRemainingToCopy = frag.getMemFragSize();
}
// can the remaining fragment fit into the buffer?
uint32 bytes_remaining_in_buffer;
if (iOMXComponentUsesFullAVCFrames && !iOMXComponentUsesNALStartCodes)
{
// need to keep to account the extra data appended at the end of the buffer
int32 temp = (input_buf->pBufHdr->nAllocLen - input_buf->pBufHdr->nFilledLen - (20 + 4 * (iNALCount + 1) + 20 + 6));//(sizeOfExtraDataStruct_NAL + sizeOfExTraData + sizeOfExtraDataStruct_terminator + padding);
bytes_remaining_in_buffer = (uint32)((temp < 0) ? 0 : temp);
}
else
{
bytes_remaining_in_buffer = (input_buf->pBufHdr->nAllocLen - input_buf->pBufHdr->nFilledLen);
}
if (iFragmentSizeRemainingToCopy <= bytes_remaining_in_buffer)
{
oscl_memcpy(input_buf->pBufHdr->pBuffer + input_buf->pBufHdr->nFilledLen,
(void *)((uint8 *)frag.getMemFragPtr() + iCopyPosition),
iFragmentSizeRemainingToCopy);
input_buf->pBufHdr->nFilledLen += iFragmentSizeRemainingToCopy;
if (iOMXComponentUsesFullAVCFrames)
{
iNALSizeArray[iNALCount] += iFragmentSizeRemainingToCopy;
if ((iCurrentMsgMarkerBit & PVMF_MEDIA_DATA_MARKER_INFO_END_OF_NAL_BIT) &&
(1 == iDataIn->getNumFragments()))
{
// streaming case (and 1 nal per frame file format case)
iNALCount++;
// we have a full NAL now, so insert a start code (if it needs it) for the next NAL, the next time through the loop
iFirstPieceOfPartialFrame = true;
}
else if (iDataIn->getNumFragments() > 1)
{
// multiple nals per frame file format case
iNALCount = iCurrFragNum + 1;
// we have a full NAL now, so insert a start code for the next NAL, the next time through the loop
iFirstPieceOfPartialFrame = true;
}
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - Copied %d bytes of fragment %d out of %d into buffer 0x%x of size %d, TS=%d ", iName.Str(), iFragmentSizeRemainingToCopy, iCurrFragNum + 1, iDataIn->getNumFragments(), input_buf->pBufHdr->pBuffer, input_buf->pBufHdr->nFilledLen, iInTimestamp));
iCopyPosition += iFragmentSizeRemainingToCopy;
iFragmentSizeRemainingToCopy = 0;
iIsNewDataFragment = true; // done with this fragment. Get a new one
iCurrFragNum++;
}
else
{
// copy as much as you can of the current fragment into the current buffer
if (bytes_remaining_in_buffer > 0)
{
oscl_memcpy(input_buf->pBufHdr->pBuffer + input_buf->pBufHdr->nFilledLen,
(void *)((uint8 *)frag.getMemFragPtr() + iCopyPosition),
bytes_remaining_in_buffer);
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - Copied %d bytes of fragment %d out of %d into buffer 0x%x of size %d, TS=%d", iName.Str(), bytes_remaining_in_buffer, iCurrFragNum + 1, iDataIn->getNumFragments(), input_buf->pBufHdr->pBuffer, input_buf->pBufHdr->nFilledLen, iInTimestamp));
}
input_buf->pBufHdr->nFilledLen += bytes_remaining_in_buffer;
if (iOMXComponentUsesFullAVCFrames && (bytes_remaining_in_buffer > 0))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - Reconstructing partial frame (iOMXComponentUsesFullAVCFrames) - more data cannot fit in buffer 0x%x, TS=%d.Skipping data.", iName.Str(), input_buf->pBufHdr->pBuffer, iInTimestamp));
iNALSizeArray[iNALCount] += bytes_remaining_in_buffer;
// increment NAL count regardless if market bit is present or not since it is a fragment
iNALCount++;
}
iCopyPosition += bytes_remaining_in_buffer; // move current position within fragment forward
iFragmentSizeRemainingToCopy -= bytes_remaining_in_buffer;
iIncompleteFrame = true;
iIsNewDataFragment = false; // set the flag to indicate we're still working on the "old" fragment
if (!iOMXComponentSupportsPartialFrames)
{
// if partial frames are not supported, and data cannot fit into the buffer, i.e. the buffer is full at this point
// simply go through remaining fragments if they exist and "drop" them
// i.e. send what data is alrady copied in the buffer and ingore the rest
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - Reconstructing partial frame - more data cannot fit in buffer 0x%x, TS=%d.Skipping data.", iName.Str(), input_buf->pBufHdr->pBuffer, iInTimestamp));
iIsNewDataFragment = true; // done with this fragment, get a new one
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 marker bit on or off
// Audio:
// a) AAC - file playback - each fragment is a complete frame (1 msg may contain multiple fragments/frames)
// AAC - streaming - 1 msg may contain a partial frame, but LATM parser will assemble a full frame
// (when LATM parser is done, we attach a marker bit to the data it produces)
// b) AMR - file playback - each msg is N whole frames (marker bit is always set)
// AMR - streaming - each msg is N whole frames (marker bit is missing from incoming msgs -set it here)
// c) MP3 - file playback - 1 msg is N whole frames
//
// Video:
// a) AVC - file playback - each fragment is a complete NAL (1 or more frags i.e. NALs per msg)
// AVC - streaming - 1 msg contains 1 full NAL or a portion of a NAL
// NAL may be broken up over multiple msgs. Frags are not allowed in streaming
// b) M4V - file playback - each msg is 1 frame
// M4V - streaming - 1 frame may be broken up into multiple messages and fragments
// c) WMV - file playback - 1 frame is 1 msg
// WMV - streaming - 1 frame may be broken up into multiple messages and fragments
if (iSetMarkerBitForEveryFrag == true)
{
if (iIsNewDataFragment)
{
if ((iDataIn->getNumFragments() > 1))
{
// if more than 1 fragment in the message and we have not broken it up
//(i.e. this is the last piece of a broken up piece), put marker bit on it unconditionally
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - END OF FRAGMENT - Multifragmented msg AVC case, Buffer 0x%x MARKER bit set to 1", iName.Str(), input_buf->pBufHdr->pBuffer));
if (!iOMXComponentUsesFullAVCFrames)
{
// NAL mode, (uses OMX_BUFFERFLAG_ENDOFFRAME flag to mark end of NAL instead of end of frame)
// once NAL is complete, make sure you send it and obtain new buffer
input_buf->pBufHdr->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
iObtainNewInputBuffer = true;
}
else if (iCurrentMsgMarkerBit & PVMF_MEDIA_DATA_MARKER_INFO_M_BIT)
{
// frame mode (send out full AVC frames)
if (iCurrFragNum == iDataIn->getNumFragments())
{
input_buf->pBufHdr->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
iObtainNewInputBuffer = true;
}
}
}
else if ((iDataIn->getNumFragments() == 1))
{
// this is (the last piece of broken up by us) single-fragmented message. This can be a piece of a NAL (streaming) or a full NAL (file )
// apply marker bit if the message carries one
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - END OF FRAGMENT - Buffer 0x%x MARKER bit set to %d", iName.Str(), input_buf->pBufHdr->pBuffer, iCurrentMsgMarkerBit));
// if either PVMF_MEDIA_DATA_MARKER_INFO_END_OF_NAL_BIT or PVMF_MEDIA_DATA_MARKER_INFO_M_BIT
// and we're not in "frame" mode, then set OMX_BUFFERFLAG_ENDOFFRAME
if (iCurrentMsgMarkerBit && !iOMXComponentUsesFullAVCFrames)
{
// NAL mode, (uses OMX_BUFFERFLAG_ENDOFFRAME flag to mark end of NAL instead of end of frame)
// once NAL is complete, make sure you send it and obtain new buffer
input_buf->pBufHdr->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
iObtainNewInputBuffer = true;
}
else if (iCurrentMsgMarkerBit & PVMF_MEDIA_DATA_MARKER_INFO_M_BIT)
{
// frame mode
input_buf->pBufHdr->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
iObtainNewInputBuffer = true;
}
}
}
else
{
// we are separating fragments that are too big, i.e. bigger than
// what 1 buffer can hold, this fragment Can NEVER have marker bit
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - NOT END OF FRAGMENT - Buffer 0x%x MARKER bit set to 0", iName.Str(), input_buf->pBufHdr->pBuffer));
}
}
else
{
// "normal" case, i.e. only fragments at ends of msgs may have marker bit set
// fragments in the middle of a message never have marker bit set
// there is also a (slight) possibility we broke up the fragment into more fragments
// because they can't fit into input buffer. In this case, make sure you apply
// the marker bit (if necessary) only to the very last piece of the very last fragment
// for all other cases, clear the marker bit flag for the buffer
if ((iCurrFragNum == iDataIn->getNumFragments()) && iIsNewDataFragment)
{
// if all the fragments have been exhausted, and this is the last piece
// of the (possibly broken up) last fragment
// use the marker bit from the end of message
if (iCurrentMsgMarkerBit)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - END OF MESSAGE - Buffer 0x%x MARKER bit set to 1, TS=%d, Ticks=%L", iName.Str(), input_buf->pBufHdr->pBuffer, iInTimestamp, iOMXTicksTimestamp));
input_buf->pBufHdr->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
// once frame is complete, make sure you send it and obtain new buffer
iObtainNewInputBuffer = true;
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - END OF MESSAGE - Buffer 0x%x MARKER bit set to 0, TS=%d, Ticks=%L", iName.Str(), input_buf->pBufHdr->pBuffer, iInTimestamp, iOMXTicksTimestamp));
}
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - NOT END OF MESSAGE - Buffer 0x%x MARKER bit set to 0, TS=%d, Ticks=%L", iName.Str(), input_buf->pBufHdr->pBuffer, iInTimestamp, iOMXTicksTimestamp));
}
}// end of else(setmarkerbitforeveryfrag)
// 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;
if (iObtainNewInputBuffer == true)
{
// if partial frames are supported, this flag will always be set
// if partial frames are not supported, this flag will be set only
// if the partial frame/NAL has been assembled, so we can send it
// if incomplete frames are not supported then let go of this buffer, and move on
if (iIncompleteFrame && !iOMXComponentCanHandleIncompleteFrames)
{
DropCurrentBufferUnderConstruction();
}
else
{
// append extra data for "frame" mode
if (iOMXComponentUsesFullAVCFrames && !iOMXComponentUsesNALStartCodes)
{
if (!AppendExtraDataToBuffer(input_buf, (OMX_EXTRADATATYPE) OMX_ExtraDataNALSizeArray, (uint8*) iNALSizeArray, 4 * iNALCount))
{
// if AppendExtraDataToBuffer returns false, that means there wasn't enough room to write the data, so drop the buffer
DropCurrentBufferUnderConstruction();
}
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendInputBufferToOMXComponent() - Sending Buffer 0x%x to OMX Component MARKER field set to %x, TS=%d, Ticks=%L", iName.Str(), input_buf->pBufHdr->pBuffer, input_buf->pBufHdr->nFlags, iInTimestamp, iOMXTicksTimestamp));
OMX_EmptyThisBuffer(iOMXDecoder, input_buf->pBufHdr);
iInputBufferUnderConstruction = NULL; // this buffer is gone to OMX component now
}
}
// 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, "%s::SendInputBufferToOMXComponent() Out", iName.Str()));
return true;
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMFOMXBaseDecNode::AppendExtraDataToBuffer(InputBufCtrlStruct* aInputBuffer,
OMX_EXTRADATATYPE aType,
uint8* aExtraData,
uint8 aDataLength)
{
// This function is used to append AVC NAL info to the buffer using the OMX_EXTRADATA_TYPE structure, when
// a component requires buffers with full AVC frames rather than just NALs
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::AppendExtraDataToBuffer() In", iName.Str()));
if ((aType != OMX_ExtraDataNone) && (aExtraData != NULL) && (aInputBuffer->pBufHdr->pBuffer != NULL))
{
const uint32 sizeOfExtraDataStruct = 20; // 20 is the number of bytes for the OMX_OTHER_EXTRADATATYPE structure (minus the data hint member)
OMX_OTHER_EXTRADATATYPE extra;
OMX_OTHER_EXTRADATATYPE terminator;
CONFIG_SIZE_AND_VERSION(extra);
CONFIG_SIZE_AND_VERSION(terminator);
extra.nPortIndex = iInputPortIndex;
terminator.nPortIndex = iInputPortIndex;
extra.eType = aType;
extra.nSize = (sizeOfExtraDataStruct + aDataLength + 3) & ~3; // size + padding for byte alignment
extra.nDataSize = aDataLength;
// fill in fields for terminator
terminator.eType = OMX_ExtraDataNone;
terminator.nDataSize = 0;
// make sure there is enough room in the buffer
if (aInputBuffer->pBufHdr->nAllocLen < (aInputBuffer->pBufHdr->nFilledLen + sizeOfExtraDataStruct + aDataLength + terminator.nSize + 6))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::AppendExtraDataToBuffer() - Error (not enough room in buffer) appending extra data to Buffer 0x%x to OMX Component, TS=%d, Ticks=%L", iName.Str(), aInputBuffer->pBufHdr->pBuffer, iInTimestamp, iOMXTicksTimestamp));
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::AppendExtraDataToBuffer() Out", iName.Str()));
return false;
}
// copy extra data into buffer
// need to align to 4 bytes
OMX_U8* buffer = aInputBuffer->pBufHdr->pBuffer + aInputBuffer->pBufHdr->nOffset + aInputBuffer->pBufHdr->nFilledLen;
buffer = (OMX_U8*)(((OMX_U32) buffer + 3) & ~3);
oscl_memcpy(buffer, &extra, sizeOfExtraDataStruct);
oscl_memcpy(buffer + sizeOfExtraDataStruct, aExtraData, aDataLength);
buffer += extra.nSize;
oscl_memcpy(buffer, &terminator, terminator.nSize);
// flag buffer
aInputBuffer->pBufHdr->nFlags |= OMX_BUFFERFLAG_EXTRADATA;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::AppendExtraDataToBuffer() - Appending extra data to Buffer 0x%x to OMX Component, TS=%d, Ticks=%L", iName.Str(), aInputBuffer->pBufHdr->pBuffer, iInTimestamp, iOMXTicksTimestamp));
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::AppendExtraDataToBuffer() Out", iName.Str()));
return true;
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::AppendExtraDataToBuffer() Out", iName.Str()));
return false;
}
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMFOMXBaseDecNode::SendConfigBufferToOMXComponent(uint8 *initbuffer, uint32 initbufsize)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendConfigBufferToOMXComponent() In", iName.Str()));
// first of all , get an input buffer. Without a buffer, no point in proceeding
InputBufCtrlStruct *input_buf = NULL;
int32 errcode = OsclErrNone;
// try to get input buffer header
OSCL_TRY(errcode, input_buf = (InputBufCtrlStruct *) iInBufMemoryPool->allocate(iInputAllocSize));
if (OsclErrNone != errcode)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::SendConfigBufferToOMXComponent() Input buffer mempool problem -unexpected at init", iName.Str()));
return false;
}
// Got a buffer OK
// keep track of buffers. When buffer is deallocated/released, the counter will be decremented
iInBufMemoryPool->notifyfreechunkavailable(*this, (OsclAny*) iInBufMemoryPool);
iNumOutstandingInputBuffers++;
input_buf->pBufHdr->nFilledLen = 0; //init this to 0
// 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
// When copying content, a special case is when the input fragment is larger than the buffer and has to
// be fragmented here and broken over 2 or more buffers. Potential problem with available buffers etc.
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();
if (!(iDataIn->getMarkerInfo() & PVMF_MEDIA_DATA_MARKER_INFO_M_BIT))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendConfigBufferToOMXComponent() - New msg has NO MARKER BIT", iName.Str()));
}
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 = initbuffer;
input_buf->pBufHdr->nFilledLen = initbufsize;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendConfigBufferToOMXComponent() - Config Buffer 0x%x of size %d", iName.Str(), initbuffer, initbufsize));
}
else
{
// in this case, no need to use input msg refcounter, each buffer fragment is copied over and treated separately
(input_buf->pMediaData).Unbind();
// we assume the buffer is large enough to fit the config data
iCopyPosition = 0;
iFragmentSizeRemainingToCopy = initbufsize;
if (iOMXComponentUsesNALStartCodes == true)
{
oscl_memcpy(input_buf->pBufHdr->pBuffer,
(void *) NAL_START_CODE,
NAL_START_CODE_SIZE);
input_buf->pBufHdr->nFilledLen += NAL_START_CODE_SIZE;
}
// can the remaining fragment fit into the buffer?
uint32 bytes_remaining_in_buffer = (input_buf->pBufHdr->nAllocLen - input_buf->pBufHdr->nFilledLen);
if (iFragmentSizeRemainingToCopy <= bytes_remaining_in_buffer)
{
oscl_memcpy(input_buf->pBufHdr->pBuffer + input_buf->pBufHdr->nFilledLen,
(void *)(initbuffer + iCopyPosition),
iFragmentSizeRemainingToCopy);
input_buf->pBufHdr->nFilledLen += iFragmentSizeRemainingToCopy;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendConfigBufferToOMXComponent() - Copied %d bytes into buffer 0x%x of size %d", iName.Str(), iFragmentSizeRemainingToCopy, input_buf->pBufHdr->pBuffer, input_buf->pBufHdr->nFilledLen));
iCopyPosition += iFragmentSizeRemainingToCopy;
iFragmentSizeRemainingToCopy = 0;
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::SendConfigBufferToOMXComponent() Config buffer too large problem -unexpected at init", iName.Str()));
return false;
}
}
// 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
iOMXTicksTimestamp = ConvertTimestampIntoOMXTicks(iInputTimestampClock); // make a conversion into OMX ticks
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 marker bit on
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendConfigBufferToOMXComponent() - END OF FRAGMENT - Buffer 0x%x MARKER bit set to 1", iName.Str(), input_buf->pBufHdr->pBuffer));
input_buf->pBufHdr->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
// set buffer flag indicating buffer contains codec config data
input_buf->pBufHdr->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
OMX_EmptyThisBuffer(iOMXDecoder, input_buf->pBufHdr);
return true;
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMFOMXBaseDecNode::CreateOutMemPool(uint32 num_buffers)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::CreateOutMemPool() start", iName.Str()));
// 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, "%s::CreateOutMemPool() Allocating output buffer header pointers", iName.Str()));
iOutputAllocSize = oscl_mem_aligned_size((uint32)sizeof(OutputBufCtrlStruct));
if (iOMXComponentSupportsExternalOutputBufferAlloc)
{
// In case of an external output buffer allocator interface, output buffer memory will be allocated
// outside the node and hence iOutputAllocSize need not be incremented here
if (NULL == ipExternalOutputBufferAllocatorInterface)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::CreateOutMemPool() Allocating output buffers of size %d as well", iName.Str(), iOMXComponentOutputBufferSize));
//pre-negotiated output buffer size
iOutputAllocSize += iOMXComponentOutputBufferSize;
}
}
// for media data wrapper
if (iMediaDataMemPool)
{
iMediaDataMemPool->removeRef();
iMediaDataMemPool = NULL;
}
if (iOutBufMemoryPool)
{
iOutBufMemoryPool->removeRef();
iOutBufMemoryPool = NULL;
}
int32 leavecode = OsclErrNone;
OSCL_TRY(leavecode, iOutBufMemoryPool = OSCL_NEW(OsclMemPoolFixedChunkAllocator, (num_buffers)););
if (leavecode || iOutBufMemoryPool == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger,
PVLOGMSG_ERR, (0, "%s::CreateOutMemPool() Memory pool structure for output buffers failed to allocate", iName.Str()));
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 = OsclErrNone;
OSCL_TRY(leavecode, dummy_alloc = iOutBufMemoryPool->allocate(iOutputAllocSize));
if (leavecode || dummy_alloc == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger,
PVLOGMSG_ERR, (0, "%s::CreateOutMemPool() Memory pool for output buffers failed to allocate", iName.Str()));
return false;
}
iOutBufMemoryPool->deallocate(dummy_alloc);
// init the counter
iNumOutstandingOutputBuffers = 0;
// allocate mempool for media data message wrapper
leavecode = OsclErrNone;
OSCL_TRY(leavecode, iMediaDataMemPool = OSCL_NEW(OsclMemPoolFixedChunkAllocator, (num_buffers, PVOMXBASEDEC_MEDIADATA_CHUNKSIZE)));
if (leavecode || iMediaDataMemPool == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "%s::CreateOutMemPool() Media Data Buffer pool for output buffers failed to allocate", iName.Str()));
return false;
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::CreateOutMemPool() done", iName.Str()));
return true;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////// Creates memory pool for input buffer management ///////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMFOMXBaseDecNode::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, "%s::CreateInputMemPool() start ", iName.Str()));
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::CreateInputMemPool() allocating buffer header pointers and shared media data ptrs ", iName.Str()));
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, "%s::CreateOutMemPool() Allocating input buffers of size %d as well", iName.Str(), iOMXComponentInputBufferSize));
iInputAllocSize += iOMXComponentInputBufferSize;
}
if (iInBufMemoryPool)
{
iInBufMemoryPool->removeRef();
iInBufMemoryPool = NULL;
}
int32 leavecode = OsclErrNone;
OSCL_TRY(leavecode, iInBufMemoryPool = OSCL_NEW(OsclMemPoolFixedChunkAllocator, (num_buffers)););
if (leavecode || iInBufMemoryPool == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger,
PVLOGMSG_ERR, (0, "%s::CreateInputMemPool() Memory pool structure for input buffers failed to allocate", iName.Str()));
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 = OsclErrNone;
OSCL_TRY(leavecode, dummy_alloc = iInBufMemoryPool->allocate(iInputAllocSize));
if (leavecode || dummy_alloc == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger,
PVLOGMSG_ERR, (0, "%s::CreateInputMemPool() Memory pool for input buffers failed to allocate", iName.Str()));
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, "%s::CreateInputMemPool() done", iName.Str()));
return true;
}
////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMFOMXBaseDecNode::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, "%s::ProvideBuffersToComponent() enter", iName.Str()));
uint32 ii = 0;
OMX_ERRORTYPE err = OMX_ErrorNone;
OsclAny **ctrl_struct_ptr = NULL; // temporary array to keep the addresses of buffer ctrl structures and buffers
ctrl_struct_ptr = (OsclAny **) oscl_malloc(aNumBuffers * sizeof(OsclAny *));
if (ctrl_struct_ptr == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::ProvideBuffersToComponent ctrl_struct_ptr == NULL", iName.Str()));
return false;
}
// 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 = OsclErrNone;
// get the address where the buf hdr ptr will be stored
errcode = AllocateChunkFromMemPool(ctrl_struct_ptr[ii], aMemPool, aAllocSize);
if ((OsclErrNone != errcode) || (ctrl_struct_ptr[ii] == NULL))
{
if (OsclErrNoResources == errcode)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::ProvideBuffersToComponent ->allocate() failed for no mempool chunk available", iName.Str()));
}
else
{
// General error
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::ProvideBuffersToComponent ->allocate() failed due to some general error", iName.Str()));
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(iOMXDecoder, // 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_ctrl_struct_ptr[ii] = ctrl_struct_ptr[ii];
in_buff_hdr_ptr[ii] = temp->pBufHdr;
}
else
{
if (ipExternalOutputBufferAllocatorInterface)
{
// Actual buffer memory will be allocated outside the node from
// an external output buffer allocator interface
uint8 *pB = (uint8*) ipFixedSizeBufferAlloc->allocate();
if (NULL == pB)
{
// error
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::ProvideBuffersToComponent ->allocate() failed due to some general error", iName.Str()));
ReportErrorEvent(PVMFFailure);
ChangeNodeState(EPVMFNodeError);
return false;
}
OutputBufCtrlStruct *temp = (OutputBufCtrlStruct *)ctrl_struct_ptr[ii];
err = OMX_UseBuffer(iOMXDecoder, // 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_ctrl_struct_ptr[ii] = ctrl_struct_ptr[ii];
out_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));
err = OMX_UseBuffer(iOMXDecoder, // 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_ctrl_struct_ptr[ii] = ctrl_struct_ptr[ii];
out_buff_hdr_ptr[ii] = temp->pBufHdr;
}
}
}
else
{
// the component must allocate its own buffers.
if (aIsThisInputBuffer)
{
InputBufCtrlStruct *temp = (InputBufCtrlStruct *) ctrl_struct_ptr[ii];
// make sure to init all this to NULL
oscl_memset(&(temp->pMediaData), 0, sizeof(PVMFSharedMediaDataPtr));
temp->pMediaData = PVMFSharedMediaDataPtr(NULL, NULL);
err = OMX_AllocateBuffer(iOMXDecoder,
&(temp->pBufHdr),
aPortIndex,
ctrl_struct_ptr[ii],
(OMX_U32)aActualBufferSize);
in_ctrl_struct_ptr[ii] = ctrl_struct_ptr[ii];
in_buff_hdr_ptr[ii] = temp->pBufHdr;
}
else
{
OutputBufCtrlStruct *temp = (OutputBufCtrlStruct *) ctrl_struct_ptr[ii];
err = OMX_AllocateBuffer(iOMXDecoder,
&(temp->pBufHdr),
aPortIndex,
ctrl_struct_ptr[ii],
(OMX_U32)aActualBufferSize);
out_ctrl_struct_ptr[ii] = ctrl_struct_ptr[ii];
out_buff_hdr_ptr[ii] = temp->pBufHdr;
}
}
if (err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::ProvideBuffersToComponent() Problem using/allocating a buffer", iName.Str()));
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]);
}
oscl_free(ctrl_struct_ptr);
// set the flags
if (aIsThisInputBuffer)
{
iInputBuffersFreed = false;
}
else
{
iOutputBuffersFreed = false;
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::ProvideBuffersToComponent() done", iName.Str()));
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool PVMFOMXBaseDecNode::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, "%s::FreeBuffersToComponent() enter", iName.Str()));
uint32 ii = 0;
OMX_ERRORTYPE err = OMX_ErrorNone;
OsclAny **ctrl_struct_ptr = NULL; // temporary array to keep the addresses of buffer ctrl structures and buffers
ctrl_struct_ptr = (OsclAny **) oscl_malloc(aNumBuffers * sizeof(OsclAny *));
if (ctrl_struct_ptr == NULL)
{
return false;
}
// Now, go through all buffers and tell component to free them
for (ii = 0; ii < aNumBuffers; ii++)
{
int32 errcode = OsclErrNone;
// get the address where the buf hdr ptr will be stored
errcode = AllocateChunkFromMemPool(ctrl_struct_ptr[ii], aMemPool, aAllocSize);
if ((OsclErrNone != errcode) || (ctrl_struct_ptr[ii] == NULL))
{
if (OsclErrNoResources == errcode)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::FreeBuffersFromComponent ->allocate() failed for no mempool chunk available", iName.Str()));
}
else
{
// General error
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::FreeBuffersFromComponent ->allocate() failed due to some general error", iName.Str()));
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];
err = OMX_FreeBuffer(iOMXDecoder,
aPortIndex,
temp->pBufHdr);
}
else
{
if (ipExternalOutputBufferAllocatorInterface)
{
//Deallocate the output buffer memory that was allocated outside the node
//using an external output buffer allocator interface
iNumOutstandingOutputBuffers++;
OutputBufCtrlStruct *temp = (OutputBufCtrlStruct *) ctrl_struct_ptr[ii];
ipFixedSizeBufferAlloc->deallocate((OsclAny*) temp->pBufHdr->pBuffer);
err = OMX_FreeBuffer(iOMXDecoder,
aPortIndex,
temp->pBufHdr);
}
else
{
iNumOutstandingOutputBuffers++;
OutputBufCtrlStruct *temp = (OutputBufCtrlStruct *) ctrl_struct_ptr[ii];
err = OMX_FreeBuffer(iOMXDecoder,
aPortIndex,
temp->pBufHdr);
}
}
if (err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::FreeBuffersFromComponent() Problem freeing a buffer", iName.Str()));
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]);
}
oscl_free(ctrl_struct_ptr);
// 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;
}
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;
if (ipExternalOutputBufferAllocatorInterface)
{
ipExternalOutputBufferAllocatorInterface->removeRef();
ipExternalOutputBufferAllocatorInterface = NULL;
}
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::FreeBuffersFromComponent() done", iName.Str()));
return true;
}
/////////////////////////////////////////////////////////////////////////////
// This function handles the event of OMX component state change
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PVMFOMXBaseDecNode::HandleComponentStateChange(OMX_U32 decoder_state)
{
switch (decoder_state)
{
case OMX_StateIdle:
{
iCurrentDecoderState = OMX_StateIdle;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleComponentStateChange: OMX_StateIdle reached", iName.Str()));
// 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 == PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_PREPARE))
{
iProcessingState = EPVMFOMXBaseDecNodeProcessingState_InitDecoder;
SetState(EPVMFNodePrepared);
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess);
RunIfNotReady();
}
else if ((iCurrentCommand.size() > 0) &&
(iCurrentCommand.front().iCmd == PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_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 == EPVMFOMXBaseDecNodeProcessingState_Stopping)
iProcessingState = EPVMFOMXBaseDecNodeProcessingState_ReadyToDecode;
// if the processing state was not stopping, leave the state as it was (continue port reconfiguration)
SetState(EPVMFNodePrepared);
iStopCommandWasSentToComponent = false;
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess);
RunIfNotReady();
}
else if ((iCurrentCommand.size() > 0) &&
(iCurrentCommand.front().iCmd == PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_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:
{
iCurrentDecoderState = OMX_StateExecuting;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleComponentStateChange: OMX_StateExecuting reached", iName.Str()));
// 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 == PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_START))
{
SetState(EPVMFNodeStarted);
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess);
RunIfNotReady();
}
break;
}//end of case OMX_StateExecuting
case OMX_StatePause:
{
iCurrentDecoderState = OMX_StatePause;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleComponentStateChange: OMX_StatePause reached", iName.Str()));
// if we are paused, we won't start until the node gets DoStart command.
// in this case, we are ready to start sending buffers
if (iProcessingState == EPVMFOMXBaseDecNodeProcessingState_Pausing)
iProcessingState = EPVMFOMXBaseDecNodeProcessingState_ReadyToDecode;
// This state can be reached going from OMX_Executing-> OMX_Pause
if ((iCurrentCommand.size() > 0) &&
(iCurrentCommand.front().iCmd == PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_PAUSE))
{
// if we are paused, we won't start until the node gets DoStart command.
// in this case, we are ready to start sending buffers
if (iProcessingState == EPVMFOMXBaseDecNodeProcessingState_Pausing)
iProcessingState = EPVMFOMXBaseDecNodeProcessingState_ReadyToDecode;
// if the processing state was not pausing, leave the state as it was (continue port reconfiguration)
SetState(EPVMFNodePaused);
iPauseCommandWasSentToComponent = false;
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess);
RunIfNotReady();
}
break;
}//end of case OMX_StatePause
case OMX_StateLoaded:
{
iCurrentDecoderState = 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, "%s::HandleComponentStateChange: OMX_StateLoaded reached", iName.Str()));
//Check if command's responce is pending
if ((iCurrentCommand.size() > 0) &&
(iCurrentCommand.front().iCmd == PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_RESET))
{
// move this here
if (iInPort)
{
OSCL_DELETE(((PVMFOMXDecPort*)iInPort));
iInPort = NULL;
}
if (iOutPort)
{
OSCL_DELETE(((PVMFOMXDecPort*)iOutPort));
iOutPort = NULL;
}
iDataIn.Unbind();
// Reset the metadata key list
iAvailableMetadataKeys.clear();
iProcessingState = EPVMFOMXBaseDecNodeProcessingState_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:
{
iCurrentDecoderState = OMX_StateInvalid;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::HandleComponentStateChange: OMX_StateInvalid reached", iName.Str()));
break;
}//end of case OMX_StateInvalid
}//end of switch(decoder_state)
}
/////////////////////////////////////////////////////////////////////////////
////////////////////// CALLBACK PROCESSING FOR EMPTY BUFFER DONE - input buffer was consumed
/////////////////////////////////////////////////////////////////////////////
OMX_ERRORTYPE PVMFOMXBaseDecNode::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, "%s::EmptyBufferDoneProcessing: In", iName.Str()));
OSCL_ASSERT((void*) aComponent == (void*) iOMXDecoder); // 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, "%s::EmptyBufferDoneProcessing: Input buffer returned non-empty with %d bytes still in it", iName.Str(), 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, "%s::EmptyBufferDoneProcessing: Release input buffer with Ticks=%d (with %d refcount remaining of input message)", iName.Str(), aBuffer->nTimeStamp, (pContext->pMediaData).get_count() - 1));
(pContext->pMediaData).Unbind();
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::EmptyBufferDoneProcessing: Release input buffer %x back to mempool - pointing to buffer %x", iName.Str(), pContext, aBuffer->pBuffer));
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 PVMFOMXBaseDecNode::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, "%s::FillBufferDoneProcessing: In", iName.Str()));
OSCL_ASSERT((void*) aComponent == (void*) iOMXDecoder); // 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, "%s::FillBufferDoneProcessing: Output buffer has EOS set", iName.Str()));
}
// 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, "%s::FillBufferDoneProcessing: Release output buffer %x back to mempool - buffer empty or not to be sent downstream", iName.Str(), pContext));
iOutBufMemoryPool->deallocate(pContext);
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::FillBufferDoneProcessing: Output frame %d received", iName.Str(), iFrameCounter++));
// get pointer to actual buffer data
uint8 *pBufdata = ((uint8*) aBuffer->pBuffer);
// move the data pointer based on offset info
pBufdata += aBuffer->nOffset;
iOutTimeStamp = ConvertOMXTicksIntoTimestamp(aBuffer->nTimeStamp);
ipPrivateData = (OsclAny *) aBuffer->pPlatformPrivate; // record the pointer
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::FillBufferDoneProcessing: Wrapping buffer %x of size %d", iName.Str(), 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> MediaDataOut = WrapOutputBuffer(pBufdata, (uint32)(aBuffer->nFilledLen), pContext);
// if you can't get the MediaDataOut, release the buffer back to the pool
if (MediaDataOut.GetRep() == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::FillBufferDoneProcessing: Problem wrapping buffer %x of size %d - releasing the buffer", iName.Str(), pBufdata, aBuffer->nFilledLen));
iOutBufMemoryPool->deallocate(pContext);
}
else
{
// if there's a problem queuing output buffer, MediaDataOut will expire at end of scope and
// release buffer back to the pool, (this should not be the case)
if (QueueOutputBuffer(MediaDataOut, aBuffer->nFilledLen))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::FillBufferDoneProcessing: Buffer %x of size %d queued - reschedule the node to send out", iName.Str(), 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, "%s::FillBufferDoneProcessing: Problem queing buffer %x of size %d - releasing the buffer", iName.Str(), pBufdata, aBuffer->nFilledLen));
}
}
}
// the OMX spec says that no error is to be returned
return OMX_ErrorNone;
}
//////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////// Attach a MediaDataImpl wrapper (refcount, deallocator etc.)
/////////////////////////////// to the output buffer /////////////////////////////////////////
OsclSharedPtr<PVMFMediaDataImpl> PVMFOMXBaseDecNode::WrapOutputBuffer(uint8 *pData, uint32 aDataLen, OsclAny *pContext)
{
// wrap output buffer into a mediadataimpl
uint32 aligned_class_size = oscl_mem_aligned_size(sizeof(PVMFSimpleMediaBuffer));
uint32 aligned_cleanup_size = oscl_mem_aligned_size(sizeof(PVOMXDecBufferSharedPtrWrapperCombinedCleanupDA));
uint32 aligned_refcnt_size = oscl_mem_aligned_size(sizeof(OsclRefCounterDA));
uint8 *my_ptr = (uint8*) oscl_malloc(aligned_refcnt_size + aligned_cleanup_size + aligned_class_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
PVOMXDecBufferSharedPtrWrapperCombinedCleanupDA *cleanup_ptr =
OSCL_PLACEMENT_NEW(my_ptr + aligned_refcnt_size, PVOMXDecBufferSharedPtrWrapperCombinedCleanupDA(iOutBufMemoryPool, pContext));
//ModifiedPvciBufferCombinedCleanup* cleanup_ptr = OSCL_PLACEMENT_NEW(my_ptr + aligned_refcnt_size,ModifiedPvciBufferCombinedCleanup(aOutput.GetRefCounter()) );
// create the ref counter after the cleanup object (refcount is set to 1 at creation)
OsclRefCounterDA *my_refcnt = OSCL_PLACEMENT_NEW(my_ptr, OsclRefCounterDA(my_ptr, cleanup_ptr));
my_ptr += aligned_refcnt_size + aligned_cleanup_size;
PVMFMediaDataImpl* media_data_ptr = OSCL_PLACEMENT_NEW(my_ptr, PVMFSimpleMediaBuffer((void *) pData, // ptr to data
aDataLen, // capacity
my_refcnt)); // ref counter
OsclSharedPtr<PVMFMediaDataImpl> MediaDataImplOut(media_data_ptr, my_refcnt);
MediaDataImplOut->setMediaFragFilledLen(0, aDataLen);
return MediaDataImplOut;
}
//////////////////////////////////////////////////////////////////////////////
bool PVMFOMXBaseDecNode::SendBeginOfMediaStreamCommand()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendBeginOfMediaStreamCommand() In", iName.Str()));
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, "%s::SendBeginOfMediaStreamCommand() Outgoing queue busy", iName.Str()));
return false;
}
iSendBOS = false;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendBeginOfMediaStreamCommand() BOS Sent StreamID %d", iName.Str(), iStreamID));
return true;
}
////////////////////////////////////
bool PVMFOMXBaseDecNode::SendEndOfTrackCommand(void)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::SendEndOfTrackCommand() In", iName.Str()));
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, "%s::SendEndOfTrackCommand() Out", iName.Str()));
return true;
}
/////////////////////////////////////////////////////////////////////////////
//The various command handlers call this routine when a command is complete.
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PVMFOMXBaseDecNode::CommandComplete(PVMFOMXBaseDecNodeCmdQ& aCmdQ, PVMFOMXBaseDecNodeCommand& aCmd, PVMFStatus aStatus, OsclAny* aEventData)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s:CommandComplete Id %d Cmd %d Status %d Context %d Data %d",
iName.Str(), 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 PVMFOMXBaseDecNode::DoInit(PVMFOMXBaseDecNodeCommand& aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::DoInit() In", iName.Str()));
switch (iInterfaceState)
{
case EPVMFNodeIdle:
{
SetState(EPVMFNodeInitialized);
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
break;
}
default:
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
break;
}
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXBaseDecNode::DoPrepare(PVMFOMXBaseDecNodeCommand& aCmd)
{
OMX_ERRORTYPE err = OMX_ErrorNone;
OMXConfigParserInputs aInputParameters;
aInputParameters.cComponentRole = NULL;
OMX_PTR aOutputParameters = NULL;
switch (iInterfaceState)
{
case EPVMFNodeInitialized:
{
if (NULL == iInPort)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "%s::DoPrepare() Input port not initialized", iName.Str()));
CommandComplete(iInputCommands, aCmd, PVMFFailure);
return;
}
// Check format of input data
PVMFFormatType format = ((PVMFOMXDecPort*)iInPort)->iFormat;
// AAC
if (format == PVMF_MIME_MPEG4_AUDIO ||
format == PVMF_MIME_3640 ||
format == PVMF_MIME_LATM ||
format == PVMF_MIME_ADIF ||
format == PVMF_MIME_ASF_MPEG4_AUDIO ||
format == PVMF_MIME_AAC_SIZEHDR)
{
aInputParameters.cComponentRole = (OMX_STRING)"audio_decoder.aac";
aOutputParameters = (AudioOMXConfigParserOutputs *)oscl_malloc(sizeof(AudioOMXConfigParserOutputs));
}
// AMR
else if (format == PVMF_MIME_AMR_IF2 ||
format == PVMF_MIME_AMR_IETF ||
format == PVMF_MIME_AMR)
{
aInputParameters.cComponentRole = (OMX_STRING)"audio_decoder.amrnb";
aOutputParameters = (AudioOMXConfigParserOutputs *)oscl_malloc(sizeof(AudioOMXConfigParserOutputs));
}
else if (format == PVMF_MIME_AMRWB_IETF ||
format == PVMF_MIME_AMRWB)
{
aInputParameters.cComponentRole = (OMX_STRING)"audio_decoder.amrwb";
aOutputParameters = (AudioOMXConfigParserOutputs *)oscl_malloc(sizeof(AudioOMXConfigParserOutputs));
}
else if (format == PVMF_MIME_MP3)
{
aInputParameters.cComponentRole = (OMX_STRING)"audio_decoder.mp3";
aOutputParameters = (AudioOMXConfigParserOutputs *)oscl_malloc(sizeof(AudioOMXConfigParserOutputs));
}
else if (format == PVMF_MIME_WMA)
{
aInputParameters.cComponentRole = (OMX_STRING)"audio_decoder.wma";
aOutputParameters = (AudioOMXConfigParserOutputs *)oscl_malloc(sizeof(AudioOMXConfigParserOutputs));
}
else if (format == PVMF_MIME_H264_VIDEO ||
format == PVMF_MIME_H264_VIDEO_MP4 ||
format == PVMF_MIME_H264_VIDEO_RAW)
{
aInputParameters.cComponentRole = (OMX_STRING)"video_decoder.avc";
aOutputParameters = (VideoOMXConfigParserOutputs *)oscl_malloc(sizeof(VideoOMXConfigParserOutputs));
}
else if (format == PVMF_MIME_M4V)
{
aInputParameters.cComponentRole = (OMX_STRING)"video_decoder.mpeg4";
aOutputParameters = (VideoOMXConfigParserOutputs *)oscl_malloc(sizeof(VideoOMXConfigParserOutputs));
}
else if (format == PVMF_MIME_H2631998 ||
format == PVMF_MIME_H2632000)
{
aInputParameters.cComponentRole = (OMX_STRING)"video_decoder.h263";
aOutputParameters = (VideoOMXConfigParserOutputs *)oscl_malloc(sizeof(VideoOMXConfigParserOutputs));
}
else if (format == PVMF_MIME_WMV)
{
aInputParameters.cComponentRole = (OMX_STRING)"video_decoder.wmv";
aOutputParameters = (VideoOMXConfigParserOutputs *)oscl_malloc(sizeof(VideoOMXConfigParserOutputs));
}
else
{
// Illegal codec specified.
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "%s::DoPrepare() Input port format other then codec type", iName.Str()));
CommandComplete(iInputCommands, aCmd, PVMFErrArgument);
return;
}
if (aOutputParameters == NULL)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::Can't allocate memory for OMXConfigParser output!", iName.Str()));
CommandComplete(iInputCommands, aCmd, PVMFErrResource);
return;
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "%s::Initializing OMX component and decoder for role %s", iName.Str(), aInputParameters.cComponentRole));
/* Set callback structure */
iCallbacks.EventHandler = CallbackEventHandler; //event_handler;
iCallbacks.EmptyBufferDone = CallbackEmptyBufferDone; //empty_buffer_done;
iCallbacks.FillBufferDone = CallbackFillBufferDone; //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_BOOL status;
OMX_U32 num_comps = 0;
OMX_STRING *CompOfRole;
OMX_S8 CompName[PV_OMX_MAX_COMPONENT_NAME_LENGTH];
//AudioOMXConfigParserOutputs aOutputParameters;
aInputParameters.inPtr = (uint8*)((PVMFOMXDecPort*)iInPort)->iTrackConfig;
aInputParameters.inBytes = (int32)((PVMFOMXDecPort*)iInPort)->iTrackConfigSize;
if (aInputParameters.inBytes == 0 || aInputParameters.inPtr == NULL)
{
if (format == PVMF_MIME_WMA ||
format == PVMF_MIME_MPEG4_AUDIO ||
format == PVMF_MIME_3640 ||
format == PVMF_MIME_LATM ||
format == PVMF_MIME_ADIF ||
format == PVMF_MIME_ASF_MPEG4_AUDIO ||
format == PVMF_MIME_AAC_SIZEHDR)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::DoPrepare() Cannot get component parameters", iName.Str()));
oscl_free(aOutputParameters);
CommandComplete(iInputCommands, aCmd, PVMFErrNoResources);
return;
}
}
// call once to find out the number of components that can fit the role
OMX_MasterGetComponentsOfRole(aInputParameters.cComponentRole, &num_comps, NULL);
uint32 ii;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "%s::DoPrepare(): There are %d components of role %s ", iName.Str(), num_comps, aInputParameters.cComponentRole));
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(aInputParameters.cComponentRole, &num_comps, (OMX_U8 **)CompOfRole);
for (ii = 0; ii < num_comps; ii++)
{
aInputParameters.cComponentName = CompOfRole[ii];
status = OMX_MasterConfigParser(&aInputParameters, aOutputParameters);
if (status == OMX_TRUE)
{
// but also needs to valid long enough to use it when getting the number of roles later on
oscl_strncpy((OMX_STRING)CompName, (OMX_STRING) CompOfRole[ii], PV_OMX_MAX_COMPONENT_NAME_LENGTH);
//JJDBG
#if 0
if ((0 == oscl_strncmp(aInputParameters.cComponentName, "OMX.qcom.video.decoder.mpeg4", PV_OMX_MAX_COMPONENT_NAME_LENGTH))
|| (0 == oscl_strncmp(aInputParameters.cComponentName, "OMX.qcom.video.decoder.h263", PV_OMX_MAX_COMPONENT_NAME_LENGTH)))
{
LOGE("%s::DoPrepare(): Cannot get component %s handle, try another component if available", iName.Str(), aInputParameters.cComponentName);
continue;
//err = OMX_ErrorUndefined ;
}
else
#endif
// try to create component
err = OMX_MasterGetHandle(&iOMXDecoder, (OMX_STRING) aInputParameters.cComponentName, (OMX_PTR) this, (OMX_CALLBACKTYPE *) & iCallbacks, bHWAccelerated);
// if successful, no need to continue
if ((err == OMX_ErrorNone) && (iOMXDecoder != NULL))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "%s::DoPrepare(): Got Component %s handle ", iName.Str(), aInputParameters.cComponentName));
break;
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "%s::DoPrepare(): Cannot get component %s handle, try another component if available", iName.Str(), aInputParameters.cComponentName));
}
}
else
{
status = OMX_FALSE;
}
}
// 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) || (iOMXDecoder == NULL))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::Can't get handle for decoder!", iName.Str()));
iOMXDecoder = NULL;
oscl_free(aOutputParameters);
CommandComplete(iInputCommands, aCmd, PVMFErrResource);
return;
}
}
else
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::No component can handle role %s !", iName.Str(), aInputParameters.cComponentRole));
iOMXDecoder = NULL;
oscl_free(aOutputParameters);
CommandComplete(iInputCommands, aCmd, PVMFErrResource);
return;
}
if (!iOMXDecoder)
{
oscl_free(aOutputParameters);
CommandComplete(iInputCommands, aCmd, PVMFErrNoResources);
return;
}
// find out how many roles the component supports
OMX_U32 NumRoles;
err = OMX_MasterGetRolesOfComponent((OMX_STRING)CompName, &NumRoles, NULL);
if (err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::DoPrepare() Problem getting component roles", iName.Str()));
CommandComplete(iInputCommands, aCmd, PVMFErrResource);
return;
}
// 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, (OMX_STRING)aInputParameters.cComponentRole, OMX_MAX_STRINGNAME_SIZE);
err = OMX_SetParameter(iOMXDecoder, OMX_IndexParamStandardComponentRole, &RoleParam);
if (err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::DoPrepare() Problem setting component role", iName.Str()));
#if 0 //QCOM WORKAROUND JJDBG
CommandComplete(iInputCommands, aCmd, PVMFErrResource);
return;
#endif
}
}
// GET CAPABILITY FLAGS FROM PV COMPONENT, IF this fails, use defaults
PV_OMXComponentCapabilityFlagsType Cap_flags;
err = OMX_GetParameter(iOMXDecoder, (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;
}
// do some sanity checking
if ((format != PVMF_MIME_H264_VIDEO) && (format != PVMF_MIME_H264_VIDEO_MP4) && (format != PVMF_MIME_H264_VIDEO_RAW))
{
iOMXComponentUsesNALStartCodes = false;
iOMXComponentUsesFullAVCFrames = false;
}
if (iOMXComponentUsesFullAVCFrames)
{
iNALCount = 0;
oscl_memset(iNALSizeArray, 0, sizeof(uint32) * MAX_NAL_PER_FRAME); // 100 is max number of NALs
}
// make sure that copying is used where necessary
if (!iOMXComponentSupportsPartialFrames || iOMXComponentUsesNALStartCodes || iOMXComponentUsesFullAVCFrames)
{
iOMXComponentSupportsMovableInputBuffers = false;
}
// find out about parameters
if (!NegotiateComponentParameters(aOutputParameters))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::DoPrepare() Cannot get component parameters", iName.Str()));
oscl_free(aOutputParameters);
CommandComplete(iInputCommands, aCmd, PVMFErrNoResources);
return;
}
oscl_free(aOutputParameters);
// 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 dec node, and set the threadsafe callback AO priority to 1 higher
iThreadSafeHandlerEventHandler = OSCL_NEW(EventHandlerThreadSafeCallbackAO, (this, 10, "EventHandlerAO", Priority() + 2));
if (iThreadSafeHandlerEmptyBufferDone)
{
OSCL_DELETE(iThreadSafeHandlerEmptyBufferDone);
iThreadSafeHandlerEmptyBufferDone = NULL;
}
// use queue depth of iNumInputBuffers to prevent deadlock
iThreadSafeHandlerEmptyBufferDone = OSCL_NEW(EmptyBufferDoneThreadSafeCallbackAO, (this, iNumInputBuffers, "EmptyBufferDoneAO", Priority() + 1));
if (iThreadSafeHandlerFillBufferDone)
{
OSCL_DELETE(iThreadSafeHandlerFillBufferDone);
iThreadSafeHandlerFillBufferDone = NULL;
}
// use queue depth of iNumOutputBuffers to prevent deadlock
iThreadSafeHandlerFillBufferDone = OSCL_NEW(FillBufferDoneThreadSafeCallbackAO, (this, iNumOutputBuffers, "FillBufferDoneAO", Priority() + 1));
if ((iThreadSafeHandlerEventHandler == NULL) ||
(iThreadSafeHandlerEmptyBufferDone == NULL) ||
(iThreadSafeHandlerFillBufferDone == NULL)
)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::Can't get threadsafe callbacks for decoder!", iName.Str()));
iOMXDecoder = NULL;
}
// ONLY FOR AVC FILE PLAYBACK WILL 1 FRAGMENT CONTAIN ONE FULL NAL
if ((format == PVMF_MIME_H264_VIDEO) || (format == PVMF_MIME_H264_VIDEO_MP4))
{
// every memory fragment in case of AVC is a full NAL
iSetMarkerBitForEveryFrag = true;
}
else
{
iSetMarkerBitForEveryFrag = false;
}
// Init Decoder
iCurrentDecoderState = OMX_StateLoaded;
/* Change state to OMX_StateIdle from OMX_StateLoaded. */
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "%s::DoPrepare(): Changing Component state Loaded -> Idle ", iName.Str()));
err = OMX_SendCommand(iOMXDecoder, OMX_CommandStateSet, OMX_StateIdle, NULL);
if (err != OMX_ErrorNone)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::DoPrepare() Can't send StateSet command!", iName.Str()));
CommandComplete(iInputCommands, aCmd, PVMFErrNoResources);
return;
}
/* Allocate input buffers */
if (!CreateInputMemPool(iNumInputBuffers))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::DoPrepare() Can't allocate mempool for input buffers!", iName.Str()));
CommandComplete(iInputCommands, aCmd, PVMFErrNoResources);
return;
}
in_ctrl_struct_ptr = NULL;
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, "%s::DoPrepare() in_ctrl_struct_ptr == NULL"));
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, "%s::DoPrepare() in_buff_hdr_ptr == NULL"));
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, "%s::DoPrepare() Component can't use input buffers!", iName.Str()));
CommandComplete(iInputCommands, aCmd, PVMFErrNoResources);
return;
}
/* Allocate output buffers */
if (!CreateOutMemPool(iNumOutputBuffers))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::DoPrepare() Can't allocate mempool for output buffers!", iName.Str()));
CommandComplete(iInputCommands, aCmd, PVMFErrNoResources);
return;
}
out_ctrl_struct_ptr = NULL;
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, "%s::DoPrepare() out_ctrl_struct_ptr == NULL"));
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, "%s::DoPrepare() out_buff_hdr_ptr == NULL"));
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, "%s::DoPrepare() Component can't use output buffers!", iName.Str()));
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 PVMFOMXBaseDecNode::DoStart(PVMFOMXBaseDecNodeCommand& aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::DoStart() In", iName.Str()));
iDiagnosticsLogged = false;
PVMFStatus status = PVMFSuccess;
OMX_ERRORTYPE err;
OMX_STATETYPE sState;
switch (iInterfaceState)
{
case EPVMFNodePrepared:
case EPVMFNodePaused:
{
//Get state of OpenMAX decoder
err = OMX_GetState(iOMXDecoder, &sState);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::DoStart(): Can't get State of decoder!", iName.Str()));
sState = OMX_StateInvalid;
}
if ((sState == OMX_StateIdle) || (sState == OMX_StatePause))
{
/* Change state to OMX_StateExecuting form OMX_StateIdle. */
// init the flag
if (!iDynamicReconfigInProgress)
{
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, "%s::DoStart() Changing Component state Idle->Executing", iName.Str()));
err = OMX_SendCommand(iOMXDecoder, OMX_CommandStateSet, OMX_StateExecuting, NULL);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::DoStart(): Can't send StateSet command to decoder!", iName.Str()));
status = PVMFErrInvalidState;
}
}
else
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::DoStart(): Decoder is not in the Idle or Pause state!", iName.Str()));
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 PVMFOMXBaseDecNode::DoStop(PVMFOMXBaseDecNodeCommand& aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::DoStop() In", iName.Str()));
LogDiagnostics();
OMX_ERRORTYPE err;
OMX_STATETYPE sState;
switch (iInterfaceState)
{
case EPVMFNodeStarted:
case EPVMFNodePaused:
case EPVMFNodePrepared:
// Stop data source
// This will also prevent execution of HandleProcessingState
iDataIn.Unbind();
// 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;
//if we're in the middle of a partial frame assembly
// abandon it and start fresh
if (iObtainNewInputBuffer == false)
{
if (iInputBufferUnderConstruction != NULL)
{
if (iInBufMemoryPool != NULL)
{
iInBufMemoryPool->deallocate((OsclAny *)iInputBufferUnderConstruction);
}
iInputBufferUnderConstruction = NULL;
}
iObtainNewInputBuffer = true;
}
iFirstDataMsgAfterBOS = true;
//Get state of OpenMAX decoder
err = OMX_GetState(iOMXDecoder, &sState);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::DoStop(): Can't get State of decoder!", iName.Str()));
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, "%s::DoStop() Changing Component State Executing->Idle or Pause->Idle", iName.Str()));
err = OMX_SendCommand(iOMXDecoder, OMX_CommandStateSet, OMX_StateIdle, NULL);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::DoStop(): Can't send StateSet command to decoder!", iName.Str()));
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 == EPVMFOMXBaseDecNodeProcessingState_ReadyToDecode)
iProcessingState = EPVMFOMXBaseDecNodeProcessingState_Stopping;
// indicate that stop cmd was sent
iStopCommandWasSentToComponent = true;
}
else
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::DoStop(): Decoder is not in the Executing or Pause state!", iName.Str()));
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 PVMFOMXBaseDecNode::DoFlush(PVMFOMXBaseDecNodeCommand& aCmd)
{
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();
}
if (iOutPort)
{
iOutPort->SuspendInput();
}
// Stop data source
// DV: Sending "OMX_CommandFlush" to the decoder: Not supported yet
break;
default:
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
break;
}
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXBaseDecNode::DoPause(PVMFOMXBaseDecNodeCommand& aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::DoPause() In", iName.Str()));
OMX_ERRORTYPE err;
OMX_STATETYPE sState;
switch (iInterfaceState)
{
case EPVMFNodeStarted:
//Get state of OpenMAX decoder
err = OMX_GetState(iOMXDecoder, &sState);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::DoPause(): Can't get State of decoder!", iName.Str()));
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, "%s::DoPause() Changing Component State Executing->Idle", iName.Str()));
// 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 == EPVMFOMXBaseDecNodeProcessingState_ReadyToDecode)
iProcessingState = EPVMFOMXBaseDecNodeProcessingState_Pausing;
// indicate that pause cmd was sent
iPauseCommandWasSentToComponent = true;
err = OMX_SendCommand(iOMXDecoder, OMX_CommandStateSet, OMX_StatePause, NULL);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::DoPause(): Can't send StateSet command to decoder!", iName.Str()));
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
break;
}
}
else
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::DoPause(): Decoder is not in the Executing state!", iName.Str()));
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 PVMFOMXBaseDecNode::DoReset(PVMFOMXBaseDecNodeCommand& aCmd)
{
OMX_ERRORTYPE err;
OMX_STATETYPE sState;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::DoReset() In", iName.Str()));
LogDiagnostics();
switch (iInterfaceState)
{
case EPVMFNodeIdle:
case EPVMFNodeInitialized:
case EPVMFNodePrepared:
case EPVMFNodeStarted:
case EPVMFNodePaused:
case EPVMFNodeError:
{
//Check if decoder is initilized
if (iOMXDecoder != NULL)
{
//if we're in the middle of a partial frame assembly
// abandon it and start fresh
if (iObtainNewInputBuffer == false)
{
if (iInputBufferUnderConstruction != NULL)
{
if (iInBufMemoryPool != NULL)
{
iInBufMemoryPool->deallocate((OsclAny *)iInputBufferUnderConstruction);
}
iInputBufferUnderConstruction = NULL;
}
iObtainNewInputBuffer = true;
}
iFirstDataMsgAfterBOS = true;
iKeepDroppingMsgsUntilMarkerBit = false;
//Get state of OpenMAX decoder
err = OMX_GetState(iOMXDecoder, &sState);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::DoReset(): Can't get State of decoder!", iName.Str()));
if (iResetInProgress)
{
// cmd is in current q
iResetInProgress = false;
if ((iCurrentCommand.size() > 0) &&
(iCurrentCommand.front().iCmd == PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_RESET)
)
{
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFErrResource);
}
}
else
{
CommandComplete(iInputCommands, aCmd, PVMFErrResource);
}
return;
}
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, "%s::DoReset() OMX comp is in loaded state. Wait for official callback to change variables etc.", iName.Str()));
return;
}
else
{
//CommandComplete(iInputCommands, aCmd, PVMFErrResource);
//delete all ports and notify observer.
if (iInPort)
{
OSCL_DELETE(((PVMFOMXDecPort*)iInPort));
iInPort = NULL;
}
if (iOutPort)
{
OSCL_DELETE(((PVMFOMXDecPort*)iOutPort));
iOutPort = NULL;
}
iDataIn.Unbind();
// Reset the metadata key list
iAvailableMetadataKeys.clear();
iEndOfDataReached = false;
iIsEOSSentToComponent = false;
iIsEOSReceivedFromComponent = false;
if (iOMXComponentUsesFullAVCFrames)
{
iNALCount = 0;
oscl_memset(iNALSizeArray, 0, sizeof(uint32) * MAX_NAL_PER_FRAME); // 100 is max number of NALs
}
// reset dynamic port reconfig flags - no point continuing with port reconfig
// if we start again - we'll have to do prepare and send new config etc.
iSecondPortReportedChange = false;
iDynamicReconfigInProgress = false;
iProcessingState = EPVMFOMXBaseDecNodeProcessingState_Idle;
SetState(EPVMFNodeIdle);
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
return;
}
}
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)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::DoReset() Waiting for %d input and-or %d output buffers", iName.Str(), 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, "%s::DoReset() Changing Component State Idle->Loaded", iName.Str()));
err = OMX_SendCommand(iOMXDecoder, OMX_CommandStateSet, OMX_StateLoaded, NULL);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::DoReset(): Can't send StateSet command to decoder!", iName.Str()));
}
iResetMsgSent = true;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::DoReset() freeing output buffers", iName.Str()));
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, "%s::DoReset() Cannot free output buffers ", iName.Str()));
if (iResetInProgress)
{
iResetInProgress = false;
if ((iCurrentCommand.size() > 0) &&
(iCurrentCommand.front().iCmd == PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_RESET)
)
{
CommandComplete(iCurrentCommand, iCurrentCommand.front() , PVMFErrResource);
}
}
}
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::DoReset() freeing input buffers ", iName.Str()));
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, "%s::DoReset() Cannot free input buffers ", iName.Str()));
if (iResetInProgress)
{
iResetInProgress = false;
if ((iCurrentCommand.size() > 0) &&
(iCurrentCommand.front().iCmd == PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_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;
}
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)
{
// replicate behavior of stop cmd
iDataIn.Unbind();
// 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, "%s::DoReset() Changing Component State Executing->Idle or Pause->Idle", iName.Str()));
err = OMX_SendCommand(iOMXDecoder, OMX_CommandStateSet, OMX_StateIdle, NULL);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::DoReset(): Can't send StateSet command to decoder!", iName.Str()));
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 == EPVMFOMXBaseDecNodeProcessingState_ReadyToDecode)
iProcessingState = EPVMFOMXBaseDecNodeProcessingState_Stopping;
}
return;
}
else
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::DoReset(): Decoder is not in the Idle state!", iName.Str()));
if (iResetInProgress)
{
iResetInProgress = false;
if ((iCurrentCommand.size() > 0) &&
(iCurrentCommand.front().iCmd == PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_RESET)
)
{
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFErrInvalidState);
}
}
else
{
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
}
break;
}//end of if (sState == OMX_StateIdle)
}//end of if (iOMXDecoder != NULL)
//delete all ports and notify observer.
if (iInPort)
{
OSCL_DELETE(((PVMFOMXDecPort*)iInPort));
iInPort = NULL;
}
if (iOutPort)
{
OSCL_DELETE(((PVMFOMXDecPort*)iOutPort));
iOutPort = NULL;
}
iDataIn.Unbind();
// Reset the metadata key list
iAvailableMetadataKeys.clear();
iEndOfDataReached = false;
iIsEOSSentToComponent = false;
iIsEOSReceivedFromComponent = false;
if (iOMXComponentUsesFullAVCFrames)
{
iNALCount = 0;
oscl_memset(iNALSizeArray, 0, sizeof(uint32) * MAX_NAL_PER_FRAME); // 100 is max number of NALs
}
// reset dynamic port reconfig flags - no point continuing with port reconfig
// if we start again - we'll have to do prepare and send new config etc.
iSecondPortReportedChange = false;
iDynamicReconfigInProgress = false;
iProcessingState = EPVMFOMXBaseDecNodeProcessingState_Idle;
//logoff & go back to Created state.
SetState(EPVMFNodeIdle);
if (iResetInProgress)
{
iResetInProgress = false;
if ((iCurrentCommand.size() > 0) &&
(iCurrentCommand.front().iCmd == PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_RESET)
)
{
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess);
}
}
else
{
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
}
}
break;
default:
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
break;
}
}
/////////////////////////////////////////////////////////////////////////////
// Clean Up Decoder
/////////////////////////////////////////////////////////////////////////////
bool PVMFOMXBaseDecNode::DeleteOMXBaseDecoder()
{
OMX_ERRORTYPE err;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::DeleteOMXBaseDecoder() In", iName.Str()));
if (iOMXDecoder != NULL)
{
/* Free Component handle. */
err = OMX_MasterFreeHandle(iOMXDecoder);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::DeleteOMXBaseDecoder(): Can't free decoder's handle!", iName.Str()));
}
iOMXDecoder = NULL;
}//end of if (iOMXDecoder != NULL)
return true;
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PVMFOMXBaseDecNode::ChangeNodeState(TPVMFNodeInterfaceState aNewState)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::ChangeNodeState() Changing state from %d to %d", iName.Str(), iInterfaceState, aNewState));
iInterfaceState = aNewState;
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PVMFOMXBaseDecNode::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, "%s::freechunkavailable() Memory chunk in INPUT mempool was deallocated, %d out of %d now available", iName.Str(), 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, "%s::freechunkavailable() Memory chunk in OUTPUT mempool was deallocated, %d out of %d now available", iName.Str(), 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, "%s::freechunkavailable() UNKNOWN mempool ", iName.Str()));
}
// reschedule
if (IsAdded())
RunIfNotReady();
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PVMFOMXBaseDecNode::HandlePortActivity(const PVMFPortActivity &aActivity)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "0x%x PVMFOMXBaseDecNode::PortActivity: port=0x%x, type=%d",
this, 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, "%s::PortActivity: IncomingMsgQueueSize=%d", iName.Str(), 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 == EPVMFOMXBaseDecNodeProcessingState_WaitForOutgoingQueue)
{
iProcessingState = EPVMFOMXBaseDecNodeProcessingState_ReadyToDecode;
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 ReadyToDecode
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
(0, "0x%x PVMFOMXBaseDecNode::PortActivity: Connected port is now ready", this));
RunIfNotReady();
break;
default:
break;
}
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXBaseDecNode::DoCancelAllCommands(PVMFOMXBaseDecNodeCommand& aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::DoCancelAllCommands", iName.Str()));
//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 PVMFOMXBaseDecNode::DoCancelCommand(PVMFOMXBaseDecNodeCommand& aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::DoCancelCommand", iName.Str()));
//extract the command ID from the parameters.
PVMFCommandId id;
aCmd.PVMFOMXBaseDecNodeCommandBase::Parse(id);
//first check "current" command if any
{
PVMFOMXBaseDecNodeCommand* cmd = iCurrentCommand.FindById(id);
if (cmd)
{
// if reset is being canceled:
if (cmd->iCmd == PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_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.
PVMFOMXBaseDecNodeCommand* 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 PVMFOMXBaseDecNode::DoQueryInterface(PVMFOMXBaseDecNodeCommand& aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::DoQueryInterface", iName.Str()));
PVUuid* uuid;
PVInterface** ptr;
aCmd.PVMFOMXBaseDecNodeCommandBase::Parse(uuid, ptr);
if (*uuid == PVUuid(PVMF_OMX_BASE_DEC_NODE_CUSTOM1_UUID))
{
addRef();
*ptr = (PVMFOMXBaseDecNodeExtensionInterface*)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
{
//not supported
*ptr = NULL;
CommandComplete(iInputCommands, aCmd, PVMFFailure);
}
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PVMFOMXBaseDecNode::addRef()
{
++iExtensionRefCount;
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PVMFOMXBaseDecNode::removeRef()
{
--iExtensionRefCount;
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF bool PVMFOMXBaseDecNode::queryInterface(const PVUuid& uuid, PVInterface*& iface)
{
PVUuid my_uuid(PVMF_OMX_BASE_DEC_NODE_CUSTOM1_UUID);
if (uuid == my_uuid)
{
PVMFOMXBaseDecNodeExtensionInterface* myInterface = OSCL_STATIC_CAST(PVMFOMXBaseDecNodeExtensionInterface*, 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;
}
//////////////////////////////////////////////////////////////////////////////////////
bool PVMFOMXBaseDecNode::HandleRepositioning()
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleRepositioning() IN", iName.Str()));
// 1) Send Flush command to component for both input and output ports
// 2) "Wait" until component flushes both ports
// 3) Resume
OMX_ERRORTYPE err = OMX_ErrorNone;
OMX_STATETYPE sState = OMX_StateInvalid;
if (!iIsRepositioningRequestSentToComponent)
{
// first check the state (if executing or paused, continue)
err = OMX_GetState(iOMXDecoder, &sState);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::HandleRepositioning(): Can't get State of decoder - trying to send reposition request!", iName.Str()));
sState = OMX_StateInvalid;
ReportErrorEvent(PVMFErrResourceConfiguration);
ChangeNodeState(EPVMFNodeError);
return false;
}
if ((sState != OMX_StateExecuting) && (sState != OMX_StatePause))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleRepositioning() Component State is not executing or paused, do not proceed with repositioning", iName.Str()));
return true;
}
iIsRepositioningRequestSentToComponent = true; // prevent sending requests multiple times
iIsInputPortFlushed = false; // flag that will be set to true once component flushes the port
iIsOutputPortFlushed = false;
iDoNotSendOutputBuffersDownstreamFlag = true;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleRepositioning() Sending Flush command to component", iName.Str()));
// send command to flush all ports (arg is OMX_ALL)
err = OMX_SendCommand(iOMXDecoder, OMX_CommandFlush, OMX_ALL, NULL);
if (err != OMX_ErrorNone)
{
//Error condition report
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::HandleRepositioning(): Can't send flush command - trying to send reposition request!", iName.Str()));
sState = OMX_StateInvalid;
ReportErrorEvent(PVMFErrResourceConfiguration);
ChangeNodeState(EPVMFNodeError);
return false;
}
}
if (iIsRepositionDoneReceivedFromComponent)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleRepositioning() Component has flushed both ports, and is done repositioning", iName.Str()));
iIsRepositioningRequestSentToComponent = false; // enable sending requests again
iIsRepositionDoneReceivedFromComponent = false;
iIsInputPortFlushed = false;
iIsOutputPortFlushed = false;
iDoNotSendOutputBuffersDownstreamFlag = false;
return true;
}
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "%s::HandleRepositioning() Component is not yet done repositioning ", iName.Str()));
return false;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF OMX_TICKS PVMFOMXBaseDecNode::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, "%s::ConvertTimestampIntoOMXTicks Input timescale is 0", iName.Str()));
SetState(EPVMFNodeError);
ReportErrorEvent(PVMFErrResourceConfiguration);
return (OMX_TICKS) 0;
}
OSCL_ASSERT(iTimeScale != 0);
if (0 == iTimeScale)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::ConvertTimestampIntoOMXTicks target timescale is 0", iName.Str()));
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 PVMFOMXBaseDecNode::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, "%s::ConvertOMXTicksIntoTimestamp Output timescale is 0", iName.Str()));
SetState(EPVMFNodeError);
ReportErrorEvent(PVMFErrResourceConfiguration);
return (uint32) 0;
}
OSCL_ASSERT(iTimeScale != 0);
if (0 == iTimeScale)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
(0, "%s::ConvertOMXTicksIntoTimestamp target timescale is 0", iName.Str()));
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 current_ts;
}
///////////////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF void PVMFOMXBaseDecNode::setObserver(PvmiConfigAndCapabilityCmdObserver* aObserver)
{
OSCL_UNUSED_ARG(aObserver);
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::setObserver()", iName.Str()));
// This method is not supported so leave
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "%s::setObserver() is not supported!", iName.Str()));
OSCL_LEAVE(PVMFErrNotSupported);
}
OSCL_EXPORT_REF PVMFStatus PVMFOMXBaseDecNode::getParametersSync(PvmiMIOSession aSession, PvmiKeyType aIdentifier, PvmiKvp*& aParameters, int& aNumParamElements, PvmiCapabilityContext aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::getParametersSync()", iName.Str()));
OSCL_UNUSED_ARG(aSession);
return DoCapConfigGetParametersSync(aIdentifier, aParameters, aNumParamElements, aContext);
}
OSCL_EXPORT_REF PVMFStatus PVMFOMXBaseDecNode::releaseParameters(PvmiMIOSession aSession, PvmiKvp* aParameters, int aNumElements)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::releaseParameters()", iName.Str()));
OSCL_UNUSED_ARG(aSession);
return DoCapConfigReleaseParameters(aParameters, aNumElements);
}
OSCL_EXPORT_REF void PVMFOMXBaseDecNode::createContext(PvmiMIOSession aSession, PvmiCapabilityContext& aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::createContext()", iName.Str()));
OSCL_UNUSED_ARG(aSession);
OSCL_UNUSED_ARG(aContext);
// This method is not supported so leave
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "%s::createContext() is not supported!", iName.Str()));
OSCL_LEAVE(PVMFErrNotSupported);
}
OSCL_EXPORT_REF void PVMFOMXBaseDecNode::setContextParameters(PvmiMIOSession aSession, PvmiCapabilityContext& aContext, PvmiKvp* aParameters, int aNumParamElements)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::setContextParameters()", iName.Str()));
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, "%s::setContextParameters() is not supported!", iName.Str()));
OSCL_LEAVE(PVMFErrNotSupported);
}
OSCL_EXPORT_REF void PVMFOMXBaseDecNode::DeleteContext(PvmiMIOSession aSession, PvmiCapabilityContext& aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::DeleteContext()", iName.Str()));
OSCL_UNUSED_ARG(aSession);
OSCL_UNUSED_ARG(aContext);
// This method is not supported so leave
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "%s::DeleteContext() is not supported!", iName.Str()));
OSCL_LEAVE(PVMFErrNotSupported);
}
OSCL_EXPORT_REF void PVMFOMXBaseDecNode::setParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters, int aNumElements, PvmiKvp* &aRetKVP)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::setParametersSync()", iName.Str()));
OSCL_UNUSED_ARG(aSession);
// Complete the request synchronously
DoCapConfigSetParameters(aParameters, aNumElements, aRetKVP);
}
OSCL_EXPORT_REF PVMFCommandId PVMFOMXBaseDecNode::setParametersAsync(PvmiMIOSession aSession, PvmiKvp* aParameters, int aNumElements, PvmiKvp*& aRetKVP, OsclAny* aContext)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::setParametersAsync()", iName.Str()));
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, "%s::setParametersAsync() is not supported!", iName.Str()));
OSCL_LEAVE(PVMFErrNotSupported);
return 0;
}
OSCL_EXPORT_REF uint32 PVMFOMXBaseDecNode::getCapabilityMetric(PvmiMIOSession aSession)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::getCapabilityMetric()", iName.Str()));
OSCL_UNUSED_ARG(aSession);
// Not supported so return 0
return 0;
}
OSCL_EXPORT_REF PVMFStatus PVMFOMXBaseDecNode::verifyParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters, int aNumElements)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::verifyParametersSync()", iName.Str()));
OSCL_UNUSED_ARG(aSession);
return DoCapConfigVerifyParameters(aParameters, aNumElements);
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMFOMXBaseDecNode::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, "%sCommand::GetNodeMetadataKeys() called", iName.Str()));
PVMFOMXBaseDecNodeCommand cmd;
cmd.PVMFOMXBaseDecNodeCommand::Construct(aSessionId, PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_GETNODEMETADATAKEY, &aKeyList, starting_index, max_entries, query_key, aContext);
return QueueCommandL(cmd);
}
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFCommandId PVMFOMXBaseDecNode::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, "%sCommand::GetNodeMetadataValue() called", iName.Str()));
PVMFOMXBaseDecNodeCommand cmd;
cmd.PVMFOMXBaseDecNodeCommand::Construct(aSessionId, PVMFOMXBaseDecNodeCommand::PVOMXBASEDEC_NODE_CMD_GETNODEMETADATAVALUE, &aKeyList, &aValueList, starting_index, max_entries, aContext);
return QueueCommandL(cmd);
}
// From PVMFMetadataExtensionInterface
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMFOMXBaseDecNode::ReleaseNodeMetadataKeys(PVMFMetadataList& , uint32 , uint32)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::ReleaseNodeMetadataKeys() called", iName.Str()));
//nothing needed-- there's no dynamic allocation in this node's key list
return PVMFSuccess;
}
// From PVMFMetadataExtensionInterface
/////////////////////////////////////////////////////////////////////////////
OSCL_EXPORT_REF PVMFStatus PVMFOMXBaseDecNode::ReleaseNodeMetadataValues(Oscl_Vector<PvmiKvp, OsclMemAllocator>& aValueList, uint32 start, uint32 end)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::ReleaseNodeMetadataValues() called", iName.Str()));
if (aValueList.size() == 0 || start > end)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "%s::ReleaseNodeMetadataValues() Invalid start/end index", iName.Str()));
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;
}
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
// CAPABILITY CONFIG PRIVATE
OSCL_EXPORT_REF PVMFStatus PVMFOMXBaseDecNode::DoCapConfigGetParametersSync(PvmiKeyType aIdentifier, PvmiKvp*& aParameters, int& aNumParamElements, PvmiCapabilityContext aContext)
{
OSCL_UNUSED_ARG(aParameters);
OSCL_UNUSED_ARG(aIdentifier);
OSCL_UNUSED_ARG(aNumParamElements);
OSCL_UNUSED_ARG(aContext);
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::DoCapConfigGetParametersSync() In", iName.Str()));
return PVMFFailure;
}
OSCL_EXPORT_REF PVMFStatus PVMFOMXBaseDecNode::DoCapConfigReleaseParameters(PvmiKvp* aParameters, int aNumElements)
{
OSCL_UNUSED_ARG(aParameters);
OSCL_UNUSED_ARG(aNumElements);
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::DoCapConfigReleaseParameters() Out", iName.Str()));
return PVMFSuccess;
}
OSCL_EXPORT_REF void PVMFOMXBaseDecNode::DoCapConfigSetParameters(PvmiKvp* aParameters, int aNumElements, PvmiKvp* &aRetKVP)
{
OSCL_UNUSED_ARG(aParameters);
OSCL_UNUSED_ARG(aNumElements);
OSCL_UNUSED_ARG(aRetKVP);
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::DoCapConfigSetParameters() Out", iName.Str()));
}
OSCL_EXPORT_REF PVMFStatus PVMFOMXBaseDecNode::DoCapConfigVerifyParameters(PvmiKvp* aParameters, int aNumElements)
{
OSCL_UNUSED_ARG(aParameters);
OSCL_UNUSED_ARG(aNumElements);
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::DoCapConfigVerifyParameters() In", iName.Str()));
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "%s::DoCapConfigVerifyParameters() Out", iName.Str()));
return PVMFSuccess;
}
/////////////////////////////////////////////////////////////////////////////
void PVMFOMXBaseDecNode::LogDiagnostics()
{
if (iDiagnosticsLogged == false)
{
iDiagnosticsLogged = true;
PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, iDiagnosticsLogger, PVLOGMSG_INFO, (0, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"));
PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, iDiagnosticsLogger, PVLOGMSG_INFO, (0, "%s - Number of Frames Sent = %d", iName.Str(), iSeqNum));
PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, iDiagnosticsLogger, PVLOGMSG_INFO, (0, "%s - TS of last decoded frame = %d", iName.Str(), iOutTimeStamp));
}
}
OSCL_EXPORT_REF OsclAny* PVMFOMXBaseDecNode::AllocateKVPKeyArray(int32& aLeaveCode, PvmiKvpValueType aValueType, int32 aNumElements)
{
int32 leaveCode = OsclErrNone;
OsclAny* aBuffer = NULL;
switch (aValueType)
{
case PVMI_KVPVALTYPE_WCHARPTR:
OSCL_TRY(leaveCode,
aBuffer = (oscl_wchar*) OSCL_ARRAY_NEW(oscl_wchar, aNumElements);
);
break;
case PVMI_KVPVALTYPE_CHARPTR:
OSCL_TRY(leaveCode,
aBuffer = (char*) OSCL_ARRAY_NEW(char, aNumElements);
);
break;
case PVMI_KVPVALTYPE_UINT8PTR:
OSCL_TRY(leaveCode,
aBuffer = (uint8*) OSCL_ARRAY_NEW(uint8, aNumElements);
);
break;
default:
break;
}
aLeaveCode = leaveCode;
return aBuffer;
}
#undef PVLOGGER_LOGMSG
#define PVLOGGER_LOGMSG(IL, LOGGER, LEVEL, MESSAGE) OSCL_UNUSED_ARG(LOGGER);