| /* ------------------------------------------------------------------ |
| * Copyright (C) 2008 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_audiodec_node.h" |
| #include "pvlogger.h" |
| #include "oscl_error_codes.h" |
| #include "pvmf_omx_audiodec_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 "latmpayloadparser.h" |
| |
| #include "omx_core.h" |
| #include "pvmf_omx_audiodec_callbacks.h" //used for thin AO in Decoder's callbacks |
| #include "pv_omxcore.h" |
| #include "pv_omxmastercore.h" |
| |
| #define PVOMXAUDIODEC_MEDIADATA_POOLNUM 2*NUMBER_OUTPUT_BUFFER |
| #define PVOMXAUDIODEC_MEDIADATA_CHUNKSIZE 128 |
| |
| |
| // Node default settings |
| |
| #define PVOMXAUDIODECNODE_CONFIG_MIMETYPE_DEF 0 |
| |
| #define PVMF_OMXAUDIODEC_NUM_METADATA_VALUES 6 |
| |
| // Constant character strings for metadata keys |
| static const char PVOMXAUDIODECMETADATA_CODECINFO_AUDIO_FORMAT_KEY[] = "codec-info/audio/format"; |
| static const char PVOMXAUDIODECMETADATA_CODECINFO_AUDIO_CHANNELS_KEY[] = "codec-info/audio/channels"; |
| static const char PVOMXAUDIODECMETADATA_CODECINFO_AUDIO_SAMPLERATE_KEY[] = "codec-info/audio/sample-rate"; |
| static const char PVOMXAUDIODECMETADATA_CODECINFO_AUDIO_AVGBITRATE_KEY[] = "codec-info/audio/avgbitrate"; |
| static const char PVOMXAUDIODECMETADATA_CODECINFO_AUDIO_AACOBJECTTYPE_KEY[] = "codec-info/audio/aac-objecttype"; |
| static const char PVOMXAUDIODECMETADATA_CODECINFO_AUDIO_AACSTREAMTYPE_KEY[] = "codec-info/audio/aac-streamtype"; |
| |
| |
| static const char PVOMXAUDIODECMETADATA_SEMICOLON[] = ";"; |
| |
| |
| |
| // 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_Audio(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) |
| { |
| |
| PVMFOMXAudioDecNode *Node = (PVMFOMXAudioDecNode *) aAppData; |
| |
| if (Node->IsComponentMultiThreaded()) |
| { |
| // allocate the memory for the callback event specific data |
| EventHandlerSpecificData_Audio* ED = (EventHandlerSpecificData_Audio*) Node->iThreadSafeHandlerEventHandler->iMemoryPool->allocate(sizeof(EventHandlerSpecificData_Audio)); |
| |
| // 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_Audio(OMX_OUT OMX_HANDLETYPE aComponent, |
| OMX_OUT OMX_PTR aAppData, |
| OMX_OUT OMX_BUFFERHEADERTYPE* aBuffer) |
| { |
| |
| PVMFOMXAudioDecNode *Node = (PVMFOMXAudioDecNode *) aAppData; |
| if (Node->IsComponentMultiThreaded()) |
| { |
| |
| // allocate the memory for the callback event specific data |
| //EmptyBufferDoneSpecificData* ED = (EmptyBufferDoneSpecificData*) oscl_malloc(sizeof (EmptyBufferDoneSpecificData)); |
| EmptyBufferDoneSpecificData_Audio* ED = (EmptyBufferDoneSpecificData_Audio*) Node->iThreadSafeHandlerEmptyBufferDone->iMemoryPool->allocate(sizeof(EmptyBufferDoneSpecificData_Audio)); |
| |
| // 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_Audio(OMX_OUT OMX_HANDLETYPE aComponent, |
| OMX_OUT OMX_PTR aAppData, |
| OMX_OUT OMX_BUFFERHEADERTYPE* aBuffer) |
| { |
| PVMFOMXAudioDecNode *Node = (PVMFOMXAudioDecNode *) aAppData; |
| if (Node->IsComponentMultiThreaded()) |
| { |
| |
| // allocate the memory for the callback event specific data |
| //FillBufferDoneSpecificData* ED = (FillBufferDoneSpecificData*) oscl_malloc(sizeof (FillBufferDoneSpecificData)); |
| FillBufferDoneSpecificData_Audio* ED = (FillBufferDoneSpecificData_Audio*) Node->iThreadSafeHandlerFillBufferDone->iMemoryPool->allocate(sizeof(FillBufferDoneSpecificData_Audio)); |
| |
| // pack the relevant data into the structure |
| ED->hComponent = aComponent; |
| ED->pAppData = aAppData; |
| ED->pBuffer = aBuffer; |
| |
| // convert the pointer into OsclAny ptr |
| OsclAny* P = (OsclAny*) ED; |
| |
| // CALL the generic callback AO API: |
| Node->iThreadSafeHandlerFillBufferDone->ReceiveEvent(P); |
| |
| return OMX_ErrorNone; |
| } |
| else |
| { |
| OMX_ERRORTYPE status; |
| status = Node->FillBufferDoneProcessing(aComponent, aAppData, aBuffer); |
| return status; |
| } |
| |
| } |
| |
| // Callback processing in multithreaded case - dequeued event - call EventHandlerProcessing |
| OsclReturnCode PVMFOMXAudioDecNode::ProcessCallbackEventHandler_MultiThreaded(OsclAny* P) |
| { |
| |
| // re-cast the pointer |
| |
| EventHandlerSpecificData_Audio* ED = (EventHandlerSpecificData_Audio*) P; |
| |
| OMX_HANDLETYPE aComponent = ED->hComponent; |
| OMX_PTR aAppData = ED->pAppData; |
| OMX_EVENTTYPE aEvent = ED->eEvent; |
| OMX_U32 aData1 = ED->nData1; |
| OMX_U32 aData2 = ED->nData2; |
| OMX_PTR aEventData = ED->pEventData; |
| |
| |
| EventHandlerProcessing(aComponent, aAppData, aEvent, aData1, aData2, aEventData); |
| |
| |
| // release the allocated memory when no longer needed |
| |
| iThreadSafeHandlerEventHandler->iMemoryPool->deallocate(ED); |
| ED = NULL; |
| |
| return OsclSuccess; |
| } |
| |
| |
| |
| // Callback processing in multithreaded case - dequeued event - call EmptyBufferDoneProcessing |
| OsclReturnCode PVMFOMXAudioDecNode::ProcessCallbackEmptyBufferDone_MultiThreaded(OsclAny* P) |
| { |
| |
| |
| // re-cast the pointer |
| EmptyBufferDoneSpecificData_Audio* ED = (EmptyBufferDoneSpecificData_Audio*) P; |
| |
| OMX_HANDLETYPE aComponent = ED->hComponent; |
| OMX_PTR aAppData = ED->pAppData; |
| OMX_BUFFERHEADERTYPE* aBuffer = ED->pBuffer; |
| |
| EmptyBufferDoneProcessing(aComponent, aAppData, aBuffer); |
| |
| // release the allocated memory when no longer needed |
| |
| iThreadSafeHandlerEmptyBufferDone->iMemoryPool->deallocate(ED); |
| ED = NULL; |
| |
| return OsclSuccess; |
| } |
| |
| |
| // Callback processing in multithreaded case - dequeued event - call FillBufferDoneProcessing |
| OsclReturnCode PVMFOMXAudioDecNode::ProcessCallbackFillBufferDone_MultiThreaded(OsclAny* P) |
| { |
| |
| // re-cast the pointer |
| FillBufferDoneSpecificData_Audio* ED = (FillBufferDoneSpecificData_Audio*) 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 Distructor |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFOMXAudioDecNode::~PVMFOMXAudioDecNode() |
| { |
| LogDiagnostics(); |
| |
| //Clearup decoder |
| DeleteOMXAudioDecoder(); |
| DeleteLATMParser(); |
| // 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 allocated interfaces |
| |
| //Cleanup allocated ports |
| ReleaseAllPorts(); |
| |
| //Cleanup commands |
| //The command queues are self-deleting, but we want to |
| //notify the observer of unprocessed commands. |
| while (!iCurrentCommand.empty()) |
| { |
| CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFFailure); |
| } |
| while (!iInputCommands.empty()) |
| { |
| CommandComplete(iInputCommands, iInputCommands.front(), PVMFFailure); |
| } |
| |
| //Release Input buffer |
| iDataIn.Unbind(); |
| |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // Add AO to the scheduler |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PVMFOMXAudioDecNode::ThreadLogon() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iLogger, PVLOGMSG_INFO, (0, "PVMFOMXAudioDecNode:ThreadLogon")); |
| |
| switch (iInterfaceState) |
| { |
| case EPVMFNodeCreated: |
| if (!IsAdded()) |
| { |
| AddToScheduler(); |
| iIsAdded = true; |
| } |
| iLogger = PVLogger::GetLoggerObject("PVMFOMXAudioDecNode"); |
| iRunLogger = PVLogger::GetLoggerObject("Run.PVMFOMXAudioDecNode"); |
| iDataPathLogger = PVLogger::GetLoggerObject("datapath"); |
| iClockLogger = PVLogger::GetLoggerObject("clock"); |
| iDiagnosticsLogger = PVLogger::GetLoggerObject("pvplayerdiagnostics.decnode.OMXAudioDecnode"); |
| |
| SetState(EPVMFNodeIdle); |
| return PVMFSuccess; |
| |
| default: |
| return PVMFErrInvalidState; |
| } |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // Remove AO from the scheduler |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PVMFOMXAudioDecNode::ThreadLogoff() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iLogger, PVLOGMSG_INFO, (0, "PVMFOMXAudioDecNode:ThreadLogoff")); |
| |
| switch (iInterfaceState) |
| { |
| case EPVMFNodeIdle: |
| if (IsAdded()) |
| { |
| RemoveFromScheduler(); |
| iIsAdded = false; |
| } |
| iLogger = NULL; |
| SetState(EPVMFNodeCreated); |
| return PVMFSuccess; |
| // break; This break statement was removed to avoid compiler warning for Unreachable Code |
| |
| |
| default: |
| return PVMFErrInvalidState; |
| // break; This break statement was removed to avoid compiler warning for Unreachable Code |
| |
| } |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PVMFOMXAudioDecNode::GetCapability(PVMFNodeCapability& aNodeCapability) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::GetCapability() called")); |
| |
| aNodeCapability = iCapability; |
| return PVMFSuccess; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFPortIter* PVMFOMXAudioDecNode::GetPorts(const PVMFPortFilter* aFilter) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::GetPorts() called")); |
| |
| OSCL_UNUSED_ARG(aFilter); |
| |
| return NULL; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXAudioDecNode::QueueCommandL(PVMFOMXAudioDecNodeCommand& aCmd) |
| { |
| PVMFCommandId id; |
| |
| id = iInputCommands.AddL(aCmd); |
| |
| if (iInputCommands.size() == 1) |
| { |
| //wakeup the AO all the rest of input commands will reschedule the AO in Run |
| RunIfNotReady(); |
| } |
| return id; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXAudioDecNode::QueryUUID(PVMFSessionId s, const PvmfMimeString& aMimeType, |
| Oscl_Vector<PVUuid, PVMFOMXAudioDecNodeAllocator>& aUuids, |
| bool aExactUuidsOnly, |
| const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::QueryUUID() called")); |
| PVMFOMXAudioDecNodeCommand cmd; |
| cmd.PVMFOMXAudioDecNodeCommandBase::Construct(s, PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_QUERYUUID, aMimeType, aUuids, aExactUuidsOnly, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXAudioDecNode::QueryInterface(PVMFSessionId s, const PVUuid& aUuid, |
| PVInterface*& aInterfacePtr, |
| const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::QueryInterface() called")); |
| PVMFOMXAudioDecNodeCommand cmd; |
| cmd.PVMFOMXAudioDecNodeCommandBase::Construct(s, PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_QUERYINTERFACE, aUuid, aInterfacePtr, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXAudioDecNode::RequestPort(PVMFSessionId s, int32 aPortTag, const PvmfMimeString* /* aPortConfig */, const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::RequestPort() called")); |
| PVMFOMXAudioDecNodeCommand cmd; |
| cmd.PVMFOMXAudioDecNodeCommandBase::Construct(s, PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_REQUESTPORT, aPortTag, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PVMFOMXAudioDecNode::ReleasePort(PVMFSessionId s, PVMFPortInterface& aPort, const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::ReleasePort() called")); |
| PVMFOMXAudioDecNodeCommand cmd; |
| cmd.PVMFOMXAudioDecNodeCommandBase::Construct(s, PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_RELEASEPORT, aPort, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXAudioDecNode::Init(PVMFSessionId s, const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::Init() called")); |
| PVMFOMXAudioDecNodeCommand cmd; |
| cmd.PVMFOMXAudioDecNodeCommandBase::Construct(s, PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_INIT, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXAudioDecNode::Prepare(PVMFSessionId s, const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::Prepare() called")); |
| PVMFOMXAudioDecNodeCommand cmd; |
| cmd.PVMFOMXAudioDecNodeCommandBase::Construct(s, PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_PREPARE, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXAudioDecNode::Start(PVMFSessionId s, const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::Start() called")); |
| PVMFOMXAudioDecNodeCommand cmd; |
| cmd.PVMFOMXAudioDecNodeCommandBase::Construct(s, PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_START, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXAudioDecNode::Stop(PVMFSessionId s, const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::Stop() called")); |
| PVMFOMXAudioDecNodeCommand cmd; |
| cmd.PVMFOMXAudioDecNodeCommandBase::Construct(s, PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_STOP, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXAudioDecNode::Flush(PVMFSessionId s, const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::Flush() called")); |
| PVMFOMXAudioDecNodeCommand cmd; |
| cmd.PVMFOMXAudioDecNodeCommandBase::Construct(s, PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_FLUSH, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXAudioDecNode::Pause(PVMFSessionId s, const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::Pause() called")); |
| PVMFOMXAudioDecNodeCommand cmd; |
| cmd.PVMFOMXAudioDecNodeCommandBase::Construct(s, PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_PAUSE, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXAudioDecNode::Reset(PVMFSessionId s, const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::Reset() called")); |
| PVMFOMXAudioDecNodeCommand cmd; |
| cmd.PVMFOMXAudioDecNodeCommandBase::Construct(s, PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_RESET, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXAudioDecNode::CancelAllCommands(PVMFSessionId s, const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::CancelAllCommands() called")); |
| PVMFOMXAudioDecNodeCommand cmd; |
| cmd.PVMFOMXAudioDecNodeCommandBase::Construct(s, PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_CANCELALL, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXAudioDecNode::CancelCommand(PVMFSessionId s, PVMFCommandId aCmdId, const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::CancelCommand() called")); |
| PVMFOMXAudioDecNodeCommand cmd; |
| cmd.PVMFOMXAudioDecNodeCommandBase::Construct(s, PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_CANCELCMD, aCmdId, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PVMFOMXAudioDecNode::SetDecoderNodeConfiguration(PVMFOMXAudioDecNodeConfig& aNodeConfig) |
| { |
| iNodeConfig = aNodeConfig; |
| return PVMFSuccess; |
| } |
| |
| |
| ///////////////////// |
| // Private Section // |
| ///////////////////// |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // Class Constructor |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFOMXAudioDecNode::PVMFOMXAudioDecNode(int32 aPriority) : |
| OsclActiveObject(aPriority, "PVMFOMXAudioDecNode"), |
| iInPort(NULL), |
| iOutPort(NULL), |
| iOutBufMemoryPool(NULL), |
| iMediaDataMemPool(NULL), |
| iOMXComponentOutputBufferSize(0), |
| iOutputAllocSize(0), |
| iProcessingState(EPVMFOMXAudioDecNodeProcessingState_Idle), |
| iOMXAudioDecoder(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), |
| iNewWidth(0), |
| iNewHeight(0), |
| iAvgBitrateValue(0), |
| iResetInProgress(false), |
| iResetMsgSent(false) |
| { |
| iInterfaceState = EPVMFNodeCreated; |
| |
| iNodeConfig.iMimeType = PVOMXAUDIODECNODE_CONFIG_MIMETYPE_DEF; |
| |
| |
| int32 err; |
| OSCL_TRY(err, |
| |
| //Create the input command queue. Use a reserve to avoid lots of |
| //dynamic memory allocation. |
| iInputCommands.Construct(PVMF_OMXAUDIODEC_NODE_COMMAND_ID_START, PVMF_OMXAUDIODEC_NODE_COMMAND_VECTOR_RESERVE); |
| |
| //Create the "current command" queue. It will only contain one |
| //command at a time, so use a reserve of 1. |
| iCurrentCommand.Construct(0, 1); |
| |
| //Set the node capability data. |
| //This node can support an unlimited number of ports. |
| iCapability.iCanSupportMultipleInputPorts = false; |
| iCapability.iCanSupportMultipleOutputPorts = false; |
| iCapability.iHasMaxNumberOfPorts = true; |
| iCapability.iMaxNumberOfPorts = 2; |
| iCapability.iInputFormatCapability.push_back(PVMF_MPEG4_AUDIO); |
| iCapability.iInputFormatCapability.push_back(PVMF_ADIF); |
| iCapability.iInputFormatCapability.push_back(PVMF_LATM); |
| iCapability.iInputFormatCapability.push_back(PVMF_ASF_MPEG4_AUDIO); |
| iCapability.iInputFormatCapability.push_back(PVMF_AAC_SIZEHDR); |
| |
| iCapability.iInputFormatCapability.push_back(PVMF_AMR_IF2); |
| iCapability.iInputFormatCapability.push_back(PVMF_AMR_IETF); |
| iCapability.iInputFormatCapability.push_back(PVMF_AMR_IETF_COMBINED); |
| iCapability.iInputFormatCapability.push_back(PVMF_AMRWB_IETF); |
| iCapability.iInputFormatCapability.push_back(PVMF_AMRWB_IETF_PAYLOAD); |
| |
| iCapability.iInputFormatCapability.push_back(PVMF_MP3); |
| |
| iCapability.iInputFormatCapability.push_back(PVMF_WMA); |
| |
| iCapability.iOutputFormatCapability.push_back(PVMF_PCM16); |
| |
| iAvailableMetadataKeys.reserve(PVMF_OMXAUDIODEC_NUM_METADATA_VALUES); |
| iAvailableMetadataKeys.clear(); |
| ); |
| |
| |
| |
| iThreadSafeHandlerEventHandler = NULL; |
| iThreadSafeHandlerEmptyBufferDone = NULL; |
| iThreadSafeHandlerFillBufferDone = NULL; |
| |
| iInBufMemoryPool = NULL; |
| iOutBufMemoryPool = NULL; |
| |
| // init to some value |
| iOMXComponentOutputBufferSize = 0; |
| iNumOutputBuffers = 0; |
| iOMXComponentInputBufferSize = 0; |
| iNumInputBuffers = 0; |
| |
| iDoNotSendOutputBuffersDownstreamFlag = false; |
| iDoNotSaveInputBuffersFlag = false; |
| |
| iOutputBuffersFreed = true;// buffers have not been created yet, so they can be considered freed |
| iInputBuffersFreed = true; |
| |
| // dynamic port reconfig init vars |
| iSecondPortReportedChange = false; |
| iDynamicReconfigInProgress = false; |
| iPauseCommandWasSentToComponent = false; |
| iStopCommandWasSentToComponent = false; |
| |
| // EOS flag init |
| iIsEOSSentToComponent = false; |
| iIsEOSReceivedFromComponent = false; |
| |
| // LATM init |
| iLATMParser = NULL; |
| iLATMConfigBuffer = NULL; |
| iLATMConfigBufferSize = 0; |
| |
| // reset repositioning related flags |
| iIsRepositioningRequestSentToComponent = false; |
| iIsRepositionDoneReceivedFromComponent = false; |
| iIsOutputPortFlushed = false; |
| iIsInputPortFlushed = false; |
| |
| iIsRepositionIdleDoneReceivedFromComponent = false; |
| iIsRepositionIdleRequestSentToComponent = false; |
| iIsRepositionExecRequestSentToComponent = false; |
| iIsRepositionExecDoneReceivedFromComponent = false; |
| |
| // init state of component |
| iCurrentDecoderState = OMX_StateInvalid; |
| |
| iOutTimeStamp = 0; |
| |
| // counts output frames (for logging) |
| iFrameCounter = 0; |
| //Try Allocate FSI buffer |
| |
| // Do This first in case of Query |
| OSCL_TRY(err, iFsiFragmentAlloc.size(PVOMXAUDIODEC_MEDIADATA_POOLNUM, sizeof(channelSampleInfo))); |
| |
| |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // Local Run Routine |
| ///////////////////////////////////////////////////////////////////////////// |
| void PVMFOMXAudioDecNode::Run() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::Run() In")); |
| |
| // if reset is in progress, call DoReset again until Reset Msg is sent |
| if ((iResetInProgress == true) && |
| (iResetMsgSent == false) && |
| (iCurrentCommand.size() > 0) && |
| (iCurrentCommand.front().iCmd == PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_RESET) |
| ) |
| { |
| DoReset(iCurrentCommand.front()); |
| 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))) |
| { |
| // 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, "PVMFOMXAudioDecNode::Run() - rescheduling after process command")); |
| RunIfNotReady(); |
| } |
| return; |
| } |
| |
| if (!iInputCommands.empty()) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVMFOMXAudioDecNode::Run() - rescheduling to process more commands")); |
| RunIfNotReady(); |
| } |
| } |
| |
| if (((iCurrentCommand.size() == 0) && (iInterfaceState != EPVMFNodeStarted)) || |
| ((iCurrentCommand.size() > 0) && (iCurrentCommand.front().iCmd == PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_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, "PVMFOMXAudioDecNode::Run() - Node not in Started state yet")); |
| 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, "PVMFOMXAudioDecNode::Run() - Outgoing Port Busy, cannot send more msgs")); |
| break; |
| } |
| } |
| } |
| |
| int loopCount = 0; |
| // try to consume all data from input port at once |
| #if (PVLOGGER_INST_LEVEL >= PVLOGMSG_INST_REL) |
| uint32 startticks = OsclTickCount::TickCount(); |
| uint32 starttime = OsclTickCount::TicksToMsec(startticks); |
| #endif |
| |
| do |
| { |
| // Process port activity if there is no input data that is being processed |
| // Do not accept any input if EOS needs to be sent out |
| if (iInPort && (iInPort->IncomingMsgQueueSize() > 0) && (iDataIn.GetRep() == NULL) && !iEndOfDataReached) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVMFOMXAudioDecNode::Run() - Getting more input")); |
| 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, "PVMFOMXAudioDecNode::Run() - Repositioning not done yet")); |
| |
| 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 == EPVMFOMXAudioDecNodeProcessingState_ReadyToDecode) && |
| (iResetMsgSent == false)) || |
| ((iDynamicReconfigInProgress == true) && (iResetMsgSent == false)) |
| |
| ) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, |
| (0, "PVMFOMXAudioDecNode::Run() - Calling HandleProcessingState")); |
| |
| // input data is available, that means there is video 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, "PVMFOMXAudioDecNode::Run() - HandleProcessingState did not return Success")); |
| |
| 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 = (endtime - starttime); |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iRunLogger, PVLOGMSG_INFO, |
| (0, "PVMFOMXAudioDecNode::Run() - LoopCount = %d, Time spent in loop(in ms) = %d, iNumOutstandingInputBuffers = %d, iNumOutstandingOutputBuffers = %d ", |
| 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, "PVMFOMXAudioDecNode::Run() - Sending EOS marked buffer To Component ")); |
| |
| 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 != EPVMFOMXAudioDecNodeProcessingState_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; |
| } |
| } |
| |
| // 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, "PVMFOMXAudioDecNode::Run() - Received EOS from component, Sending EOS msg downstream ")); |
| |
| 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, "PVMFOMXAudioDecNode::Run() - - EOS cannot be sent downstream, outgoing queue busy - wait")); |
| 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, "PVMFOMXAudioDecNode::Run() - EOS was queued to be sent downstream")); |
| |
| 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 == PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_FLUSH) && |
| (iInPort->IncomingMsgQueueSize() == 0) && |
| (iOutPort->OutgoingMsgQueueSize() == 0) && |
| (iDataIn.GetRep() == NULL)) |
| { |
| //flush command is completed |
| //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, "PVMFOMXAudioDecNode::Run() - Flush pending")); |
| 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, "PVMFOMXAudioDecNode::Run() Out")); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // This routine will dispatch recived commands |
| ///////////////////////////////////////////////////////////////////////////// |
| bool PVMFOMXAudioDecNode::ProcessCommand(PVMFOMXAudioDecNodeCommand& 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 PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_QUERYUUID: |
| DoQueryUuid(aCmd); |
| break; |
| |
| case PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_QUERYINTERFACE: |
| DoQueryInterface(aCmd); |
| break; |
| |
| case PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_REQUESTPORT: |
| DoRequestPort(aCmd); |
| break; |
| |
| case PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_RELEASEPORT: |
| DoReleasePort(aCmd); |
| break; |
| |
| case PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_INIT: |
| DoInit(aCmd); |
| break; |
| |
| case PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_PREPARE: |
| DoPrepare(aCmd); |
| break; |
| |
| case PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_START: |
| DoStart(aCmd); |
| break; |
| |
| case PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_STOP: |
| DoStop(aCmd); |
| break; |
| |
| case PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_FLUSH: |
| DoFlush(aCmd); |
| break; |
| |
| case PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_PAUSE: |
| DoPause(aCmd); |
| break; |
| |
| case PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_RESET: |
| DoReset(aCmd); |
| break; |
| |
| case PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_CANCELCMD: |
| DoCancelCommand(aCmd); |
| break; |
| |
| case PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_CANCELALL: |
| DoCancelAllCommands(aCmd); |
| break; |
| |
| case PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_GETNODEMETADATAKEY: |
| { |
| PVMFStatus retval = DoGetNodeMetadataKey(aCmd); |
| CommandComplete(iInputCommands, aCmd, retval); |
| } |
| break; |
| |
| case PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_GETNODEMETADATAVALUE: |
| { |
| PVMFStatus retval = DoGetNodeMetadataValue(aCmd); |
| CommandComplete(iInputCommands, aCmd, retval); |
| } |
| break; |
| |
| default://unknown command type |
| CommandComplete(iInputCommands, aCmd, PVMFFailure); |
| break; |
| } |
| |
| return true; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // This routine will process incomming message from the port |
| ///////////////////////////////////////////////////////////////////////////// |
| bool PVMFOMXAudioDecNode::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 PVMFOMXAudioDecNode::ProcessIncomingMsg: aPort=0x%x", this, aPort)); |
| |
| PVMFStatus status = PVMFFailure; |
| #ifdef SIMULATE_DROP_MSGS |
| if ((((PVMFOMXAudioDecPort*)aPort)->iNumFramesConsumed % 300 == 299)) // && (((PVMFOMXAudioDecPort*)aPort)->iNumFramesConsumed < 30) ) |
| { |
| |
| // just dequeue |
| PVMFSharedMediaMsgPtr msg; |
| |
| status = aPort->DequeueIncomingMsg(msg); |
| ((PVMFOMXAudioDecPort*)aPort)->iNumFramesConsumed++; |
| status = aPort->DequeueIncomingMsg(msg); |
| ((PVMFOMXAudioDecPort*)aPort)->iNumFramesConsumed++; |
| status = aPort->DequeueIncomingMsg(msg); |
| ((PVMFOMXAudioDecPort*)aPort)->iNumFramesConsumed++; |
| |
| #ifdef _DEBUG |
| printf("PVMFOMXAudioDecNode::ProcessIncomingMsg() SIMULATED DROP 3 MSGS\n"); |
| #endif |
| |
| |
| } |
| #endif |
| |
| #ifdef SIMULATE_BOS |
| |
| if ((((PVMFOMXAudioDecPort*)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(); |
| iSendBOS = true; |
| |
| #ifdef _DEBUG |
| printf("PVMFOMXAudioDecNode::ProcessIncomingMsg() SIMULATED BOS\n"); |
| #endif |
| ((PVMFOMXAudioDecPort*)aPort)->iNumFramesConsumed++; |
| return true; |
| |
| } |
| #endif |
| #ifdef SIMULATE_PREMATURE_EOS |
| if (((PVMFOMXAudioDecPort*)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); |
| |
| ((PVMFOMXAudioDecPort*)aPort)->iNumFramesConsumed++; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::ProcessIncomingMsg: SIMULATED EOS")); |
| #ifdef _DEBUG |
| printf("PVMFOMXAudioDecNode::ProcessIncomingMsg() SIMULATED EOS\n"); |
| #endif |
| // Set EOS flag |
| iEndOfDataReached = true; |
| // Save the timestamp for the EOS cmd |
| iEndOfDataTimestamp = mediaMsgOut->getTimestamp(); |
| |
| return true; |
| } |
| |
| #endif |
| |
| |
| |
| PVMFSharedMediaMsgPtr msg; |
| |
| status = aPort->DequeueIncomingMsg(msg); |
| if (status != PVMFSuccess) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "0x%x PVMFOMXAudioDecNode::ProcessIncomingMsg: Error - DequeueIncomingMsg failed", this)); |
| 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; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::ProcessIncomingMsg: Received BOS stream %d, timestamp %d", iStreamID, iBOSTimestamp)); |
| ((PVMFOMXAudioDecPort*)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, "PVMFOMXAudioDecNode::ProcessIncomingMsg: Received EOS")); |
| |
| ((PVMFOMXAudioDecPort*)aPort)->iNumFramesConsumed++; |
| return true; // do not do conversion into media data, just set the flag and leave |
| } |
| |
| |
| /////////////////////////////////////////////////////////////////////////////////////// |
| /////////////////////////////////////////////////////////////////////// |
| // For LATM data, need to convert to raw bitstream |
| if (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_LATM) |
| { |
| // Keep looping and parsing LATM data until frame complete or data queue runs out |
| uint8 retval; //=FRAME_INCOMPLETE; |
| // if LATM parser does not exist (very first frame), create it: |
| if (iLATMParser == NULL) |
| { |
| // Create and configure the LATM parser based on the stream MUX config |
| // which should be sent as the format specific config in the first media data |
| if (CreateLATMParser() != PVMFSuccess) |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::Process Incoming Msg - LATM parser cannot be created")); |
| OSCL_ASSERT(false); |
| ReportErrorEvent(PVMFErrResourceConfiguration); |
| ChangeNodeState(EPVMFNodeError); |
| return true; |
| } |
| |
| // get FSI |
| OsclRefCounterMemFrag DataFrag; |
| msg->getFormatSpecificInfo(DataFrag); |
| |
| //get pointer to the data fragment |
| uint8* initbuffer = (uint8 *) DataFrag.getMemFragPtr(); |
| uint32 initbufsize = (int32) DataFrag.getMemFragSize(); |
| |
| iLATMConfigBufferSize = initbufsize; |
| iLATMConfigBuffer = iLATMParser->ParseStreamMuxConfig(initbuffer, (int32 *) & iLATMConfigBufferSize); |
| if (iLATMConfigBuffer == NULL) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::ProcessIncomingMsg() LATM Stream MUX config parsing failed")); |
| OSCL_ASSERT(false); |
| ReportErrorEvent(PVMFErrResourceConfiguration); |
| ChangeNodeState(EPVMFNodeError); |
| return true; |
| } |
| |
| } |
| |
| do |
| { |
| 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, "PVMFOMXAudioDecNode::ProcessIncomingMsg: Received EOS")); |
| |
| ((PVMFOMXAudioDecPort*)aPort)->iNumFramesConsumed++; |
| return true; // do not do conversion into media data, just set the flag and leave |
| |
| } |
| // Convert the next input media msg to media data |
| PVMFSharedMediaDataPtr mediaData; |
| convertToPVMFMediaData(mediaData, msg); |
| |
| |
| ((PVMFOMXAudioDecPort*)aPort)->iNumFramesConsumed++; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iDataPathLogger, PVLOGMSG_INFO, |
| (0, "PVMFOMXAudioDecNode::ProcessIncomingMsg: TS=%d, SEQNUM= %d", msg->getTimestamp(), msg->getSeqNum())); |
| |
| |
| // Convert the LATM data to raw bitstream |
| retval = iLATMParser->compose(mediaData); |
| |
| // if frame is complete, break out of the loop |
| if (retval != FRAME_INCOMPLETE && retval != FRAME_ERROR) |
| break; |
| |
| // frame is not complete, keep looping |
| if (aPort->IncomingMsgQueueSize() == 0) |
| { |
| // no more data in the input port queue, unbind current msg, and return |
| msg.Unbind(); |
| // enable reading more data from port |
| break; |
| } |
| else |
| { |
| msg.Unbind(); |
| aPort->DequeueIncomingMsg(msg); // dequeue the message directly from input port |
| |
| } |
| |
| // Log parser error |
| if (retval == FRAME_ERROR) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFAACDecNode::GetInputMediaData() LATM parser error")); |
| } |
| } |
| while ((retval == FRAME_INCOMPLETE || retval == FRAME_ERROR)); |
| |
| if (retval == FRAME_COMPLETE) |
| { |
| // Save the media data containing the parser data as the input media data |
| iDataIn = iLATMParser->GetOutputBuffer(); |
| // set the MARKER bit on the data msg, since this is a complete frame produced by LATM parser |
| iDataIn->setMarkerInfo(PVMF_MEDIA_DATA_MARKER_INFO_M_BIT); |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iLogger, PVLOGMSG_INFO, |
| (0, "PVMFOMXAudioDecNode::ProcessIncomingMsg: - LATM frame assembled")); |
| |
| } |
| else if ((retval == FRAME_INCOMPLETE) || (retval == FRAME_ERROR)) |
| { |
| // Do nothing and wait for more data to come in |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iLogger, PVLOGMSG_INFO, |
| (0, "PVMFOMXAudioDecNode::ProcessIncomingMsg: - incomplete LATM")); |
| // return immediately (i.e. don't assign anything to iDataIn, which will prevent |
| // processing |
| return true; |
| } |
| else if (retval == FRAME_OUTPUTNOTAVAILABLE) |
| { |
| // This should not happen since this node processes one parsed media data at a time |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::ProcessIncomingMsg: LATM parser OUTPUT NOT AVAILABLE")); |
| |
| msg.Unbind(); |
| |
| OSCL_ASSERT(false); |
| ReportErrorEvent(PVMFErrResourceConfiguration); |
| ChangeNodeState(EPVMFNodeError); |
| |
| return true; |
| } |
| } |
| ///////////////////////////////////////////////////////// |
| ////////////////////////// |
| else |
| { |
| // regular (i.e. Non-LATM case) |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iDataPathLogger, PVLOGMSG_INFO, |
| (0, "PVMFOMXAudioDecNode::ProcessIncomingMsg: TS=%d, SEQNUM= %d", msg->getTimestamp(), msg->getSeqNum())); |
| |
| convertToPVMFMediaData(iDataIn, msg); |
| ((PVMFOMXAudioDecPort*)aPort)->iNumFramesConsumed++; |
| } |
| |
| iCurrFragNum = 0; // for new message, reset the fragment counter |
| iIsNewDataFragment = true; |
| |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::ProcessIncomingMsg() Received %d frames", ((PVMFOMXAudioDecPort*)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 PVMFOMXAudioDecNode::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 PVMFOMXAudioDecNode::ProcessOutgoingMsg: aPort=0x%x", this, aPort)); |
| |
| PVMFStatus status = aPort->Send(); |
| if (status == PVMFErrBusy) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, |
| (0, "0x%x PVMFOMXAudioDecNode::ProcessOutgoingMsg: Connected port goes into busy state", this)); |
| } |
| |
| //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 PVMFOMXAudioDecNode::Run: Error - ProcessPortActivity failed. port=0x%x, type=%d", |
| this, 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 PVMFOMXAudioDecNode::HandleProcessingState() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::HandleProcessingState() In")); |
| |
| PVMFStatus status = PVMFSuccess; |
| |
| switch (iProcessingState) |
| { |
| case EPVMFOMXAudioDecNodeProcessingState_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, "PVMFOMXAudioDecNode::HandleProcessingState() Decoder initialization failed")); |
| ReportErrorEvent(PVMFErrResourceConfiguration); |
| ChangeNodeState(EPVMFNodeError); |
| break; |
| } |
| |
| iProcessingState = EPVMFOMXAudioDecNodeProcessingState_ReadyToDecode; |
| // spin once to send output buffers |
| RunIfNotReady(); |
| status = PVMFSuccess; // allow rescheduling |
| } |
| break; |
| } |
| |
| case EPVMFOMXAudioDecNodeProcessingState_WaitForInitCompletion: |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() WaitForInitCompletion -> wait for config buffer to return")); |
| |
| |
| status = PVMFErrNoMemory; // prevent rescheduling |
| break; |
| } |
| // The FOLLOWING 4 states handle Dynamic Port Reconfiguration |
| case EPVMFOMXAudioDecNodeProcessingState_PortReconfig: |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> Sending Port Disable Command")); |
| |
| // 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(iOMXAudioDecoder, &sState); |
| if (err != OMX_ErrorNone) |
| { |
| //Error condition report |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState (): PortReconfig Can't get State of decoder - trying to send port flush request!")); |
| |
| sState = OMX_StateInvalid; |
| ReportErrorEvent(PVMFErrResourceConfiguration); |
| ChangeNodeState(EPVMFNodeError); |
| status = PVMFFailure; |
| break; |
| } |
| |
| if ((sState != OMX_StateExecuting) && (sState != OMX_StatePause)) |
| { |
| // possibly as a consequence of a previously queued cmd to go to Idle state? |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState (): PortReconfig: Component State is not executing or paused, do not proceed with port flush")); |
| } |
| else |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState (): PortReconfig Sending Flush command to component")); |
| |
| // the port will now start returning outstanding buffers |
| // set the flag to prevent output from going downstream (in case of output port being reconfigured) |
| // set the flag to prevent input from being saved and returned to component (in case of input port being reconfigured) |
| // 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, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> Output Port")); |
| } |
| else if (iPortIndexForDynamicReconfig == iInputPortIndex) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> Input Port")); |
| |
| iDoNotSaveInputBuffersFlag = true; |
| } |
| else |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> UNKNOWN PORT")); |
| sState = OMX_StateInvalid; |
| ReportErrorEvent(PVMFErrResourceConfiguration); |
| ChangeNodeState(EPVMFNodeError); |
| status = PVMFFailure; |
| break; |
| } |
| |
| // send command to flush appropriate port |
| err = OMX_SendCommand(iOMXAudioDecoder, OMX_CommandFlush, iPortIndexForDynamicReconfig, NULL); |
| if (err != OMX_ErrorNone) |
| { |
| //Error condition report |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState (): PortReconfig : Can't send flush command !")); |
| |
| 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 = EPVMFOMXAudioDecNodeProcessingState_WaitForBufferReturn; |
| // fall through to the next case to check if all buffers are already back |
| } |
| |
| case EPVMFOMXAudioDecNodeProcessingState_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, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> WaitForBufferReturn ")); |
| // check if it's output port being reconfigured |
| if (iPortIndexForDynamicReconfig == iOutputPortIndex) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> WaitForBufferReturn Output ")); |
| |
| // if all buffers have returned, free them |
| if (iNumOutstandingOutputBuffers == 0) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> all output buffers are back, send port disable command")); |
| |
| // port reconfiguration is required. Only one port at a time is disabled and then re-enabled after buffer resizing |
| OMX_SendCommand(iOMXAudioDecoder, OMX_CommandPortDisable, iPortIndexForDynamicReconfig, NULL); |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> all output buffers are back, free them")); |
| 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, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> Cannot free output buffers ")); |
| |
| 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 != EPVMFOMXAudioDecNodeProcessingState_PortReEnable) |
| iProcessingState = EPVMFOMXAudioDecNodeProcessingState_WaitForPortDisable; |
| |
| status = PVMFSuccess; // allow rescheduling of the node potentially |
| } |
| else |
| status = PVMFErrNoMemory; // must wait for buffers to come back. No point in automatic rescheduling |
| // but each buffer will reschedule the node when it comes in |
| } |
| else if (iPortIndexForDynamicReconfig == iInputPortIndex) |
| { // this is input port |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> WaitForBufferReturn Input")); |
| |
| |
| // if all buffers have returned, free them |
| if (iNumOutstandingInputBuffers == 0) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> all input buffers are back, send port disable command")); |
| |
| // port reconfiguration is required. Only one port at a time is disabled and then re-enabled after buffer resizing |
| OMX_SendCommand(iOMXAudioDecoder, OMX_CommandPortDisable, iPortIndexForDynamicReconfig, NULL); |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> all input buffers are back, free them")); |
| |
| |
| 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, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> Cannot free input buffers ")); |
| |
| 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 != EPVMFOMXAudioDecNodeProcessingState_PortReEnable) |
| iProcessingState = EPVMFOMXAudioDecNodeProcessingState_WaitForPortDisable; |
| |
| status = PVMFSuccess; // allow rescheduling of the node |
| } |
| else |
| status = PVMFErrNoMemory; // must wait for buffers to come back. No point in automatic |
| // rescheduling. Each buffer will reschedule the node |
| // when it comes in |
| } |
| else |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() WaitForBufferReturn -> UNKNOWN PORT")); |
| } |
| |
| // the state will be changed to PortReEnable once we get confirmation that Port was actually disabled |
| break; |
| } |
| |
| case EPVMFOMXAudioDecNodeProcessingState_WaitForPortDisable: |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> wait for port disable callback")); |
| // do nothing. Just wait for the port to become disabled (we'll get event from component, which will |
| // transition the state to PortReEnable |
| status = PVMFErrNoMemory; // prevent Rescheduling the node |
| break; |
| } |
| |
| case EPVMFOMXAudioDecNodeProcessingState_PortReEnable: |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> Sending reenable port command")); |
| // set the port index so that we get parameters for the proper port |
| iParamPort.nPortIndex = iPortIndexForDynamicReconfig; |
| // iParamPort.nVersion = OMX_VERSION; |
| |
| // get new parameters of the port |
| OMX_GetParameter(iOMXAudioDecoder, OMX_IndexParamPortDefinition, &iParamPort); |
| |
| // send command for port re-enabling (for this to happen, we must first recreate the buffers) |
| OMX_SendCommand(iOMXAudioDecoder, OMX_CommandPortEnable, iPortIndexForDynamicReconfig, NULL); |
| |
| |
| // get also input info (for frame duration if necessary) |
| OMX_ERRORTYPE Err; |
| OMX_PTR CodecProfilePtr; |
| OMX_INDEXTYPE CodecProfileIndx; |
| OMX_AUDIO_PARAM_AACPROFILETYPE Audio_Aac_Param; |
| |
| // determine the proper index and structure (based on codec type) |
| if (iInPort) |
| { |
| switch (((PVMFOMXAudioDecPort*)iInPort)->iFormat) |
| { |
| // AAC |
| case PVMF_MPEG4_AUDIO: |
| case PVMF_LATM: |
| case PVMF_ADIF: |
| case PVMF_ASF_MPEG4_AUDIO: |
| case PVMF_AAC_SIZEHDR: // for testing |
| CodecProfilePtr = (OMX_PTR) & Audio_Aac_Param; |
| CodecProfileIndx = OMX_IndexParamAudioAac; |
| Audio_Aac_Param.nPortIndex = iInputPortIndex; |
| Audio_Aac_Param.nSize = sizeof(OMX_AUDIO_PARAM_AACPROFILETYPE); |
| Audio_Aac_Param.nVersion.s.nVersionMajor = SPECVERSIONMAJOR; |
| Audio_Aac_Param.nVersion.s.nVersionMinor = SPECVERSIONMINOR; |
| Audio_Aac_Param.nVersion.s.nRevision = SPECREVISION; |
| Audio_Aac_Param.nVersion.s.nStep = SPECSTEP; |
| |
| // get parameters: |
| Err = OMX_GetParameter(iOMXAudioDecoder, CodecProfileIndx, CodecProfilePtr); |
| if (Err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> Input port parameters problem")); |
| |
| SetState(EPVMFNodeError); |
| ReportErrorEvent(PVMFErrResource); |
| return PVMFErrResource; |
| } |
| |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| |
| |
| |
| switch (((PVMFOMXAudioDecPort*)iInPort)->iFormat) |
| { |
| case PVMF_MPEG4_AUDIO: |
| case PVMF_LATM: |
| case PVMF_ADIF: |
| case PVMF_ASF_MPEG4_AUDIO: |
| case PVMF_AAC_SIZEHDR: // for testing |
| iSamplesPerFrame = Audio_Aac_Param.nFrameLength; |
| break; |
| |
| // AMR |
| case PVMF_AMR_IF2: |
| case PVMF_AMR_IETF: |
| case PVMF_AMR_IETF_COMBINED: |
| // AMR NB has fs=8khz Mono and the frame is 20ms long, i.e. there is 160 samples per frame |
| iSamplesPerFrame = PVOMXAUDIODEC_AMRNB_SAMPLES_PER_FRAME; |
| break; |
| |
| case PVMF_AMRWB_IETF: |
| case PVMF_AMRWB_IETF_PAYLOAD: |
| // AMR WB has fs=16khz Mono and the frame is 20ms long, i.e. there is 320 samples per frame |
| iSamplesPerFrame = PVOMXAUDIODEC_AMRWB_SAMPLES_PER_FRAME; |
| break; |
| |
| case PVMF_MP3: |
| // frame size is either 576 or 1152 samples per frame. However, this information cannot be |
| // obtained through OMX MP3 Params. Assume that it's 1152 |
| iSamplesPerFrame = PVOMXAUDIODEC_MP3_DEFAULT_SAMPLES_PER_FRAME; |
| break; |
| |
| case PVMF_WMA: |
| // output frame size is unknown in WMA. However, the PV-WMA decoder can control the number |
| // of samples it places in an output buffer, so we can create an output buffer of arbitrary size |
| // and let the decoder control how it is filled |
| iSamplesPerFrame = 0; // unknown |
| break; |
| |
| default: |
| break; |
| } |
| |
| if (iPortIndexForDynamicReconfig == iOutputPortIndex) |
| { |
| |
| // GET the output buffer params and sizes |
| OMX_AUDIO_PARAM_PCMMODETYPE Audio_Pcm_Param; |
| Audio_Pcm_Param.nPortIndex = iOutputPortIndex; // we're looking for output port params |
| Audio_Pcm_Param.nSize = sizeof(OMX_AUDIO_PARAM_PCMMODETYPE); |
| Audio_Pcm_Param.nVersion.s.nVersionMajor = SPECVERSIONMAJOR; |
| Audio_Pcm_Param.nVersion.s.nVersionMinor = SPECVERSIONMINOR; |
| Audio_Pcm_Param.nVersion.s.nRevision = SPECREVISION; |
| Audio_Pcm_Param.nVersion.s.nStep = SPECSTEP; |
| |
| |
| Err = OMX_GetParameter(iOMXAudioDecoder, OMX_IndexParamAudioPcm, &Audio_Pcm_Param); |
| if (Err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> Cannot get component output parameters")); |
| |
| SetState(EPVMFNodeError); |
| ReportErrorEvent(PVMFErrResource); |
| return PVMFErrResource; |
| } |
| |
| iPCMSamplingRate = Audio_Pcm_Param.nSamplingRate; // can be set to 0 (if unknown) |
| |
| if (iPCMSamplingRate == 0) // use default sampling rate (i.e. 48000) |
| iPCMSamplingRate = PVOMXAUDIODEC_DEFAULT_SAMPLINGRATE; |
| |
| iNumberOfAudioChannels = Audio_Pcm_Param.nChannels; // should be 1 or 2 |
| if (iNumberOfAudioChannels != 1 && iNumberOfAudioChannels != 2) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> Output parameters num channels = %d", iNumberOfAudioChannels)); |
| |
| SetState(EPVMFNodeError); |
| ReportErrorEvent(PVMFErrResource); |
| return PVMFErrResource; |
| } |
| |
| if (iSamplesPerFrame != 0) // if this value is known |
| { |
| // CALCULATE NumBytes per frame, Msec per frame, etc. |
| iNumBytesPerFrame = 2 * iSamplesPerFrame * iNumberOfAudioChannels; |
| iMilliSecPerFrame = (iSamplesPerFrame * 1000) / iPCMSamplingRate; |
| // Determine the size of each PCM output buffer. Size would be big enough to hold certain time amount of PCM data |
| uint32 numframes = PVOMXAUDIODEC_DEFAULT_OUTPUTPCM_TIME / iMilliSecPerFrame; |
| |
| if (PVOMXAUDIODEC_DEFAULT_OUTPUTPCM_TIME % iMilliSecPerFrame) |
| { |
| // If there is a remainder, include one more frame |
| ++numframes; |
| } |
| |
| // set the output buffer size accordingly: |
| iOMXComponentOutputBufferSize = numframes * iNumBytesPerFrame; |
| } |
| else |
| iOMXComponentOutputBufferSize = (iPCMSamplingRate * 1000) / (PVOMXAUDIODEC_DEFAULT_OUTPUTPCM_TIME); |
| |
| // do we need to increase the number of buffers? |
| if (iNumOutputBuffers < iParamPort.nBufferCountMin) |
| iNumOutputBuffers = iParamPort.nBufferCountMin; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() new output buffers %d, size %d", iNumOutputBuffers, iOMXComponentOutputBufferSize)); |
| |
| /* Allocate output buffers */ |
| if (!CreateOutMemPool(iNumOutputBuffers)) |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> Cannot allocate output buffers ")); |
| |
| SetState(EPVMFNodeError); |
| ReportErrorEvent(PVMFErrNoMemory); |
| return PVMFErrNoMemory; |
| } |
| |
| if (!ProvideBuffersToComponent(iOutBufMemoryPool, // allocator |
| iOutputAllocSize, // size to allocate from pool (hdr only or hdr+ buffer) |
| iNumOutputBuffers, // number of buffers |
| iOMXComponentOutputBufferSize, // actual buffer size |
| iOutputPortIndex, // port idx |
| iOMXComponentSupportsExternalOutputBufferAlloc, // can component use OMX_UseBuffer |
| false // this is not input |
| )) |
| { |
| |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> Cannot provide output buffers to component")); |
| |
| SetState(EPVMFNodeError); |
| ReportErrorEvent(PVMFErrNoMemory); |
| return PVMFErrNoMemory; |
| |
| } |
| |
| // do not drop output any more, i.e. enable output to be sent downstream |
| iDoNotSendOutputBuffersDownstreamFlag = false; |
| |
| |
| } |
| else |
| { |
| // this is input port |
| |
| iOMXComponentInputBufferSize = iParamPort.nBufferSize; |
| // do we need to increase the number of buffers? |
| if (iNumInputBuffers < iParamPort.nBufferCountMin) |
| iNumInputBuffers = iParamPort.nBufferCountMin; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() new buffers %d, size %d", iNumInputBuffers, iOMXComponentInputBufferSize)); |
| |
| /* Allocate input buffers */ |
| if (!CreateInputMemPool(iNumInputBuffers)) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> Cannot allocate new input buffers to component")); |
| |
| SetState(EPVMFNodeError); |
| ReportErrorEvent(PVMFErrNoMemory); |
| return PVMFErrNoMemory; |
| } |
| |
| if (!ProvideBuffersToComponent(iInBufMemoryPool, // allocator |
| iInputAllocSize, // size to allocate from pool (hdr only or hdr+ buffer) |
| iNumInputBuffers, // number of buffers |
| iOMXComponentInputBufferSize, // actual buffer size |
| iInputPortIndex, // port idx |
| iOMXComponentSupportsExternalInputBufferAlloc, // can component use OMX_UseBuffer |
| true // this is input |
| )) |
| { |
| |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> Cannot provide new input buffers to component")); |
| |
| SetState(EPVMFNodeError); |
| ReportErrorEvent(PVMFErrNoMemory); |
| return PVMFErrNoMemory; |
| |
| } |
| // do not drop partially consumed input |
| iDoNotSaveInputBuffersFlag = false; |
| |
| } |
| |
| // if the callback that the port was re-enabled has not arrived yet, wait for it |
| // if it has arrived, it will set the state to either PortReconfig or to ReadyToDecode |
| if (iProcessingState != EPVMFOMXAudioDecNodeProcessingState_PortReconfig && |
| iProcessingState != EPVMFOMXAudioDecNodeProcessingState_ReadyToDecode) |
| iProcessingState = EPVMFOMXAudioDecNodeProcessingState_WaitForPortEnable; |
| |
| status = PVMFSuccess; // allow rescheduling of the node |
| break; |
| } |
| |
| case EPVMFOMXAudioDecNodeProcessingState_WaitForPortEnable: |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() Port Reconfiguration -> wait for port enable callback")); |
| // do nothing. Just wait for the port to become enabled (we'll get event from component, which will |
| // transition the state to ReadyToDecode |
| status = PVMFErrNoMemory; // prevent ReScheduling |
| break; |
| } |
| |
| // NORMAL DATA FLOW STATE: |
| case EPVMFOMXAudioDecNodeProcessingState_ReadyToDecode: |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() Ready To Decode start")); |
| // 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, "PVMFOMXAudioDecNode::HandleProcessingState() Sending previous - partially consumed input back to the OMX component")); |
| |
| OMX_EmptyThisBuffer(iOMXAudioDecoder, 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 EPVMFOMXAudioDecNodeProcessingState_Stopping: |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() Stopping -> wait for Component to move from Executing->Idle")); |
| |
| |
| status = PVMFErrNoMemory; // prevent rescheduling |
| break; |
| } |
| |
| case EPVMFOMXAudioDecNodeProcessingState_Pausing: |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleProcessingState() Pausing -> wait for Component to move from Executing->Pause")); |
| |
| |
| status = PVMFErrNoMemory; // prevent rescheduling |
| break; |
| } |
| |
| |
| case EPVMFOMXAudioDecNodeProcessingState_WaitForOutgoingQueue: |
| status = PVMFErrNoMemory; |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::HandleProcessingState() Do nothing since waiting for output port queue to become available")); |
| break; |
| |
| default: |
| break; |
| } |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::HandleProcessingState() Out")); |
| |
| return status; |
| |
| } |
| ///////////////////////////////////////////////////////////////////////////// |
| bool PVMFOMXAudioDecNode::SendOutputBufferToOMXComponent() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::SendOutputBufferToOMXComponent() In")); |
| |
| |
| OutputBufCtrlStruct_Audio *output_buf = NULL; |
| int32 errcode = 0; |
| |
| // try to get output buffer header |
| OSCL_TRY(errcode, output_buf = (OutputBufCtrlStruct_Audio *) iOutBufMemoryPool->allocate(iOutputAllocSize)); |
| if (errcode != 0) |
| { |
| if (errcode == OsclErrNoResources) |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, |
| PVLOGMSG_DEBUG, (0, "PVMFOMXAudioDecNode::SendOutputBufferToOMXComponent() No more output buffers in the mempool")); |
| |
| 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, "PVMFOMXAudioDecNode::SendOutputBufferToOMXComponent() Output mempool error")); |
| |
| |
| 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++; |
| |
| 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; //Clear flags |
| OMX_FillThisBuffer(iOMXAudioDecoder, output_buf->pBufHdr); |
| |
| |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::SendOutputBufferToOMXComponent() Out")); |
| |
| return true; |
| } |
| //////////////////////////////////////////////////////////////////////////////// |
| bool PVMFOMXAudioDecNode::NegotiateComponentParameters() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::NegotiateComponentParameters() In")); |
| |
| OMX_ERRORTYPE Err; |
| // first get the number of ports and port indices |
| OMX_PORT_PARAM_TYPE AudioPortParameters; |
| uint32 NumPorts; |
| uint32 ii; |
| |
| // get starting number |
| Err = OMX_GetParameter(iOMXAudioDecoder, OMX_IndexParamAudioInit, &AudioPortParameters); |
| NumPorts = AudioPortParameters.nPorts; // must be at least 2 of them (in&out) |
| |
| if (Err != OMX_ErrorNone || NumPorts < 2) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::NegotiateComponentParameters() There is insuffucient (%d) ports", NumPorts)); |
| return false; |
| } |
| |
| |
| // loop through video ports starting from the starting index to find index of the first input port |
| for (ii = AudioPortParameters.nStartPortNumber ;ii < AudioPortParameters.nStartPortNumber + NumPorts; ii++) |
| { |
| // get port parameters, and determine if it is input or output |
| // if there are more than 2 ports, the first one we encounter that has input direction is picked |
| |
| iParamPort.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE); |
| |
| //port |
| iParamPort.nPortIndex = ii; |
| Err = OMX_GetParameter(iOMXAudioDecoder, OMX_IndexParamPortDefinition, &iParamPort); |
| |
| if (Err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::NegotiateComponentParameters() Problem negotiating with port %d ", ii)); |
| |
| return false; |
| } |
| |
| if (iParamPort.eDir == OMX_DirInput) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::NegotiateComponentParameters() Found Input port index %d ", ii)); |
| |
| iInputPortIndex = ii; |
| break; |
| } |
| } |
| if (ii == AudioPortParameters.nStartPortNumber + NumPorts) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::NegotiateComponentParameters() Cannot find any input port ")); |
| return false; |
| } |
| |
| |
| // loop through video ports starting from the starting index to find index of the first output port |
| for (ii = AudioPortParameters.nStartPortNumber ;ii < AudioPortParameters.nStartPortNumber + NumPorts; ii++) |
| { |
| // get port parameters, and determine if it is input or output |
| // if there are more than 2 ports, the first one we encounter that has output direction is picked |
| |
| iParamPort.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE); |
| |
| //port |
| iParamPort.nPortIndex = ii; |
| Err = OMX_GetParameter(iOMXAudioDecoder, OMX_IndexParamPortDefinition, &iParamPort); |
| |
| if (Err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::NegotiateComponentParameters() Problem negotiating with port %d ", ii)); |
| |
| return false; |
| } |
| |
| if (iParamPort.eDir == OMX_DirOutput) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::NegotiateComponentParameters() Found Output port index %d ", ii)); |
| |
| iOutputPortIndex = ii; |
| break; |
| } |
| } |
| if (ii == AudioPortParameters.nStartPortNumber + NumPorts) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::NegotiateComponentParameters() Cannot find any output port ")); |
| return false; |
| } |
| |
| |
| |
| // now get input parameters |
| iParamPort.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE); |
| |
| //Input port |
| iParamPort.nPortIndex = iInputPortIndex; |
| Err = OMX_GetParameter(iOMXAudioDecoder, OMX_IndexParamPortDefinition, &iParamPort); |
| if (Err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::NegotiateComponentParameters() Problem negotiating with input port %d ", iInputPortIndex)); |
| return false; |
| } |
| |
| // preset the number of input buffers |
| iNumInputBuffers = NUMBER_INPUT_BUFFER; |
| |
| // do we need to increase the number of buffers? |
| if (iNumInputBuffers < iParamPort.nBufferCountMin) |
| iNumInputBuffers = iParamPort.nBufferCountMin; |
| iOMXComponentInputBufferSize = iParamPort.nBufferSize; |
| |
| iParamPort.nBufferCountActual = iNumInputBuffers; |
| |
| // set the number of actual input buffers |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::NegotiateComponentParameters() Inport buffers %d,size %d", iNumInputBuffers, iOMXComponentInputBufferSize)); |
| |
| Err = OMX_SetParameter(iOMXAudioDecoder, OMX_IndexParamPortDefinition, &iParamPort); |
| if (Err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::NegotiateComponentParameters() Problem setting parameters in input port %d ", iInputPortIndex)); |
| return false; |
| } |
| |
| |
| |
| |
| // Codec specific info set/get: SamplingRate, formats etc. |
| if (!GetSetCodecSpecificInfo()) |
| return false; |
| |
| |
| //Port 1 for output port |
| iParamPort.nPortIndex = iOutputPortIndex; |
| Err = OMX_GetParameter(iOMXAudioDecoder, OMX_IndexParamPortDefinition, &iParamPort); |
| if (Err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::NegotiateComponentParameters() Problem negotiating with output port %d ", iOutputPortIndex)); |
| return false; |
| } |
| |
| // set number of output buffers and the size |
| iNumOutputBuffers = NUMBER_OUTPUT_BUFFER; |
| |
| |
| if (iNumOutputBuffers < iParamPort.nBufferCountMin) |
| iNumOutputBuffers = iParamPort.nBufferCountMin; |
| |
| iParamPort.nBufferCountActual = iNumOutputBuffers; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::NegotiateComponentParameters() Outport buffers %d,size %d", iNumOutputBuffers, iOMXComponentOutputBufferSize)); |
| |
| Err = OMX_SetParameter(iOMXAudioDecoder, OMX_IndexParamPortDefinition, &iParamPort); |
| if (Err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::NegotiateComponentParameters() Problem setting parameters in output port %d ", iOutputPortIndex)); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool PVMFOMXAudioDecNode::GetSetCodecSpecificInfo() |
| { |
| |
| // for AAC, need to let the decoder know about the type of AAC format. Need to get the frame length |
| // need to get the parameters |
| OMX_PTR CodecProfilePtr; |
| OMX_INDEXTYPE CodecProfileIndx; |
| OMX_AUDIO_PARAM_AACPROFILETYPE Audio_Aac_Param; |
| OMX_AUDIO_PARAM_AMRTYPE Audio_Amr_Param; |
| OMX_AUDIO_PARAM_MP3TYPE Audio_Mp3_Param; |
| OMX_AUDIO_PARAM_WMATYPE Audio_Wma_Param; |
| OMX_ERRORTYPE Err = OMX_ErrorNone; |
| |
| // determine the proper index and structure (based on codec type) |
| switch (((PVMFOMXAudioDecPort*)iInPort)->iFormat) |
| { |
| |
| // AAC |
| case PVMF_MPEG4_AUDIO: |
| case PVMF_LATM: |
| case PVMF_ADIF: |
| case PVMF_ASF_MPEG4_AUDIO: |
| case PVMF_AAC_SIZEHDR: // for testing |
| CodecProfilePtr = (OMX_PTR) & Audio_Aac_Param; |
| CodecProfileIndx = OMX_IndexParamAudioAac; |
| Audio_Aac_Param.nPortIndex = iInputPortIndex; |
| Audio_Aac_Param.nSize = sizeof(OMX_AUDIO_PARAM_AACPROFILETYPE); |
| Audio_Aac_Param.nVersion.s.nVersionMajor = SPECVERSIONMAJOR; |
| Audio_Aac_Param.nVersion.s.nVersionMinor = SPECVERSIONMINOR; |
| Audio_Aac_Param.nVersion.s.nRevision = SPECREVISION; |
| Audio_Aac_Param.nVersion.s.nStep = SPECSTEP; |
| break; |
| |
| // AMR |
| case PVMF_AMR_IF2: |
| case PVMF_AMR_IETF: |
| case PVMF_AMR_IETF_COMBINED: |
| case PVMF_AMRWB_IETF: |
| case PVMF_AMRWB_IETF_PAYLOAD: |
| CodecProfilePtr = (OMX_PTR) & Audio_Amr_Param; |
| CodecProfileIndx = OMX_IndexParamAudioAmr; |
| Audio_Amr_Param.nPortIndex = iInputPortIndex; |
| Audio_Amr_Param.nSize = sizeof(OMX_AUDIO_PARAM_AMRTYPE); |
| Audio_Amr_Param.nVersion.s.nVersionMajor = SPECVERSIONMAJOR; |
| Audio_Amr_Param.nVersion.s.nVersionMinor = SPECVERSIONMINOR; |
| Audio_Amr_Param.nVersion.s.nRevision = SPECREVISION; |
| Audio_Amr_Param.nVersion.s.nStep = SPECSTEP; |
| break; |
| // MP3 |
| case PVMF_MP3: |
| CodecProfilePtr = (OMX_PTR) & Audio_Mp3_Param; |
| CodecProfileIndx = OMX_IndexParamAudioMp3; |
| Audio_Mp3_Param.nPortIndex = iInputPortIndex; |
| Audio_Mp3_Param.nSize = sizeof(OMX_AUDIO_PARAM_MP3TYPE); |
| Audio_Mp3_Param.nVersion.s.nVersionMajor = SPECVERSIONMAJOR; |
| Audio_Mp3_Param.nVersion.s.nVersionMinor = SPECVERSIONMINOR; |
| Audio_Mp3_Param.nVersion.s.nRevision = SPECREVISION; |
| Audio_Mp3_Param.nVersion.s.nStep = SPECSTEP; |
| break; |
| //WMA |
| case PVMF_WMA: |
| CodecProfilePtr = (OMX_PTR) & Audio_Wma_Param; |
| CodecProfileIndx = OMX_IndexParamAudioWma; |
| Audio_Wma_Param.nPortIndex = iInputPortIndex; |
| Audio_Wma_Param.nSize = sizeof(OMX_AUDIO_PARAM_WMATYPE); |
| Audio_Wma_Param.nVersion.s.nVersionMajor = SPECVERSIONMAJOR; |
| Audio_Wma_Param.nVersion.s.nVersionMinor = SPECVERSIONMINOR; |
| Audio_Wma_Param.nVersion.s.nRevision = SPECREVISION; |
| Audio_Wma_Param.nVersion.s.nStep = SPECSTEP; |
| break; |
| |
| default: |
| break; |
| } |
| |
| // first get parameters: |
| Err = OMX_GetParameter(iOMXAudioDecoder, CodecProfileIndx, CodecProfilePtr); |
| if (Err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::NegotiateComponentParameters() Problem getting codec profile parameter on input port %d ", iInputPortIndex)); |
| return false; |
| } |
| // Set the stream format |
| switch (((PVMFOMXAudioDecPort*)iInPort)->iFormat) |
| { |
| |
| // AAC FORMATS: |
| case PVMF_MPEG4_AUDIO: |
| Audio_Aac_Param.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS; |
| break; |
| case PVMF_LATM: |
| Audio_Aac_Param.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4LATM; |
| break; |
| case PVMF_ADIF: |
| Audio_Aac_Param.eAACStreamFormat = OMX_AUDIO_AACStreamFormatADIF; |
| |
| break; |
| case PVMF_ASF_MPEG4_AUDIO: |
| Audio_Aac_Param.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS; |
| |
| break; |
| case PVMF_AAC_SIZEHDR: // for testing |
| Audio_Aac_Param.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS; |
| break; |
| |
| |
| // AMR FORMATS |
| case PVMF_AMR_IF2: |
| Audio_Amr_Param.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatIF2; |
| Audio_Amr_Param.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0; // we don't know the bitrate yet, but for init |
| // purposes, we'll set this to any NarrowBand bitrate |
| // to indicate NB vs WB |
| |
| break; |
| |
| // File format |
| // NB |
| case PVMF_AMR_IETF: |
| Audio_Amr_Param.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF; |
| Audio_Amr_Param.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0; // we don't know the bitrate yet, but for init |
| // purposes, we'll set this to any NarrowBand bitrate |
| // to indicate NB vs WB |
| break; |
| |
| // WB |
| case PVMF_AMRWB_IETF: |
| Audio_Amr_Param.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF; |
| Audio_Amr_Param.eAMRBandMode = OMX_AUDIO_AMRBandModeWB0; // we don't know the bitrate yet, but for init |
| // purposes, we'll set this to any WideBand bitrate |
| // to indicate NB vs WB |
| |
| break; |
| |
| // streaming with Table of Contents |
| |
| case PVMF_AMR_IETF_COMBINED: |
| Audio_Amr_Param.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatRTPPayload; |
| Audio_Amr_Param.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0; // we don't know the bitrate yet, but for init |
| // purposes, we'll set this to any WideBand bitrate |
| // to indicate NB vs WB |
| |
| break; |
| case PVMF_AMRWB_IETF_PAYLOAD: |
| Audio_Amr_Param.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatRTPPayload; |
| Audio_Amr_Param.eAMRBandMode = OMX_AUDIO_AMRBandModeWB0; // we don't know the bitrate yet, but for init |
| // purposes, we'll set this to any WideBand bitrate |
| // to indicate NB vs WB |
| |
| break; |
| |
| case PVMF_MP3: |
| // nothing to do here |
| break; |
| |
| case PVMF_WMA: |
| Audio_Wma_Param.eFormat = OMX_AUDIO_WMAFormatUnused; // set this initially |
| break; |
| |
| default: |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::NegotiateComponentParameters() Unknown format in input port negotiation ")); |
| return false; |
| |
| } |
| |
| |
| |
| // set parameters to inform teh component of the stream type |
| Err = OMX_SetParameter(iOMXAudioDecoder, CodecProfileIndx, CodecProfilePtr); |
| if (Err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::NegotiateComponentParameters() Problem setting codec profile parameter on input port %d ", iInputPortIndex)); |
| return false; |
| } |
| |
| |
| // read the output frame size |
| |
| switch (((PVMFOMXAudioDecPort*)iInPort)->iFormat) |
| { |
| // AAC |
| case PVMF_MPEG4_AUDIO: |
| case PVMF_LATM: |
| case PVMF_ADIF: |
| case PVMF_ASF_MPEG4_AUDIO: |
| case PVMF_AAC_SIZEHDR: // for testing |
| // AAC frame size is 1024 samples or 2048 samples for AAC-HE |
| iSamplesPerFrame = Audio_Aac_Param.nFrameLength; |
| break; |
| |
| // AMR |
| case PVMF_AMR_IF2: |
| case PVMF_AMR_IETF: |
| case PVMF_AMR_IETF_COMBINED: |
| // AMR NB has fs=8khz Mono and the frame is 20ms long, i.e. there is 160 samples per frame |
| iSamplesPerFrame = PVOMXAUDIODEC_AMRNB_SAMPLES_PER_FRAME; |
| break; |
| |
| case PVMF_AMRWB_IETF: |
| case PVMF_AMRWB_IETF_PAYLOAD: |
| // AMR WB has fs=16khz Mono and the frame is 20ms long, i.e. there is 320 samples per frame |
| iSamplesPerFrame = PVOMXAUDIODEC_AMRWB_SAMPLES_PER_FRAME; |
| break; |
| |
| case PVMF_MP3: |
| // frame size is either 576 or 1152 samples per frame. However, this information cannot be |
| // obtained through OMX MP3 Params. Assume that it's 1152 |
| iSamplesPerFrame = PVOMXAUDIODEC_MP3_DEFAULT_SAMPLES_PER_FRAME; |
| break; |
| case PVMF_WMA: |
| // output frame size is unknown in WMA. However, the PV-WMA decoder can control the number |
| // of samples it places in an output buffer, so we can create an output buffer of arbitrary size |
| // and let the decoder control how it is filled |
| iSamplesPerFrame = 0; // unknown |
| break; |
| |
| default: |
| break; |
| } |
| |
| |
| // iSamplesPerFrame depends on the codec. |
| // for AAC: iSamplesPerFrame = 1024 |
| // for AAC+: iSamplesPerFrame = 2048 |
| // for AMRNB: iSamplesPerFrame = 160 |
| // for AMRWB: iSamplesPerFrame = 320 |
| // for MP3: iSamplesPerFrame = unknown, but either 1152 or 576 (we pick 1152 as default) |
| // for WMA: unknown (iSamplesPerFrame is set to 0) |
| |
| // GET the output buffer params and sizes |
| OMX_AUDIO_PARAM_PCMMODETYPE Audio_Pcm_Param; |
| Audio_Pcm_Param.nPortIndex = iOutputPortIndex; // we're looking for output port params |
| Audio_Pcm_Param.nSize = sizeof(OMX_AUDIO_PARAM_PCMMODETYPE); |
| Audio_Pcm_Param.nVersion.s.nVersionMajor = SPECVERSIONMAJOR; |
| Audio_Pcm_Param.nVersion.s.nVersionMinor = SPECVERSIONMINOR; |
| Audio_Pcm_Param.nVersion.s.nRevision = SPECREVISION; |
| Audio_Pcm_Param.nVersion.s.nStep = SPECSTEP; |
| |
| |
| Err = OMX_GetParameter(iOMXAudioDecoder, OMX_IndexParamAudioPcm, &Audio_Pcm_Param); |
| if (Err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::NegotiateComponentParameters() Problem negotiating PCM parameters with output port %d ", iOutputPortIndex)); |
| return false; |
| } |
| |
| |
| // these are some initial default values that may change |
| iPCMSamplingRate = Audio_Pcm_Param.nSamplingRate; // can be set to 0 (if unknown) |
| |
| if (iPCMSamplingRate == 0) // use default sampling rate (i.e. 48000) |
| iPCMSamplingRate = PVOMXAUDIODEC_DEFAULT_SAMPLINGRATE; |
| |
| iNumberOfAudioChannels = Audio_Pcm_Param.nChannels; // should be 1 or 2 |
| if (iNumberOfAudioChannels != 1 && iNumberOfAudioChannels != 2) |
| return false; |
| |
| |
| if (iSamplesPerFrame != 0) // if this value is known |
| { |
| // CALCULATE NumBytes per frame, Msec per frame, etc. |
| |
| iNumBytesPerFrame = 2 * iSamplesPerFrame * iNumberOfAudioChannels; |
| iMilliSecPerFrame = (iSamplesPerFrame * 1000) / iPCMSamplingRate; |
| // Determine the size of each PCM output buffer. Size would be big enough to hold certain time amount of PCM data |
| uint32 numframes = PVOMXAUDIODEC_DEFAULT_OUTPUTPCM_TIME / iMilliSecPerFrame; |
| |
| if (PVOMXAUDIODEC_DEFAULT_OUTPUTPCM_TIME % iMilliSecPerFrame) |
| { |
| // If there is a remainder, include one more frame |
| ++numframes; |
| } |
| // set the output buffer size accordingly: |
| iOMXComponentOutputBufferSize = numframes * iNumBytesPerFrame; |
| } |
| else |
| iOMXComponentOutputBufferSize = (iPCMSamplingRate * 1000) / (PVOMXAUDIODEC_DEFAULT_OUTPUTPCM_TIME); |
| |
| return true; |
| |
| } |
| |
| bool PVMFOMXAudioDecNode::SetDefaultCapabilityFlags() |
| { |
| |
| iIsOMXComponentMultiThreaded = true; |
| |
| iOMXComponentSupportsExternalOutputBufferAlloc = true; |
| iOMXComponentSupportsExternalInputBufferAlloc = true; |
| iOMXComponentSupportsMovableInputBuffers = true; //false; |
| |
| |
| return true; |
| } |
| |
| |
| |
| bool PVMFOMXAudioDecNode::SendEOSBufferToOMXComponent() |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::SendEOSBufferToOMXComponent() In")); |
| |
| |
| // 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_Audio *input_buf = NULL; |
| int32 errcode = 0; |
| |
| // we already checked that the number of buffers is OK, so we don't expect problems |
| // try to get input buffer header |
| OSCL_TRY(errcode, input_buf = (InputBufCtrlStruct_Audio *) iInBufMemoryPool->allocate(iInputAllocSize)); |
| if (errcode != 0) |
| { |
| if (errcode == OsclErrNoResources) |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, |
| PVLOGMSG_DEBUG, (0, "PVMFOMXAudioDecNode::SendEOSBufferToOMXComponent() No more buffers in the mempool - unexpected")); |
| |
| 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, "PVMFOMXAudioDecNode::SendEOSBufferToOMXComponent() Input mempool error")); |
| |
| |
| 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; |
| input_buf->pBufHdr->nTimeStamp = iEndOfDataTimestamp; |
| |
| // 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(iOMXAudioDecoder, input_buf->pBufHdr); |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::SendEOSBufferToOMXComponent() Out")); |
| |
| return true; |
| |
| } |
| |
| |
| bool PVMFOMXAudioDecNode::SendInputBufferToOMXComponent() |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::SendInputBufferToOMXComponent() In")); |
| |
| |
| // first of all , get an input buffer. Without a buffer, no point in proceeding |
| InputBufCtrlStruct_Audio *input_buf = NULL; |
| int32 errcode = 0; |
| |
| do |
| { |
| // do loop to loop over all fragments |
| |
| // try to get input buffer header |
| OSCL_TRY(errcode, input_buf = (InputBufCtrlStruct_Audio *) iInBufMemoryPool->allocate(iInputAllocSize)); |
| if (errcode != 0) |
| { |
| if (errcode == OsclErrNoResources) |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, |
| PVLOGMSG_DEBUG, (0, "PVMFOMXAudioDecNode::SendInputBufferToOMXComponent() No more buffers in the mempool")); |
| |
| 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, "PVMFOMXAudioDecNode::SendInputBufferToOMXComponent() Input mempool error")); |
| |
| |
| 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++; |
| |
| // 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. |
| |
| // 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) |
| { |
| iCurrentMsgMarkerBit = iDataIn->getMarkerInfo() & PVMF_MEDIA_DATA_MARKER_INFO_END_OF_NAL_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 && ( |
| (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_AMR_IETF_COMBINED) || |
| (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_AMRWB_IETF_PAYLOAD) || |
| (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_MP3) |
| ) |
| ) |
| { |
| iCurrentMsgMarkerBit = PVMF_MEDIA_DATA_MARKER_INFO_M_BIT; |
| } |
| |
| // logging info: |
| if (iDataIn->getNumFragments() > 1) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::SendInputBufferToOMXComponent() - New msg has MULTI-FRAGMENTS")); |
| } |
| |
| 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, "PVMFOMXAudioDecNode::SendInputBufferToOMXComponent() - New msg has NO MARKER BIT")); |
| } |
| } |
| |
| |
| // 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, "PVMFOMXAudioDecNode::SendInputBufferToOMXComponent() - Buffer 0x%x of size %d, %d frag out of tot. %d", input_buf->pBufHdr->pBuffer, frag.getMemFragSize(), iCurrFragNum + 1, iDataIn->getNumFragments())); |
| |
| 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(); |
| |
| // 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? |
| if (iFragmentSizeRemainingToCopy <= (input_buf->pBufHdr->nAllocLen)) |
| { |
| |
| oscl_memcpy(input_buf->pBufHdr->pBuffer, |
| (void *)((uint8 *)frag.getMemFragPtr() + iCopyPosition), |
| iFragmentSizeRemainingToCopy); |
| |
| input_buf->pBufHdr->nFilledLen = iFragmentSizeRemainingToCopy; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::SendInputBufferToOMXComponent() - Copied %d bytes of fragment %d out of %d into buffer 0x%x of size %d", iFragmentSizeRemainingToCopy, iCurrFragNum + 1, iDataIn->getNumFragments(), input_buf->pBufHdr->pBuffer, input_buf->pBufHdr->nFilledLen)); |
| |
| 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 |
| oscl_memcpy(input_buf->pBufHdr->pBuffer, |
| (void *)((uint8 *)frag.getMemFragPtr() + iCopyPosition), |
| input_buf->pBufHdr->nAllocLen); |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::SendInputBufferToOMXComponent() - Copied %d bytes of fragment %d out of %d into buffer 0x%x of size %d", input_buf->pBufHdr->nAllocLen, iCurrFragNum + 1, iDataIn->getNumFragments(), input_buf->pBufHdr->pBuffer, input_buf->pBufHdr->nFilledLen)); |
| |
| input_buf->pBufHdr->nFilledLen = input_buf->pBufHdr->nAllocLen; |
| iCopyPosition += input_buf->pBufHdr->nAllocLen; // move current position within fragment forward |
| iFragmentSizeRemainingToCopy -= input_buf->pBufHdr->nAllocLen; |
| iIsNewDataFragment = false; // set the flag to indicate we're still working on the "old" fragment |
| } |
| |
| } |
| |
| |
| // set buffer fields (this is the same regardless of whether the input is movable or not |
| input_buf->pBufHdr->nOffset = 0; |
| input_buf->pBufHdr->nTimeStamp = iInTimestamp; |
| |
| // 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 |
| // 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 |
| |
| |
| 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, "PVMFOMXAudioDecNode::SendInputBufferToOMXComponent() - END OF FRAGMENT - Multifragmented msg AVC case, Buffer 0x%x MARKER bit set to 1", input_buf->pBufHdr->pBuffer)); |
| input_buf->pBufHdr->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME; |
| } |
| 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, "PVMFOMXAudioDecNode::SendInputBufferToOMXComponent() - END OF FRAGMENT - Buffer 0x%x MARKER bit set to %d", input_buf->pBufHdr->pBuffer, iCurrentMsgMarkerBit)); |
| |
| if (iCurrentMsgMarkerBit) |
| input_buf->pBufHdr->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME; |
| |
| } |
| } |
| 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, "PVMFOMXAudioDecNode::SendInputBufferToOMXComponent() - NOT END OF FRAGMENT - Buffer 0x%x MARKER bit set to 0", 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, "PVMFOMXAudioDecNode::SendInputBufferToOMXComponent() - END OF MESSAGE - Buffer 0x%x MARKER bit set to 1", input_buf->pBufHdr->pBuffer)); |
| |
| input_buf->pBufHdr->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME; |
| |
| } |
| else |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::SendInputBufferToOMXComponent() - END OF MESSAGE - Buffer 0x%x MARKER bit set to 0", input_buf->pBufHdr->pBuffer)); |
| } |
| } |
| else |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::SendInputBufferToOMXComponent() - NOT END OF MESSAGE - Buffer 0x%x MARKER bit set to 0", input_buf->pBufHdr->pBuffer)); |
| } |
| |
| |
| }// 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; |
| |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::SendInputBufferToOMXComponent() - SENDING Buffer 0x%x MARKER bit set to %d,TS=%d", input_buf->pBufHdr->pBuffer, input_buf->pBufHdr->nFlags, input_buf->pBufHdr->nTimeStamp)); |
| |
| |
| OMX_EmptyThisBuffer(iOMXAudioDecoder, input_buf->pBufHdr); |
| |
| |
| // 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, "PVMFOMXAudioDecNode::SendInputBufferToOMXComponent() Out")); |
| |
| return true; |
| |
| } |
| ///////////////////////////////////////////////////////////////////////////// |
| bool PVMFOMXAudioDecNode::InitDecoder(PVMFSharedMediaDataPtr& DataIn) |
| { |
| uint16 length = 0, size = 0; |
| |
| |
| OsclRefCounterMemFrag DataFrag; |
| OsclRefCounterMemFrag refCtrMemFragOut; |
| uint8* initbuffer = NULL; |
| uint32 initbufsize = 0; |
| |
| |
| // NOTE: the component may not start decoding without providing the Output buffer to it, |
| // here, we're sending input/config buffers. |
| // Then, we'll go to ReadyToDecode state and send output as well |
| |
| switch (((PVMFOMXAudioDecPort*)iInPort)->iFormat) |
| { |
| case PVMF_LATM: |
| { |
| |
| // must have the LATM config buffer and size already present |
| if (iLATMConfigBuffer != NULL) |
| { |
| initbuffer = iLATMConfigBuffer; |
| initbufsize = iLATMConfigBufferSize; |
| } |
| else |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::InitDecoder() Error - LATM config buffer not present")); |
| return false; |
| } |
| |
| |
| } |
| break; |
| |
| case PVMF_MPEG4_AUDIO: |
| case PVMF_ADIF: |
| case PVMF_ASF_MPEG4_AUDIO: |
| case PVMF_AAC_SIZEHDR: // for testing |
| { |
| // get format specific info and send it as config data: |
| DataIn->getFormatSpecificInfo(DataFrag); |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::InitDecoder() VOL header (Size=%d)", DataFrag.getMemFragSize())); |
| |
| //get pointer to the data fragment |
| initbuffer = (uint8 *) DataFrag.getMemFragPtr(); |
| initbufsize = (int32) DataFrag.getMemFragSize(); |
| |
| } // in some cases, initbufsize may be 0, and initbuf= NULL. Config is done after 1st frame of data |
| break; |
| |
| case PVMF_AMR_IF2: |
| case PVMF_AMR_IETF: |
| case PVMF_AMR_IETF_COMBINED: |
| case PVMF_AMRWB_IETF: |
| case PVMF_AMRWB_IETF_PAYLOAD: |
| case PVMF_MP3: |
| { |
| initbuffer = NULL; // no special config header. Need to decode 1 frame |
| initbufsize = 0; |
| } |
| break; |
| |
| case PVMF_WMA: |
| |
| // in case of WMA, get config parameters from the port |
| initbuffer = ((PVMFOMXAudioDecPort*)iInPort)->getTrackConfig(); |
| initbufsize = (int32)((PVMFOMXAudioDecPort*)iInPort)->getTrackConfigSize(); |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::InitDecoder() for WMA Decoder. Initialization data Size %d.", initbufsize)); |
| |
| |
| break; |
| |
| |
| default: |
| |
| break; |
| } |
| |
| |
| if (initbufsize > 0) |
| { |
| |
| |
| if (!SendConfigBufferToOMXComponent(initbuffer, initbufsize)) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::InitDecoder() Error in processing config buffer")); |
| return false; |
| } |
| } |
| |
| |
| //Varibles initialization |
| sendFsi = true; |
| |
| |
| return true; |
| } |
| |
| |
| |
| bool PVMFOMXAudioDecNode::SendConfigBufferToOMXComponent(uint8 *initbuffer, uint32 initbufsize) |
| |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::SendConfigBufferToOMXComponent() In")); |
| |
| |
| // first of all , get an input buffer. Without a buffer, no point in proceeding |
| InputBufCtrlStruct_Audio *input_buf = NULL; |
| int32 errcode = 0; |
| |
| // try to get input buffer header |
| OSCL_TRY(errcode, input_buf = (InputBufCtrlStruct_Audio *) iInBufMemoryPool->allocate(iInputAllocSize)); |
| if (errcode != 0) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::SendConfigBufferToOMXComponent() Input buffer mempool problem -unexpected at init")); |
| |
| 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++; |
| |
| // 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, "PVMFOMXAudioDecNode::SendConfigBufferToOMXComponent() - New msg has NO MARKER BIT")); |
| } |
| |
| |
| 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, "PVMFOMXAudioDecNode::SendConfigBufferToOMXComponent() - Config Buffer 0x%x of size %d", 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; |
| |
| |
| |
| // can the remaining fragment fit into the buffer? |
| if (iFragmentSizeRemainingToCopy <= (input_buf->pBufHdr->nAllocLen)) |
| { |
| |
| oscl_memcpy(input_buf->pBufHdr->pBuffer, |
| (void *)(initbuffer + iCopyPosition), |
| iFragmentSizeRemainingToCopy); |
| |
| input_buf->pBufHdr->nFilledLen = iFragmentSizeRemainingToCopy; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::SendConfigBufferToOMXComponent() - Copied %d bytes into buffer 0x%x of size %d", iFragmentSizeRemainingToCopy, input_buf->pBufHdr->pBuffer, input_buf->pBufHdr->nFilledLen)); |
| |
| iCopyPosition += iFragmentSizeRemainingToCopy; |
| iFragmentSizeRemainingToCopy = 0; |
| |
| |
| } |
| else |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::SendConfigBufferToOMXComponent() Config buffer too large problem -unexpected at init")); |
| |
| return false; |
| } |
| |
| } |
| |
| |
| // set buffer fields (this is the same regardless of whether the input is movable or not |
| input_buf->pBufHdr->nOffset = 0; |
| input_buf->pBufHdr->nTimeStamp = iInTimestamp; |
| |
| // 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, "PVMFOMXAudioDecNode::SendConfigBufferToOMXComponent() - END OF FRAGMENT - Buffer 0x%x MARKER bit set to 1", input_buf->pBufHdr->pBuffer)); |
| |
| input_buf->pBufHdr->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME; |
| |
| OMX_EmptyThisBuffer(iOMXAudioDecoder, input_buf->pBufHdr); |
| |
| return true; |
| |
| } |
| |
| |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| bool PVMFOMXAudioDecNode::CreateOutMemPool(uint32 num_buffers) |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::CreateOutMemPool() start")); |
| // 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, "PVMFOMXAudioDecNode::CreateOutMemPool() Allocating output buffer header pointers")); |
| |
| iOutputAllocSize = oscl_mem_aligned_size((uint32)sizeof(OutputBufCtrlStruct_Audio)); |
| |
| if (iOMXComponentSupportsExternalOutputBufferAlloc) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::CreateOutMemPool() Allocating output buffers of size %d as well", 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 = 0; |
| OSCL_TRY(leavecode, iOutBufMemoryPool = OSCL_NEW(OsclMemPoolFixedChunkAllocator, (num_buffers));); |
| if (leavecode || iOutBufMemoryPool == NULL) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, |
| PVLOGMSG_ERR, (0, "PVMFOMXAudioDecNode::CreateOutMemPool() Memory pool structure for output buffers failed to allocate")); |
| return false; |
| } |
| |
| |
| |
| // allocate a dummy buffer to actually create the mempool |
| OsclAny *dummy_alloc = NULL; // this dummy buffer will be released at end of scope |
| leavecode = 0; |
| OSCL_TRY(leavecode, dummy_alloc = iOutBufMemoryPool->allocate(iOutputAllocSize)); |
| if (leavecode || dummy_alloc == NULL) |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, |
| PVLOGMSG_ERR, (0, "PVMFOMXAudioDecNode::CreateOutMemPool() Memory pool for output buffers failed to allocate")); |
| return false; |
| } |
| iOutBufMemoryPool->deallocate(dummy_alloc); |
| // init the counter |
| iNumOutstandingOutputBuffers = 0; |
| |
| // allocate mempool for media data message wrapper |
| leavecode = 0; |
| OSCL_TRY(leavecode, iMediaDataMemPool = OSCL_NEW(OsclMemPoolFixedChunkAllocator, (num_buffers, PVOMXAUDIODEC_MEDIADATA_CHUNKSIZE))); |
| if (leavecode || iMediaDataMemPool == NULL) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXAudioDecNode::CreateOutMemPool() Media Data Buffer pool for output buffers failed to allocate")); |
| return false; |
| } |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::CreateOutMemPool() done")); |
| return true; |
| } |
| ///////////////////////////////////////////////////////////////////////////////////////////////////// |
| ///////////////////////////// Creates memory pool for input buffer management /////////////////////// |
| ///////////////////////////////////////////////////////////////////////////////////////////////////// |
| bool PVMFOMXAudioDecNode::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, "PVMFOMXAudioDecNode::CreateInputMemPool() start ")); |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::CreateInputMemPool() allocating buffer header pointers and shared media data ptrs ")); |
| |
| |
| |
| iInputAllocSize = oscl_mem_aligned_size((uint32) sizeof(InputBufCtrlStruct_Audio)); //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, "PVMFOMXAudioDecNode::CreateOutMemPool() Allocating input buffers of size %d as well", iOMXComponentInputBufferSize)); |
| |
| iInputAllocSize += iOMXComponentInputBufferSize; |
| } |
| |
| if (iInBufMemoryPool) |
| { |
| iInBufMemoryPool->removeRef(); |
| iInBufMemoryPool = NULL; |
| } |
| |
| int32 leavecode = 0; |
| OSCL_TRY(leavecode, iInBufMemoryPool = OSCL_NEW(OsclMemPoolFixedChunkAllocator, (num_buffers));); |
| if (leavecode || iInBufMemoryPool == NULL) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, |
| PVLOGMSG_ERR, (0, "PVMFOMXAudioDecNode::CreateInputMemPool() Memory pool structure for input buffers failed to allocate")); |
| return false; |
| } |
| // try to allocate a dummy buffer to actually create the mempool and allocate the needed memory |
| // allocate a dummy buffer to actually create the mempool, this dummy buffer will be released at end of scope of this method |
| OsclAny *dummy_alloc = NULL; |
| leavecode = 0; |
| OSCL_TRY(leavecode, dummy_alloc = iInBufMemoryPool->allocate(iInputAllocSize)); |
| if (leavecode || dummy_alloc == NULL) |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, |
| PVLOGMSG_ERR, (0, "PVMFOMXAudioDecNode::CreateInputMemPool() Memory pool for input buffers failed to allocate")); |
| 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, "PVMFOMXAudioDecNode::CreateInputMemPool() done")); |
| return true; |
| } |
| //////////////////////////////////////////////////////////////////////////// |
| bool PVMFOMXAudioDecNode::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, "PVMFOMXAudioDecNode::ProvideBuffersToComponent() enter")); |
| |
| 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, "PVMFOMXAudioDecNode::ProvideBuffersToComponent ctrl_struct_ptr == NULL")); |
| 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 = 0; |
| // get the address where the buf hdr ptr will be stored |
| OSCL_TRY(errcode, ctrl_struct_ptr[ii] = (OsclAny *) aMemPool->allocate(aAllocSize)); |
| if ((errcode != OsclErrNone) || (ctrl_struct_ptr[ii] == NULL)) |
| { |
| if (errcode == OsclErrNoResources) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::ProvideBuffersToComponent ->allocate() failed for no mempool chunk available")); |
| } |
| else |
| { |
| // General error |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::ProvideBuffersToComponent ->allocate() failed due to some general error")); |
| |
| 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_Audio *temp = (InputBufCtrlStruct_Audio *) 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_Audio)); |
| |
| err = OMX_UseBuffer(iOMXAudioDecoder, // 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 |
| |
| } |
| else |
| { |
| OutputBufCtrlStruct_Audio *temp = (OutputBufCtrlStruct_Audio *) ctrl_struct_ptr[ii]; |
| // advance buffer ptr to skip the structure |
| pB += oscl_mem_aligned_size(sizeof(OutputBufCtrlStruct_Audio)); |
| |
| |
| err = OMX_UseBuffer(iOMXAudioDecoder, // 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 |
| |
| |
| } |
| |
| |
| } |
| else |
| { |
| // the component must allocate its own buffers. |
| if (aIsThisInputBuffer) |
| { |
| |
| InputBufCtrlStruct_Audio *temp = (InputBufCtrlStruct_Audio *) ctrl_struct_ptr[ii]; |
| err = OMX_AllocateBuffer(iOMXAudioDecoder, |
| &(temp->pBufHdr), |
| aPortIndex, |
| ctrl_struct_ptr[ii], |
| (OMX_U32)aActualBufferSize); |
| } |
| else |
| { |
| OutputBufCtrlStruct_Audio *temp = (OutputBufCtrlStruct_Audio *) ctrl_struct_ptr[ii]; |
| err = OMX_AllocateBuffer(iOMXAudioDecoder, |
| &(temp->pBufHdr), |
| aPortIndex, |
| ctrl_struct_ptr[ii], |
| (OMX_U32)aActualBufferSize); |
| } |
| |
| } |
| |
| if (err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::ProvideBuffersToComponent() Problem using/allocating a buffer")); |
| |
| |
| 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, "PVMFOMXAudioDecNode::ProvideBuffersToComponent() done")); |
| return true; |
| } |
| /////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| /////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| bool PVMFOMXAudioDecNode::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, "PVMFOMXAudioDecNode::FreeBuffersToComponent() enter")); |
| |
| 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 = 0; |
| // get the address where the buf hdr ptr will be stored |
| |
| OSCL_TRY(errcode, ctrl_struct_ptr[ii] = (OsclAny *) aMemPool->allocate(aAllocSize)); |
| if ((errcode != OsclErrNone) || (ctrl_struct_ptr[ii] == NULL)) |
| { |
| if (errcode == OsclErrNoResources) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::FreeBuffersFromComponent ->allocate() failed for no mempool chunk available")); |
| } |
| else |
| { |
| // General error |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::FreeBuffersFromComponent ->allocate() failed due to some general error")); |
| |
| ReportErrorEvent(PVMFFailure); |
| ChangeNodeState(EPVMFNodeError); |
| } |
| |
| return false; |
| } |
| // to maintain correct count |
| aMemPool->notifyfreechunkavailable((*this), (OsclAny*) aMemPool); |
| |
| if (aIsThisInputBuffer) |
| { |
| |
| iNumOutstandingInputBuffers++; |
| // get the buf hdr pointer |
| InputBufCtrlStruct_Audio *temp = (InputBufCtrlStruct_Audio *) ctrl_struct_ptr[ii]; |
| err = OMX_FreeBuffer(iOMXAudioDecoder, |
| aPortIndex, |
| temp->pBufHdr); |
| |
| } |
| else |
| { |
| iNumOutstandingOutputBuffers++; |
| OutputBufCtrlStruct_Audio *temp = (OutputBufCtrlStruct_Audio *) ctrl_struct_ptr[ii]; |
| err = OMX_FreeBuffer(iOMXAudioDecoder, |
| aPortIndex, |
| temp->pBufHdr); |
| |
| } |
| |
| if (err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::FreeBuffersFromComponent() Problem freeing a buffer")); |
| |
| 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) |
| { |
| iInputBuffersFreed = true; |
| } |
| else |
| { |
| iOutputBuffersFreed = true; |
| } |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::FreeBuffersFromComponent() done")); |
| return true; |
| } |
| |
| |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| ////////////////////// CALLBACK PROCESSING FOR EVENT HANDLER |
| ///////////////////////////////////////////////////////////////////////////// |
| OMX_ERRORTYPE PVMFOMXAudioDecNode::EventHandlerProcessing(OMX_OUT OMX_HANDLETYPE aComponent, |
| OMX_OUT OMX_PTR aAppData, |
| OMX_OUT OMX_EVENTTYPE aEvent, |
| OMX_OUT OMX_U32 aData1, |
| OMX_OUT OMX_U32 aData2, |
| OMX_OUT OMX_PTR aEventData) |
| { |
| |
| OSCL_UNUSED_ARG(aComponent); |
| OSCL_UNUSED_ARG(aAppData); |
| OSCL_UNUSED_ARG(aEventData); |
| |
| |
| switch (aEvent) |
| { |
| case OMX_EventCmdComplete: |
| { |
| |
| switch (aData1) |
| { |
| case OMX_CommandStateSet: |
| { |
| HandleComponentStateChange(aData2); |
| break; |
| } |
| case OMX_CommandFlush: |
| { |
| // flush can be sent as part of repositioning or as part of port reconfig |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::EventHandlerProcessing: OMX_CommandFlush - completed on port %d", aData2)); |
| |
| if (iIsRepositioningRequestSentToComponent) |
| { |
| if (aData2 == iOutputPortIndex) |
| { |
| iIsOutputPortFlushed = true; |
| } |
| else if (aData2 == iInputPortIndex) |
| { |
| iIsInputPortFlushed = true; |
| } |
| |
| if (iIsOutputPortFlushed && iIsInputPortFlushed) |
| { |
| iIsRepositionDoneReceivedFromComponent = true; |
| } |
| } |
| RunIfNotReady(); |
| |
| } |
| |
| break; |
| |
| case OMX_CommandPortDisable: |
| { |
| // if port disable command is done, we can re-allocate the buffers and re-enable the port |
| |
| iProcessingState = EPVMFOMXAudioDecNodeProcessingState_PortReEnable; |
| iPortIndexForDynamicReconfig = aData2; |
| |
| RunIfNotReady(); |
| break; |
| } |
| case OMX_CommandPortEnable: |
| // port enable command is done. Check if the other port also reported change. |
| // If not, we can start data flow. Otherwise, must start dynamic reconfig procedure for |
| // the other port as well. |
| { |
| if (iSecondPortReportedChange) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::EventHandlerProcessing: OMX_CommandPortEnable - completed on port %d, dynamic reconfiguration needed on port %d", aData2, iSecondPortToReconfig)); |
| |
| iProcessingState = EPVMFOMXAudioDecNodeProcessingState_PortReconfig; |
| iPortIndexForDynamicReconfig = iSecondPortToReconfig; |
| iSecondPortReportedChange = false; |
| } |
| else |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::EventHandlerProcessing: OMX_CommandPortEnable - completed on port %d, resuming normal data flow", aData2)); |
| iProcessingState = EPVMFOMXAudioDecNodeProcessingState_ReadyToDecode; |
| iDynamicReconfigInProgress = false; |
| // in case pause or stop command was sent to component |
| // change processing state (because the node might otherwise |
| // start sending buffers to component before pause/stop is processed) |
| if (iPauseCommandWasSentToComponent) |
| { |
| iProcessingState = EPVMFOMXAudioDecNodeProcessingState_Pausing; |
| } |
| if (iStopCommandWasSentToComponent) |
| { |
| iProcessingState = EPVMFOMXAudioDecNodeProcessingState_Stopping; |
| } |
| |
| } |
| RunIfNotReady(); |
| break; |
| } |
| |
| case OMX_CommandMarkBuffer: |
| // nothing to do here yet; |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::EventHandlerProcessing: OMX_CommandMarkBuffer - completed - no action taken")); |
| |
| break; |
| |
| default: |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::EventHandlerProcessing: Unsupported event")); |
| break; |
| } |
| }//end of switch (aData1) |
| |
| break; |
| }//end of case OMX_EventCmdComplete |
| |
| case OMX_EventError: |
| { |
| |
| if (aData1 == OMX_ErrorStreamCorrupt) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::EventHandlerProcessing: OMX_EventError - Bitstream corrupt error")); |
| // Errors from corrupt bitstream are reported as info events |
| ReportInfoEvent(PVMFInfoProcessingFailure, NULL); |
| |
| } |
| else |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::EventHandlerProcessing: OMX_EventError")); |
| // for now, any error from the component will be reported as error |
| ReportErrorEvent(PVMFErrorEvent, NULL, NULL); |
| SetState(EPVMFNodeError); |
| } |
| break; |
| |
| |
| |
| } |
| |
| case OMX_EventBufferFlag: |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::EventHandlerProcessing: OMX_EventBufferFlag (EOS) flag returned from OMX component")); |
| |
| RunIfNotReady(); |
| break; |
| }//end of case OMX_EventBufferFlag |
| |
| case OMX_EventMark: |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::EventHandlerProcessing: OMX_EventMark returned from OMX component - no action taken")); |
| |
| RunIfNotReady(); |
| break; |
| }//end of case OMX_EventMark |
| |
| case OMX_EventPortSettingsChanged: |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::EventHandlerProcessing: OMX_EventPortSettingsChanged returned from OMX component")); |
| |
| // first check if dynamic reconfiguration is already in progress, |
| // if so, wait until this is completed, and then initiate the 2nd reconfiguration |
| if (iDynamicReconfigInProgress) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::EventHandlerProcessing: OMX_EventPortSettingsChanged returned for port %d, dynamic reconfig already in progress", aData1)); |
| |
| iSecondPortToReconfig = aData1; |
| iSecondPortReportedChange = true; |
| |
| // check the audio sampling rate and fs right away in case of output port |
| // is this output port? |
| if (iSecondPortToReconfig == iOutputPortIndex) |
| { |
| |
| OMX_ERRORTYPE Err; |
| // GET the output buffer params and sizes |
| OMX_AUDIO_PARAM_PCMMODETYPE Audio_Pcm_Param; |
| Audio_Pcm_Param.nPortIndex = iOutputPortIndex; // we're looking for output port params |
| Audio_Pcm_Param.nSize = sizeof(OMX_AUDIO_PARAM_PCMMODETYPE); |
| Audio_Pcm_Param.nVersion.s.nVersionMajor = SPECVERSIONMAJOR; |
| Audio_Pcm_Param.nVersion.s.nVersionMinor = SPECVERSIONMINOR; |
| Audio_Pcm_Param.nVersion.s.nRevision = SPECREVISION; |
| Audio_Pcm_Param.nVersion.s.nStep = SPECSTEP; |
| |
| |
| Err = OMX_GetParameter(iOMXAudioDecoder, OMX_IndexParamAudioPcm, &Audio_Pcm_Param); |
| if (Err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::EventHandlerProcessing() PortSettingsChanged -> Cannot get component output parameters")); |
| |
| SetState(EPVMFNodeError); |
| ReportErrorEvent(PVMFErrResource); |
| } |
| |
| iPCMSamplingRate = Audio_Pcm_Param.nSamplingRate; // can be set to 0 (if unknown) |
| |
| if (iPCMSamplingRate == 0) // use default sampling rate (i.e. 48000) |
| iPCMSamplingRate = PVOMXAUDIODEC_DEFAULT_SAMPLINGRATE; |
| |
| iNumberOfAudioChannels = Audio_Pcm_Param.nChannels; // should be 1 or 2 |
| if (iNumberOfAudioChannels != 1 && iNumberOfAudioChannels != 2) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::EventHandlerProcessing() PortSettingsChanged -> Output parameters num channels = %d", iNumberOfAudioChannels)); |
| |
| SetState(EPVMFNodeError); |
| ReportErrorEvent(PVMFErrResource); |
| } |
| } |
| } |
| else |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::EventHandlerProcessing: OMX_EventPortSettingsChanged returned for port %d", aData1)); |
| |
| iProcessingState = EPVMFOMXAudioDecNodeProcessingState_PortReconfig; |
| iPortIndexForDynamicReconfig = aData1; |
| // start "discarding" data right away, don't wait |
| // check the audio sampling rate and fs right away in case of output port |
| // is this output port? |
| if (iPortIndexForDynamicReconfig == iOutputPortIndex) |
| { |
| |
| OMX_ERRORTYPE Err; |
| // GET the output buffer params and sizes |
| OMX_AUDIO_PARAM_PCMMODETYPE Audio_Pcm_Param; |
| Audio_Pcm_Param.nPortIndex = iOutputPortIndex; // we're looking for output port params |
| Audio_Pcm_Param.nSize = sizeof(OMX_AUDIO_PARAM_PCMMODETYPE); |
| Audio_Pcm_Param.nVersion.s.nVersionMajor = SPECVERSIONMAJOR; |
| Audio_Pcm_Param.nVersion.s.nVersionMinor = SPECVERSIONMINOR; |
| Audio_Pcm_Param.nVersion.s.nRevision = SPECREVISION; |
| Audio_Pcm_Param.nVersion.s.nStep = SPECSTEP; |
| |
| |
| Err = OMX_GetParameter(iOMXAudioDecoder, OMX_IndexParamAudioPcm, &Audio_Pcm_Param); |
| if (Err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::EventHandlerProcessing() PortSettingsChanged -> Cannot get component output parameters")); |
| |
| SetState(EPVMFNodeError); |
| ReportErrorEvent(PVMFErrResource); |
| |
| } |
| |
| iPCMSamplingRate = Audio_Pcm_Param.nSamplingRate; // can be set to 0 (if unknown) |
| |
| if (iPCMSamplingRate == 0) // use default sampling rate (i.e. 48000) |
| iPCMSamplingRate = PVOMXAUDIODEC_DEFAULT_SAMPLINGRATE; |
| |
| iNumberOfAudioChannels = Audio_Pcm_Param.nChannels; // should be 1 or 2 |
| if (iNumberOfAudioChannels != 1 && iNumberOfAudioChannels != 2) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::EventHandlerProcessing() PortSettingsChanged -> Output parameters num channels = %d", iNumberOfAudioChannels)); |
| |
| SetState(EPVMFNodeError); |
| ReportErrorEvent(PVMFErrResource); |
| |
| } |
| |
| } |
| iDynamicReconfigInProgress = true; |
| } |
| |
| RunIfNotReady(); |
| break; |
| }//end of case OMX_PortSettingsChanged |
| |
| case OMX_EventResourcesAcquired: //not supported |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::EventHandlerProcessing: OMX_EventResourcesAcquired returned from OMX component - no action taken")); |
| |
| RunIfNotReady(); |
| |
| break; |
| } |
| |
| default: |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::EventHandlerProcessing: Unknown Event returned from OMX component - no action taken")); |
| |
| break; |
| } |
| |
| }//end of switch (eEvent) |
| |
| |
| |
| return OMX_ErrorNone; |
| } |
| |
| |
| |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // This function handles the event of OMX component state change |
| ///////////////////////////////////////////////////////////////////////////// |
| void PVMFOMXAudioDecNode::HandleComponentStateChange(OMX_U32 decoder_state) |
| { |
| switch (decoder_state) |
| { |
| case OMX_StateIdle: |
| { |
| iCurrentDecoderState = OMX_StateIdle; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleComponentStateChange: OMX_StateIdle reached")); |
| |
| // this state can be reached either going from OMX_Loaded->OMX_Idle (preparing) |
| // or going from OMX_Executing->OMX_Idle (stopping) |
| |
| // Also, in case of Audio, repositioning is done by performing Executing->Idle ->Executing |
| if (iIsRepositionIdleRequestSentToComponent) |
| { |
| iIsRepositionIdleDoneReceivedFromComponent = true; |
| RunIfNotReady(); |
| } |
| else if ((iCurrentCommand.size() > 0) && |
| (iCurrentCommand.front().iCmd == PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_PREPARE)) |
| { |
| iProcessingState = EPVMFOMXAudioDecNodeProcessingState_InitDecoder; |
| SetState(EPVMFNodePrepared); |
| CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess); |
| RunIfNotReady(); |
| } |
| else if ((iCurrentCommand.size() > 0) && |
| (iCurrentCommand.front().iCmd == PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_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 == EPVMFOMXAudioDecNodeProcessingState_Stopping) |
| iProcessingState = EPVMFOMXAudioDecNodeProcessingState_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 == PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_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 |
| RunIfNotReady(); |
| } |
| break; |
| }//end of case OMX_StateIdle |
| |
| case OMX_StateExecuting: |
| { |
| iCurrentDecoderState = OMX_StateExecuting; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleComponentStateChange: OMX_StateExecuting reached")); |
| |
| // this state can be reached going from OMX_Idle -> OMX_Executing (preparing) |
| // or going from OMX_Pause -> OMX_Executing (coming from pause) |
| // This is a response to "DoStart" command |
| |
| // Also, during repositioning, idle->executing transition can be requested |
| if (iIsRepositionExecRequestSentToComponent) |
| { |
| iIsRepositionExecDoneReceivedFromComponent = true; |
| RunIfNotReady(); |
| } |
| else if ((iCurrentCommand.size() > 0) && |
| (iCurrentCommand.front().iCmd == PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_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, "PVMFOMXAudioDecNode::HandleComponentStateChange: OMX_StatePause reached")); |
| |
| |
| // This state can be reached going from OMX_Executing-> OMX_Pause |
| if ((iCurrentCommand.size() > 0) && |
| (iCurrentCommand.front().iCmd == PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_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 == EPVMFOMXAudioDecNodeProcessingState_Pausing) |
| iProcessingState = EPVMFOMXAudioDecNodeProcessingState_ReadyToDecode; |
| |
| |
| |
| 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, "PVMFOMXAudioDecNode::HandleComponentStateChange: OMX_StateLoaded reached")); |
| //Check if command's responce is pending |
| if ((iCurrentCommand.size() > 0) && |
| (iCurrentCommand.front().iCmd == PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_RESET)) |
| { |
| |
| // move this here |
| if (iInPort) |
| { |
| OSCL_DELETE(((PVMFOMXAudioDecPort*)iInPort)); |
| iInPort = NULL; |
| } |
| |
| if (iOutPort) |
| { |
| OSCL_DELETE(((PVMFOMXAudioDecPort*)iOutPort)); |
| iOutPort = NULL; |
| } |
| |
| iDataIn.Unbind(); |
| |
| // Reset the metadata key list |
| iAvailableMetadataKeys.clear(); |
| |
| |
| iProcessingState = EPVMFOMXAudioDecNodeProcessingState_Idle; |
| //logoff & go back to Created state. |
| SetState(EPVMFNodeIdle); |
| PVMFStatus status = ThreadLogoff(); |
| CommandComplete(iCurrentCommand, iCurrentCommand.front(), status); |
| iResetInProgress = false; |
| iResetMsgSent = false; |
| //DeleteOMXAudioDecoder(); |
| } |
| |
| break; |
| }//end of case OMX_StateLoaded |
| |
| case OMX_StateInvalid: |
| default: |
| { |
| iCurrentDecoderState = OMX_StateInvalid; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::HandleComponentStateChange: OMX_StateInvalid reached")); |
| |
| break; |
| }//end of case OMX_StateInvalid |
| |
| }//end of switch(decoder_state) |
| |
| } |
| |
| |
| |
| |
| |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| ////////////////////// CALLBACK PROCESSING FOR EMPTY BUFFER DONE - input buffer was consumed |
| ///////////////////////////////////////////////////////////////////////////// |
| OMX_ERRORTYPE PVMFOMXAudioDecNode::EmptyBufferDoneProcessing(OMX_OUT OMX_HANDLETYPE aComponent, |
| OMX_OUT OMX_PTR aAppData, |
| OMX_OUT OMX_BUFFERHEADERTYPE* aBuffer) |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::EmptyBufferDoneProcessing: In")); |
| |
| OSCL_ASSERT((void*) aComponent == (void*) iOMXAudioDecoder); // 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_Audio *pContext = (InputBufCtrlStruct_Audio *)(aBuffer->pAppPrivate); |
| |
| |
| |
| // if a buffer is not empty, we should send the same buffer back to the component |
| // do not release it in this case |
| 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, "PVMFOMXAudioDecNode::EmptyBufferDoneProcessing: Input buffer returned with %d bytes still in it, TS=%d", aBuffer->nFilledLen, aBuffer->nTimeStamp)); |
| |
| iInputBufferToResendToComponent = NULL; |
| |
| } |
| |
| { |
| |
| 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, "PVMFOMXAudioDecNode::EmptyBufferDoneProcessing: Release input buffer with TS=%d (with %d refcount remaining of input message)", aBuffer->nTimeStamp, (pContext->pMediaData).get_count() - 1)); |
| |
| |
| (pContext->pMediaData).Unbind(); |
| |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::EmptyBufferDoneProcessing: Release input buffer %x back to mempool", pContext)); |
| |
| iInBufMemoryPool->deallocate((OsclAny *) pContext); |
| } |
| |
| // the OMX spec says that no error is to be returned |
| return OMX_ErrorNone; |
| |
| } |
| |
| |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| ////////////////////// CALLBACK PROCESSING FOR FILL BUFFER DONE - output buffer is ready |
| ///////////////////////////////////////////////////////////////////////////// |
| OMX_ERRORTYPE PVMFOMXAudioDecNode::FillBufferDoneProcessing(OMX_OUT OMX_HANDLETYPE aComponent, |
| OMX_OUT OMX_PTR aAppData, |
| OMX_OUT OMX_BUFFERHEADERTYPE* aBuffer) |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::FillBufferDoneProcessing: In")); |
| |
| OSCL_ASSERT((void*) aComponent == (void*) iOMXAudioDecoder); // 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 |
| iIsEOSReceivedFromComponent = true; |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::FillBufferDoneProcessing: Output buffer has EOS set")); |
| |
| } |
| |
| // 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, "PVMFOMXAudioDecNode::FillBufferDoneProcessing: Release output buffer %x back to mempool - buffer empty or not to be sent downstream", pContext)); |
| |
| iOutBufMemoryPool->deallocate(pContext); |
| |
| } |
| else |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "Output frame %d received", iFrameCounter++)); |
| |
| // get pointer to actual buffer data |
| uint8 *pBufdata = ((uint8*) aBuffer->pBuffer); |
| // move the data pointer based on offset info |
| pBufdata += aBuffer->nOffset; |
| |
| iOutTimeStamp = aBuffer->nTimeStamp; |
| //iOutTimeStamp = iInTimestamp; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::FillBufferDoneProcessing: Wrapping buffer %x of size %d", 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, "PVMFOMXAudioDecNode::FillBufferDoneProcessing: Problem wrapping buffer %x of size %d - releasing the buffer", 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, "PVMFOMXAudioDecNode::FillBufferDoneProcessing: Buffer %x of size %d queued - reschedule the node to send out", 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, "PVMFOMXAudioDecNode::FillBufferDoneProcessing: Problem queing buffer %x of size %d - releasing the buffer", pBufdata, aBuffer->nFilledLen)); |
| } |
| |
| |
| } |
| |
| } |
| // the OMX spec says that no error is to be returned |
| return OMX_ErrorNone; |
| |
| } |
| //////////////////////////////////////////////////////////////////////////////////////////////// |
| ///////////////////////////// Put output buffer in outgoing queue ////////////////////////////// |
| //////////////////////////////////////////////////////////////////////////////////////////////// |
| bool PVMFOMXAudioDecNode::QueueOutputBuffer(OsclSharedPtr<PVMFMediaDataImpl> &mediadataimplout, uint32 aDataLen) |
| { |
| |
| bool status = true; |
| PVMFSharedMediaDataPtr mediaDataOut; |
| int32 leavecode = 0; |
| |
| // NOTE: ASSUMPTION IS THAT OUTGOING QUEUE IS BIG ENOUGH TO QUEUE ALL THE OUTPUT BUFFERS |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::QueueOutputFrame: In")); |
| |
| // First check if we can put outgoing msg. into the queue |
| if (iOutPort->IsOutgoingQueueBusy()) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, |
| (0, "PVMFOMXAudioDecNode::QueueOutputFrame() OutgoingQueue is busy")); |
| return false; |
| } |
| |
| OSCL_TRY(leavecode, |
| mediaDataOut = PVMFMediaData::createMediaData(mediadataimplout, iMediaDataMemPool);); |
| if (leavecode == 0) |
| { |
| |
| // Update the filled length of the fragment |
| mediaDataOut->setMediaFragFilledLen(0, aDataLen); |
| |
| // Set timestamp |
| mediaDataOut->setTimestamp(iOutTimeStamp); |
| |
| // Set sequence number |
| mediaDataOut->setSeqNum(iSeqNum++); |
| // set stream id |
| mediaDataOut->setStreamID(iStreamID); |
| |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iDataPathLogger, PVLOGMSG_INFO, (0, ":PVMFOMXAudioDecNode::QueueOutputFrame(): - SeqNum=%d, TS=%d", iSeqNum, iOutTimeStamp)); |
| int fsiErrorCode = 0; |
| |
| // Check if Fsi configuration need to be sent |
| if (sendFsi) |
| { |
| |
| OsclRefCounterMemFrag FsiMemfrag; |
| |
| OSCL_TRY(fsiErrorCode, FsiMemfrag = iFsiFragmentAlloc.get();); |
| |
| OSCL_FIRST_CATCH_ANY(fsiErrorCode, PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::RemoveOutputFrame() Failed to allocate memory for FSI"))); |
| |
| if (fsiErrorCode == 0) |
| { |
| |
| channelSampleInfo* pcminfo = (channelSampleInfo*) FsiMemfrag.getMemFragPtr(); |
| OSCL_ASSERT(pcminfo != NULL); |
| |
| pcminfo->samplingRate = iPCMSamplingRate; |
| pcminfo->desiredChannels = iNumberOfAudioChannels; |
| |
| mediaDataOut->setFormatSpecificInfo(FsiMemfrag); |
| ((PVMFOMXAudioDecPort*)iOutPort)->pvmiSetPortFormatSpecificInfoSync(FsiMemfrag); |
| } |
| else |
| |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, |
| (0, "PVMFOMXAudioDecNode::QueueOutputFrame - Problem allocating Output FSI")); |
| return false; // this is going to make everything go out of scope |
| } |
| |
| // Reset the flag |
| sendFsi = false; |
| } |
| |
| if (fsiErrorCode == 0) |
| { |
| // Send frame to downstream node |
| PVMFSharedMediaMsgPtr mediaMsgOut; |
| convertToPVMFMediaMsg(mediaMsgOut, mediaDataOut); |
| |
| if (iOutPort && (iOutPort->QueueOutgoingMsg(mediaMsgOut) == PVMFSuccess)) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::QueueOutputFrame(): Queued frame OK ")); |
| |
| } |
| else |
| { |
| // we should not get here because we always check for whether queue is busy or not MC |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::QueueOutputFrame(): Send frame failed")); |
| return false; |
| } |
| |
| } |
| |
| |
| }//end of if (leavecode==0) |
| else |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::QueueOutputFrame() call PVMFMediaData::createMediaData is failed")); |
| return false; |
| } |
| |
| return status; |
| |
| } |
| |
| ////////////////////////////////////////////////////////////////////////////////////////////// |
| ///////////////////////////// Attach a MediaDataImpl wrapper (refcount, deallocator etc.) |
| /////////////////////////////// to the output buffer ///////////////////////////////////////// |
| OsclSharedPtr<PVMFMediaDataImpl> PVMFOMXAudioDecNode::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(PVOMXBufferSharedPtrWrapperCombinedCleanupDA)); |
| 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 |
| PVOMXBufferSharedPtrWrapperCombinedCleanupDA *cleanup_ptr = |
| OSCL_PLACEMENT_NEW(my_ptr + aligned_refcnt_size, PVOMXBufferSharedPtrWrapperCombinedCleanupDA(iOutBufMemoryPool, pContext)); |
| |
| // 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 PVMFOMXAudioDecNode::SendBeginOfMediaStreamCommand() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::SendBeginOfMediaStreamCommand() In")); |
| |
| 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 |
| sharedMediaCmdPtr->setSeqNum(iSeqNum); |
| sharedMediaCmdPtr->setStreamID(iStreamID); |
| |
| PVMFSharedMediaMsgPtr mediaMsgOut; |
| convertToPVMFMediaCmdMsg(mediaMsgOut, sharedMediaCmdPtr); |
| if (iOutPort->QueueOutgoingMsg(mediaMsgOut) != PVMFSuccess) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::SendBeginOfMediaStreamCommand() Outgoing queue busy")); |
| return false; |
| } |
| |
| iSendBOS = false; |
| |
| // reset repositioning related flags |
| iIsRepositionIdleDoneReceivedFromComponent = false; |
| iIsRepositionIdleRequestSentToComponent = false; |
| iIsRepositionExecRequestSentToComponent = false; |
| iIsRepositionExecDoneReceivedFromComponent = false; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::SendBeginOfMediaStreamCommand() BOS Sent StreamID %d", iStreamID)); |
| return true; |
| } |
| //////////////////////////////////// |
| bool PVMFOMXAudioDecNode::SendEndOfTrackCommand(void) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::SendEndOfTrackCommand() In")); |
| |
| PVMFSharedMediaCmdPtr sharedMediaCmdPtr = PVMFMediaCmd::createMediaCmd(); |
| |
| sharedMediaCmdPtr->setFormatID(PVMF_MEDIA_CMD_EOS_FORMAT_ID); |
| |
| // Set the timestamp |
| sharedMediaCmdPtr->setTimestamp(iEndOfDataTimestamp); |
| |
| // Set the sequence number |
| sharedMediaCmdPtr->setSeqNum(iSeqNum++); |
| // set stream ID |
| sharedMediaCmdPtr->setStreamID(iStreamID); |
| |
| 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, "PVMFOMXAudioDecNode::SendEndOfTrackCommand() Out")); |
| return true; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| //The various command handlers call this routine when a command is complete. |
| ///////////////////////////////////////////////////////////////////////////// |
| void PVMFOMXAudioDecNode::CommandComplete(PVMFOMXAudioDecNodeCmdQ& aCmdQ, PVMFOMXAudioDecNodeCommand& aCmd, PVMFStatus aStatus, OsclAny* aEventData) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode:CommandComplete Id %d Cmd %d Status %d Context %d Data %d" |
| , 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 PVMFOMXAudioDecNode::DoInit(PVMFOMXAudioDecNodeCommand& aCmd) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::DoInit() In")); |
| switch (iInterfaceState) |
| { |
| case EPVMFNodeIdle: |
| { |
| SetState(EPVMFNodeInitialized); |
| CommandComplete(iInputCommands, aCmd, PVMFSuccess); |
| break; |
| } |
| |
| default: |
| CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState); |
| break; |
| } |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| void PVMFOMXAudioDecNode::DoPrepare(PVMFOMXAudioDecNodeCommand& aCmd) |
| { |
| OMX_ERRORTYPE err = OMX_ErrorNone; |
| OMX_STRING Role = NULL; |
| |
| switch (iInterfaceState) |
| { |
| case EPVMFNodeInitialized: |
| { |
| if (NULL == iInPort) |
| { |
| CommandComplete(iInputCommands, aCmd, PVMFFailure); |
| } |
| |
| // Check format of input data |
| |
| uint32 Format = ((PVMFOMXAudioDecPort*)iInPort)->iFormat; |
| switch (Format) |
| { |
| // AAC |
| case PVMF_MPEG4_AUDIO: |
| case PVMF_LATM: |
| case PVMF_ADIF: |
| case PVMF_ASF_MPEG4_AUDIO: |
| case PVMF_AAC_SIZEHDR: |
| Role = "audio_decoder.aac"; |
| break; |
| |
| // AMR |
| case PVMF_AMR_IF2: |
| case PVMF_AMR_IETF: |
| case PVMF_AMR_IETF_COMBINED: |
| case PVMF_AMRWB_IETF: |
| case PVMF_AMRWB_IETF_PAYLOAD: |
| |
| Role = "audio_decoder.amr"; |
| break; |
| |
| case PVMF_MP3: |
| |
| Role = "audio_decoder.mp3"; |
| break; |
| |
| case PVMF_WMA: |
| Role = "audio_decoder.wma"; |
| break; |
| |
| default: |
| // Illegal codec specified. |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFAVCNode::DoPrepare() Input port format other then codec type")); |
| CommandComplete(iInputCommands, aCmd, PVMFErrArgument); |
| return; |
| } |
| |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_DEBUG, |
| (0, "PVMFOMXAudioDecNode::Initializing OMX component and decoder for role %s", Role)); |
| |
| /* Set callback structure */ |
| iCallbacks.EventHandler = CallbackEventHandler_Audio; //event_handler; |
| iCallbacks.EmptyBufferDone = CallbackEmptyBufferDone_Audio; //empty_buffer_done; |
| iCallbacks.FillBufferDone = CallbackFillBufferDone_Audio; //fill_buffer_done; |
| |
| |
| // determine components which can fit the role |
| // then, create the component. If multiple components fit the role, |
| // the first one registered will be selected. If that one fails to |
| // be created, the second one in the list is selected etc. |
| OMX_U32 num_comps = 0; |
| OMX_STRING *CompOfRole; |
| // call once to find out the number of components that can fit the role |
| PV_MasterOMX_GetComponentsOfRole(Role, &num_comps, NULL); |
| uint32 ii; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, |
| (0, "PVMFOMXAudioDecNode::DoPrepare(): There are %d components of role %s ", num_comps, Role)); |
| |
| if (num_comps > 0) |
| { |
| CompOfRole = (OMX_STRING *)oscl_malloc(num_comps * sizeof(OMX_STRING)); |
| |
| for (ii = 0; ii < num_comps; ii++) |
| CompOfRole[ii] = (OMX_STRING) oscl_malloc(PV_OMX_MAX_COMPONENT_NAME_LENGTH * sizeof(OMX_U8)); |
| |
| // call 2nd time to get the component names |
| PV_MasterOMX_GetComponentsOfRole(Role, &num_comps, (OMX_U8 **)CompOfRole); |
| |
| for (ii = 0; ii < num_comps; ii++) |
| { |
| // try to create component |
| err = PV_MasterOMX_GetHandle(&iOMXAudioDecoder, (OMX_STRING) CompOfRole[ii], (OMX_PTR) this, (OMX_CALLBACKTYPE *) & iCallbacks); |
| // if successful, no need to continue |
| if ((err == OMX_ErrorNone) && (iOMXAudioDecoder != NULL)) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, |
| (0, "PVMFOMXAudioDecNode::DoPrepare(): Got Component %s handle ", CompOfRole[ii])); |
| |
| break; |
| } |
| else |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, |
| (0, "PVMFOMXAudioDecNode::DoPrepare(): Cannot get component %s handle, try another component if available", CompOfRole[ii])); |
| } |
| |
| } |
| // 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) || (iOMXAudioDecoder == NULL)) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::Can't get handle for decoder!")); |
| iOMXAudioDecoder = NULL; |
| CommandComplete(iInputCommands, aCmd, PVMFErrResource); |
| return; |
| } |
| } |
| else |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::No component can handle role %s !", Role)); |
| iOMXAudioDecoder = NULL; |
| CommandComplete(iInputCommands, aCmd, PVMFErrResource); |
| return; |
| } |
| |
| |
| |
| if (!iOMXAudioDecoder) |
| { |
| CommandComplete(iInputCommands, aCmd, PVMFErrNoResources); |
| return; |
| } |
| |
| // GET CAPABILITY FLAGS FROM PV COMPONENT, IF this fails, use defaults |
| PV_OMXComponentCapabilityFlagsType Cap_flags; |
| err = OMX_GetParameter(iOMXAudioDecoder, (OMX_INDEXTYPE) PV_OMX_COMPONENT_CAPABILITY_TYPE_INDEX, &Cap_flags); |
| if (err != OMX_ErrorNone) |
| { |
| SetDefaultCapabilityFlags(); |
| } |
| else |
| { |
| iIsOMXComponentMultiThreaded = Cap_flags.iIsOMXComponentMultiThreaded; |
| iOMXComponentSupportsExternalInputBufferAlloc = Cap_flags.iOMXComponentSupportsExternalInputBufferAlloc; |
| iOMXComponentSupportsExternalOutputBufferAlloc = Cap_flags.iOMXComponentSupportsExternalOutputBufferAlloc; |
| iOMXComponentSupportsMovableInputBuffers = Cap_flags.iOMXComponentSupportsMovableInputBuffers; |
| } |
| |
| |
| // find out about parameters |
| |
| if (!NegotiateComponentParameters()) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::DoPrepare() Cannot get component parameters")); |
| |
| CommandComplete(iInputCommands, aCmd, PVMFErrNoResources); |
| return; |
| } |
| |
| // create active objects to handle callbacks in case of multithreaded implementation |
| |
| // NOTE: CREATE THE THREADSAFE CALLBACK AOs REGARDLESS OF WHETHER MULTITHREADED COMPONENT OR NOT |
| // If it is not multithreaded, we won't use them |
| // The Flag iIsComponentMultiThreaded decides which mechanism is used for callbacks. |
| // This flag is set by looking at component capabilities (or to true by default) |
| |
| if (iThreadSafeHandlerEventHandler) |
| { |
| OSCL_DELETE(iThreadSafeHandlerEventHandler); |
| iThreadSafeHandlerEventHandler = NULL; |
| } |
| // substitute default parameters: observer(this node),queuedepth(3),nameAO for logging |
| // Get the priority of video dec node, and set the threadsafe callback AO priority to 1 higher |
| iThreadSafeHandlerEventHandler = OSCL_NEW(EventHandlerThreadSafeCallbackAO_Audio, (this, 10, "EventHandlerAO_Audio", Priority() + 2)); |
| |
| if (iThreadSafeHandlerEmptyBufferDone) |
| { |
| OSCL_DELETE(iThreadSafeHandlerEmptyBufferDone); |
| iThreadSafeHandlerEmptyBufferDone = NULL; |
| } |
| // use queue depth of iNumInputBuffers to prevent deadlock |
| iThreadSafeHandlerEmptyBufferDone = OSCL_NEW(EmptyBufferDoneThreadSafeCallbackAO_Audio, (this, iNumInputBuffers, "EmptyBufferDoneAO_Audio", Priority() + 1)); |
| |
| if (iThreadSafeHandlerFillBufferDone) |
| { |
| OSCL_DELETE(iThreadSafeHandlerFillBufferDone); |
| iThreadSafeHandlerFillBufferDone = NULL; |
| } |
| // use queue depth of iNumOutputBuffers to prevent deadlock |
| iThreadSafeHandlerFillBufferDone = OSCL_NEW(FillBufferDoneThreadSafeCallbackAO_Audio, (this, iNumOutputBuffers, "FillBufferDoneAO_Audio", Priority() + 1)); |
| |
| if ((iThreadSafeHandlerEventHandler == NULL) || |
| (iThreadSafeHandlerEmptyBufferDone == NULL) || |
| (iThreadSafeHandlerFillBufferDone == NULL) |
| ) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::Can't get threadsafe callbacks for decoder!")); |
| iOMXAudioDecoder = NULL; |
| } |
| |
| |
| iSetMarkerBitForEveryFrag = false; |
| |
| |
| // Init Decoder |
| iCurrentDecoderState = OMX_StateLoaded; |
| |
| /* Change state to OMX_StateIdle from OMX_StateLoaded. */ |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, |
| (0, "PVMFOMXAudioDecNode::DoPrepare(): Changing Component state Loaded -> Idle ")); |
| |
| err = OMX_SendCommand(iOMXAudioDecoder, OMX_CommandStateSet, OMX_StateIdle, NULL); |
| if (err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::DoPrepare() Can't send StateSet command!")); |
| |
| CommandComplete(iInputCommands, aCmd, PVMFErrNoResources); |
| return; |
| } |
| |
| |
| /* Allocate input buffers */ |
| if (!CreateInputMemPool(iNumInputBuffers)) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::DoPrepare() Can't allocate mempool for input buffers!")); |
| |
| 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, "PVMFOMXAudioDecNode::DoPrepare() Component can't use input buffers!")); |
| |
| CommandComplete(iInputCommands, aCmd, PVMFErrNoResources); |
| return; |
| } |
| |
| |
| /* Allocate output buffers */ |
| if (!CreateOutMemPool(iNumOutputBuffers)) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::DoPrepare() Can't allocate mempool for output buffers!")); |
| |
| 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, "PVMFOMXAudioDecNode::DoPrepare() Component can't use output buffers!")); |
| |
| 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 PVMFOMXAudioDecNode::DoStart(PVMFOMXAudioDecNodeCommand& aCmd) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::DoStart() In")); |
| |
| 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(iOMXAudioDecoder, &sState); |
| if (err != OMX_ErrorNone) |
| { |
| //Error condition report |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| |
| (0, "PVMFOMXAudioDecNode::DoStart(): Can't get State of decoder!")); |
| |
| 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-enable sending output |
| iDoNotSaveInputBuffersFlag = false; |
| } |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::DoStart() Changing Component state Idle->Executing")); |
| |
| err = OMX_SendCommand(iOMXAudioDecoder, OMX_CommandStateSet, OMX_StateExecuting, NULL); |
| if (err != OMX_ErrorNone) |
| { |
| //Error condition report |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::DoStart(): Can't send StateSet command to decoder!")); |
| |
| status = PVMFErrInvalidState; |
| } |
| |
| } |
| else |
| { |
| //Error condition report |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::DoStart(): Decoder is not in the Idle or Pause state!")); |
| |
| 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 PVMFOMXAudioDecNode::DoStop(PVMFOMXAudioDecNodeCommand& aCmd) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::DoStop() In")); |
| |
| 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; |
| |
| //Get state of OpenMAX decoder |
| err = OMX_GetState(iOMXAudioDecoder, &sState); |
| if (err != OMX_ErrorNone) |
| { |
| //Error condition report |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::DoStop(): Can't get State of decoder!")); |
| |
| 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, "PVMFOMXAudioDecNode::DoStop() Changing Component State Executing->Idle or Pause->Idle")); |
| |
| err = OMX_SendCommand(iOMXAudioDecoder, OMX_CommandStateSet, OMX_StateIdle, NULL); |
| if (err != OMX_ErrorNone) |
| { |
| //Error condition report |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::DoStop(): Can't send StateSet command to decoder!")); |
| |
| 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 == EPVMFOMXAudioDecNodeProcessingState_ReadyToDecode) |
| iProcessingState = EPVMFOMXAudioDecNodeProcessingState_Stopping; |
| |
| // indicate that stop cmd was sent |
| if (iDynamicReconfigInProgress) |
| { |
| iStopCommandWasSentToComponent = true; |
| } |
| |
| |
| |
| } |
| else |
| { |
| //Error condition report |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::DoStop(): Decoder is not in the Executing or Pause state!")); |
| |
| 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 PVMFOMXAudioDecNode::DoFlush(PVMFOMXAudioDecNodeCommand& 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(); |
| } |
| break; |
| |
| default: |
| CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState); |
| break; |
| } |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| void PVMFOMXAudioDecNode::DoPause(PVMFOMXAudioDecNodeCommand& aCmd) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::DoPause() In")); |
| |
| OMX_ERRORTYPE err; |
| OMX_STATETYPE sState; |
| |
| switch (iInterfaceState) |
| { |
| case EPVMFNodeStarted: |
| |
| |
| //Get state of OpenMAX decoder |
| err = OMX_GetState(iOMXAudioDecoder, &sState); |
| if (err != OMX_ErrorNone) |
| { |
| //Error condition report |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::DoPause(): Can't get State of decoder!")); |
| |
| 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, "PVMFOMXAudioDecNode::DoPause() Changing Component State Executing->Pause")); |
| |
| err = OMX_SendCommand(iOMXAudioDecoder, OMX_CommandStateSet, OMX_StatePause, NULL); |
| if (err != OMX_ErrorNone) |
| { |
| //Error condition report |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::DoPause(): Can't send StateSet command to decoder!")); |
| |
| 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 == EPVMFOMXAudioDecNodeProcessingState_ReadyToDecode) |
| iProcessingState = EPVMFOMXAudioDecNodeProcessingState_Pausing; |
| |
| // indicate that pause cmd was sent |
| if (iDynamicReconfigInProgress) |
| { |
| iPauseCommandWasSentToComponent = true; |
| } |
| |
| |
| } |
| else |
| { |
| //Error condition report |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::DoPause(): Decoder is not in the Executing state!")); |
| 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 PVMFOMXAudioDecNode::DoReset(PVMFOMXAudioDecNodeCommand& aCmd) |
| { |
| |
| OMX_ERRORTYPE err; |
| OMX_STATETYPE sState; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::DoReset() In")); |
| |
| LogDiagnostics(); |
| |
| switch (iInterfaceState) |
| { |
| |
| case EPVMFNodeIdle: |
| case EPVMFNodeInitialized: |
| case EPVMFNodePrepared: |
| case EPVMFNodeStarted: |
| case EPVMFNodePaused: |
| case EPVMFNodeError: |
| |
| { |
| //Check if decoder is initilized |
| if (iOMXAudioDecoder != NULL) |
| { |
| //Get state of OpenMAX decoder |
| err = OMX_GetState(iOMXAudioDecoder, &sState); |
| if (err != OMX_ErrorNone) |
| { |
| //Error condition report |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::DoReset(): Can't get State of decoder!")); |
| if (iResetInProgress) |
| { |
| // cmd is in current q |
| iResetInProgress = false; |
| if ((iCurrentCommand.size() > 0) && |
| (iCurrentCommand.front().iCmd == PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_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, "PVMFOMXAudioDecNode::DoReset() OMX comp is in loaded state. Wait for official callback to change variables etc.")); |
| return; |
| } |
| else |
| { |
| CommandComplete(iInputCommands, aCmd, PVMFErrResource); |
| 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, "PVMFOMXAudioDecNode::DoReset() Waiting for %d input and-or %d output buffers", 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, "PVMFOMXAudioDecNode::DoReset() Changing Component State Idle->Loaded")); |
| |
| err = OMX_SendCommand(iOMXAudioDecoder, OMX_CommandStateSet, OMX_StateLoaded, NULL); |
| if (err != OMX_ErrorNone) |
| { |
| //Error condition report |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::DoReset(): Can't send StateSet command to decoder!")); |
| } |
| |
| iResetMsgSent = true; |
| |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::DoReset() freeing output buffers")); |
| |
| 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, "PVMFOMXAudioDecNode::DoReset() Cannot free output buffers ")); |
| |
| if (iResetInProgress) |
| { |
| iResetInProgress = false; |
| if ((iCurrentCommand.size() > 0) && |
| (iCurrentCommand.front().iCmd == PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_RESET) |
| ) |
| { |
| CommandComplete(iCurrentCommand, iCurrentCommand.front() , PVMFErrResource); |
| } |
| } |
| |
| } |
| |
| } |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::DoReset() freeing input buffers ")); |
| 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, "PVMFOMXAudioDecNode::DoReset() Cannot free input buffers ")); |
| |
| if (iResetInProgress) |
| { |
| iResetInProgress = false; |
| if ((iCurrentCommand.size() > 0) && |
| (iCurrentCommand.front().iCmd == PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_RESET) |
| ) |
| { |
| CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFErrResource); |
| } |
| } |
| |
| |
| } |
| } |
| |
| |
| |
| iEndOfDataReached = false; |
| iIsEOSSentToComponent = false; |
| iIsEOSReceivedFromComponent = false; |
| |
| |
| |
| // also, perform Port deletion when the component replies with the command |
| // complete, not right here |
| } // end of if(iResetMsgSent) |
| |
| |
| return; |
| |
| } |
| else |
| { |
| //Error condition report |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::DoReset(): Decoder is not in the Idle state!")); |
| if (iResetInProgress) |
| { |
| iResetInProgress = false; |
| if ((iCurrentCommand.size() > 0) && |
| (iCurrentCommand.front().iCmd == PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_RESET) |
| ) |
| { |
| CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFErrInvalidState); |
| } |
| } |
| else |
| { |
| CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState); |
| } |
| break; |
| }//end of if (sState == OMX_StateIdle) |
| }//end of if (iOMXAudioDecoder != NULL) |
| |
| //delete all ports and notify observer. |
| if (iInPort) |
| { |
| OSCL_DELETE(((PVMFOMXAudioDecPort*)iInPort)); |
| iInPort = NULL; |
| } |
| |
| if (iOutPort) |
| { |
| OSCL_DELETE(((PVMFOMXAudioDecPort*)iOutPort)); |
| iOutPort = NULL; |
| } |
| |
| iDataIn.Unbind(); |
| |
| |
| // Reset the metadata key list |
| iAvailableMetadataKeys.clear(); |
| |
| iEndOfDataReached = false; |
| iIsEOSSentToComponent = false; |
| iIsEOSReceivedFromComponent = false; |
| |
| |
| iProcessingState = EPVMFOMXAudioDecNodeProcessingState_Idle; |
| //logoff & go back to Created state. |
| SetState(EPVMFNodeIdle); |
| |
| |
| if (iResetInProgress) |
| { |
| iResetInProgress = false; |
| if ((iCurrentCommand.size() > 0) && |
| (iCurrentCommand.front().iCmd == PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_RESET) |
| ) |
| { |
| CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess); |
| } |
| } |
| else |
| { |
| CommandComplete(iInputCommands, aCmd, PVMFSuccess); |
| } |
| |
| } |
| break; |
| |
| default: |
| CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState); |
| break; |
| } |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| void PVMFOMXAudioDecNode::DoRequestPort(PVMFOMXAudioDecNodeCommand& aCmd) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::DoRequestPort() In")); |
| //This node supports port request from any state |
| |
| //retrieve port tag. |
| int32 tag; |
| OSCL_String* portconfig; |
| |
| aCmd.PVMFOMXAudioDecNodeCommandBase::Parse(tag, portconfig); |
| |
| PVMFPortInterface* port = NULL; |
| int32 leavecode = 0; |
| //validate the tag... |
| switch (tag) |
| { |
| case PVMF_OMX_AUDIO_DEC_NODE_PORT_TYPE_SOURCE: |
| if (iInPort) |
| { |
| CommandComplete(iInputCommands, aCmd, PVMFFailure); |
| break; |
| } |
| OSCL_TRY(leavecode, iInPort = OSCL_NEW(PVMFOMXAudioDecPort, ((int32)tag, this, "OMXAudioDecIn(Video)"));); |
| if (leavecode || iInPort == NULL) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::DoRequestPort: Error - Input port instantiation failed")); |
| CommandComplete(iInputCommands, aCmd, PVMFErrArgument); |
| return; |
| } |
| port = iInPort; |
| break; |
| |
| case PVMF_OMX_AUDIO_DEC_NODE_PORT_TYPE_SINK: |
| if (iOutPort) |
| { |
| CommandComplete(iInputCommands, aCmd, PVMFFailure); |
| break; |
| } |
| OSCL_TRY(leavecode, iOutPort = OSCL_NEW(PVMFOMXAudioDecPort, ((int32)tag, this, "OMXAudioDecOut(Video)"))); |
| if (leavecode || iOutPort == NULL) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::DoRequestPort: Error - Output port instantiation failed")); |
| CommandComplete(iInputCommands, aCmd, PVMFErrArgument); |
| return; |
| } |
| port = iOutPort; |
| break; |
| |
| default: |
| //bad port tag |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::DoRequestPort: Error - Invalid port tag")); |
| CommandComplete(iInputCommands, aCmd, PVMFErrArgument); |
| return; |
| } |
| |
| //Return the port pointer to the caller. |
| CommandComplete(iInputCommands, aCmd, PVMFSuccess, (OsclAny*)port); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| void PVMFOMXAudioDecNode::DoReleasePort(PVMFOMXAudioDecNodeCommand& aCmd) |
| { |
| PVMFOMXAudioDecPort* port; |
| aCmd.PVMFOMXAudioDecNodeCommandBase::Parse((PVMFPortInterface*&)port); |
| |
| if (port != NULL && (port == iInPort || port == iOutPort)) |
| { |
| if (port == iInPort) |
| { |
| OSCL_DELETE(((PVMFOMXAudioDecPort*)iInPort)); |
| iInPort = NULL; |
| } |
| else |
| { |
| OSCL_DELETE(((PVMFOMXAudioDecPort*)iOutPort)); |
| iOutPort = NULL; |
| } |
| //delete the port. |
| CommandComplete(iInputCommands, aCmd, PVMFSuccess); |
| } |
| else |
| { |
| //port not found. |
| CommandComplete(iInputCommands, aCmd, PVMFFailure); |
| } |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PVMFOMXAudioDecNode::DoGetNodeMetadataKey(PVMFOMXAudioDecNodeCommand& aCmd) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::DoGetNodeMetadataKey() In")); |
| |
| PVMFMetadataList* keylistptr = NULL; |
| uint32 starting_index; |
| int32 max_entries; |
| char* query_key; |
| |
| aCmd.PVMFOMXAudioDecNodeCommand::Parse(keylistptr, starting_index, max_entries, query_key); |
| |
| // Check parameters |
| if (keylistptr == NULL) |
| { |
| // The list pointer is invalid |
| return PVMFErrArgument; |
| } |
| |
| if ((starting_index > (iAvailableMetadataKeys.size() - 1)) || max_entries == 0) |
| { |
| // Invalid starting index and/or max entries |
| return PVMFErrArgument; |
| } |
| |
| // Copy the requested keys |
| uint32 num_entries = 0; |
| int32 num_added = 0; |
| int32 leavecode = 0; |
| for (uint32 lcv = 0; lcv < iAvailableMetadataKeys.size(); lcv++) |
| { |
| if (query_key == NULL) |
| { |
| // No query key so this key is counted |
| ++num_entries; |
| if (num_entries > starting_index) |
| { |
| // Past the starting index so copy the key |
| leavecode = 0; |
| OSCL_TRY(leavecode, keylistptr->push_back(iAvailableMetadataKeys[lcv])); |
| OSCL_FIRST_CATCH_ANY(leavecode, |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXAudioDecNode::DoGetNodeMetadataKey() Memory allocation failure when copying metadata key")); |
| return PVMFErrNoMemory); |
| num_added++; |
| } |
| } |
| else |
| { |
| // Check if the key matche the query key |
| if (pv_mime_strcmp(iAvailableMetadataKeys[lcv].get_cstr(), query_key) >= 0) |
| { |
| // This key is counted |
| ++num_entries; |
| if (num_entries > starting_index) |
| { |
| // Past the starting index so copy the key |
| leavecode = 0; |
| OSCL_TRY(leavecode, keylistptr->push_back(iAvailableMetadataKeys[lcv])); |
| OSCL_FIRST_CATCH_ANY(leavecode, |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXAudioDecNode::DoGetNodeMetadataKey() Memory allocation failure when copying metadata key")); |
| return PVMFErrNoMemory); |
| num_added++; |
| } |
| } |
| } |
| |
| // Check if max number of entries have been copied |
| if (max_entries > 0 && num_added >= max_entries) |
| { |
| break; |
| } |
| } |
| |
| return PVMFSuccess; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PVMFOMXAudioDecNode::DoGetNodeMetadataValue(PVMFOMXAudioDecNodeCommand& aCmd) |
| { |
| PVMFMetadataList* keylistptr = NULL; |
| Oscl_Vector<PvmiKvp, OsclMemAllocator>* valuelistptr = NULL; |
| uint32 starting_index; |
| int32 max_entries; |
| |
| aCmd.PVMFOMXAudioDecNodeCommand::Parse(keylistptr, valuelistptr, starting_index, max_entries); |
| |
| // Check the parameters |
| if (keylistptr == NULL || valuelistptr == NULL) |
| { |
| return PVMFErrArgument; |
| } |
| |
| uint32 numkeys = keylistptr->size(); |
| |
| if (starting_index > (numkeys - 1) || numkeys <= 0 || max_entries == 0) |
| { |
| // Don't do anything |
| return PVMFErrArgument; |
| } |
| |
| uint32 numvalentries = 0; |
| int32 numentriesadded = 0; |
| for (uint32 lcv = 0; lcv < numkeys; lcv++) |
| { |
| int32 leavecode = 0; |
| PvmiKvp KeyVal; |
| KeyVal.key = NULL; |
| uint32 KeyLen = 0; |
| if ((oscl_strcmp((*keylistptr)[lcv].get_cstr(), PVOMXAUDIODECMETADATA_CODECINFO_AUDIO_CHANNELS_KEY) == 0)) |
| { |
| // PCM output channels |
| if (iNumberOfAudioChannels > 0) |
| { |
| // Increment the counter for the number of values found so far |
| ++numvalentries; |
| |
| // Create a value entry if past the starting index |
| if (numvalentries > starting_index) |
| { |
| KeyLen = oscl_strlen(PVOMXAUDIODECMETADATA_CODECINFO_AUDIO_CHANNELS_KEY) + 1; // for "codec-info/audio/channels;" |
| KeyLen += oscl_strlen(PVMI_KVPVALTYPE_STRING_CONSTCHAR); // for "valtype=" |
| KeyLen += oscl_strlen(PVMI_KVPVALTYPE_UINT32_STRING_CONSTCHAR) + 1; // for "uint32" and NULL terminator |
| |
| // Allocate memory for the string |
| leavecode = 0; |
| OSCL_TRY(leavecode, |
| KeyVal.key = OSCL_ARRAY_NEW(char, KeyLen); |
| ); |
| |
| if (leavecode == 0) |
| { |
| // Copy the key string |
| oscl_strncpy(KeyVal.key, PVOMXAUDIODECMETADATA_CODECINFO_AUDIO_CHANNELS_KEY, oscl_strlen(PVOMXAUDIODECMETADATA_CODECINFO_AUDIO_CHANNELS_KEY) + 1); |
| oscl_strncat(KeyVal.key, PVOMXAUDIODECMETADATA_SEMICOLON, oscl_strlen(PVOMXAUDIODECMETADATA_SEMICOLON)); |
| oscl_strncat(KeyVal.key, PVMI_KVPVALTYPE_STRING_CONSTCHAR, oscl_strlen(PVMI_KVPVALTYPE_STRING_CONSTCHAR)); |
| oscl_strncat(KeyVal.key, PVMI_KVPVALTYPE_UINT32_STRING_CONSTCHAR, oscl_strlen(PVMI_KVPVALTYPE_UINT32_STRING_CONSTCHAR)); |
| KeyVal.key[KeyLen-1] = NULL_TERM_CHAR; |
| // Copy the value |
| KeyVal.value.uint32_value = iNumberOfAudioChannels; |
| // Set the length and capacity |
| KeyVal.length = 1; |
| KeyVal.capacity = 1; |
| } |
| else |
| { |
| // Memory allocation failed |
| KeyVal.key = NULL; |
| break; |
| } |
| } |
| } |
| } |
| else if ((oscl_strcmp((*keylistptr)[lcv].get_cstr(), PVOMXAUDIODECMETADATA_CODECINFO_AUDIO_SAMPLERATE_KEY) == 0) && |
| (iPCMSamplingRate > 0)) |
| { |
| // PCM output sampling rate |
| // Increment the counter for the number of values found so far |
| ++numvalentries; |
| |
| // Create a value entry if past the starting index |
| if (numvalentries > starting_index) |
| { |
| KeyLen = oscl_strlen(PVOMXAUDIODECMETADATA_CODECINFO_AUDIO_SAMPLERATE_KEY) + 1; // for "codec-info/audio/sample-rate;" |
| KeyLen += oscl_strlen(PVMI_KVPVALTYPE_STRING_CONSTCHAR); // for "valtype=" |
| KeyLen += oscl_strlen(PVMI_KVPVALTYPE_UINT32_STRING_CONSTCHAR) + 1; // for "uint32" and NULL terminator |
| |
| // Allocate memory for the string |
| leavecode = 0; |
| OSCL_TRY(leavecode, |
| KeyVal.key = OSCL_ARRAY_NEW(char, KeyLen); |
| ); |
| |
| if (leavecode == 0) |
| { |
| // Copy the key string |
| oscl_strncpy(KeyVal.key, PVOMXAUDIODECMETADATA_CODECINFO_AUDIO_SAMPLERATE_KEY, oscl_strlen(PVOMXAUDIODECMETADATA_CODECINFO_AUDIO_SAMPLERATE_KEY) + 1); |
| oscl_strncat(KeyVal.key, PVOMXAUDIODECMETADATA_SEMICOLON, oscl_strlen(PVOMXAUDIODECMETADATA_SEMICOLON)); |
| oscl_strncat(KeyVal.key, PVMI_KVPVALTYPE_STRING_CONSTCHAR, oscl_strlen(PVMI_KVPVALTYPE_STRING_CONSTCHAR)); |
| oscl_strncat(KeyVal.key, PVMI_KVPVALTYPE_UINT32_STRING_CONSTCHAR, oscl_strlen(PVMI_KVPVALTYPE_UINT32_STRING_CONSTCHAR)); |
| KeyVal.key[KeyLen-1] = NULL_TERM_CHAR; |
| // Copy the value |
| KeyVal.value.uint32_value = iPCMSamplingRate; |
| // Set the length and capacity |
| KeyVal.length = 1; |
| KeyVal.capacity = 1; |
| } |
| else |
| { |
| // Memory allocation failed |
| KeyVal.key = NULL; |
| break; |
| } |
| } |
| } |
| else if ((oscl_strcmp((*keylistptr)[lcv].get_cstr(), PVOMXAUDIODECMETADATA_CODECINFO_AUDIO_FORMAT_KEY) == 0) && |
| iInPort != NULL) |
| { |
| // Format |
| if ((((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_LATM) || |
| (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_MPEG4_AUDIO) || |
| (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_ADIF) || |
| (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_AAC_SIZEHDR) || |
| (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_AMR_IF2) || |
| (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_AMR_IETF) || |
| (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_AMR_IETF_COMBINED) || |
| (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_AMRWB_IETF) || |
| (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_AMRWB_IETF_PAYLOAD) || |
| (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_MP3) || |
| (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_WMA) |
| |
| ) |
| { |
| // Increment the counter for the number of values found so far |
| ++numvalentries; |
| |
| // Create a value entry if past the starting index |
| if (numvalentries > starting_index) |
| { |
| KeyLen = oscl_strlen(PVOMXAUDIODECMETADATA_CODECINFO_AUDIO_FORMAT_KEY) + 1; // for "codec-info/audio/format;" |
| KeyLen += oscl_strlen(PVMI_KVPVALTYPE_STRING_CONSTCHAR); // for "valtype=" |
| KeyLen += oscl_strlen(PVMI_KVPVALTYPE_CHARPTR_STRING_CONSTCHAR) + 1; // for "char*" and NULL terminator |
| |
| uint32 valuelen = 0; |
| switch (((PVMFOMXAudioDecPort*)iInPort)->iFormat) |
| { |
| case PVMF_LATM: |
| valuelen = oscl_strlen(_STRLIT_CHAR(PVMF_MIME_LATM)) + 1; // Value string plus one for NULL terminator |
| break; |
| |
| case PVMF_MPEG4_AUDIO: |
| valuelen = oscl_strlen(_STRLIT_CHAR(PVMF_MIME_MPEG4_AUDIO)) + 1; // Value string plus one for NULL terminator |
| break; |
| case PVMF_ADIF: |
| valuelen = oscl_strlen(_STRLIT_CHAR(PVMF_MIME_ADIF)) + 1; |
| break; |
| |
| case PVMF_AMR_IF2: |
| valuelen = oscl_strlen(_STRLIT_CHAR(PVMF_MIME_AMR_IF2)) + 1; |
| break; |
| |
| case PVMF_AMR_IETF: |
| valuelen = oscl_strlen(_STRLIT_CHAR(PVMF_MIME_AMR_IETF)) + 1; |
| break; |
| |
| case PVMF_AMR_IETF_COMBINED: |
| valuelen = oscl_strlen(_STRLIT_CHAR(PVMF_MIME_AMR)) + 1; |
| break; |
| |
| case PVMF_AMRWB_IETF: |
| valuelen = oscl_strlen(_STRLIT_CHAR(PVMF_MIME_AMRWB_IETF)) + 1; |
| break; |
| |
| case PVMF_AMRWB_IETF_PAYLOAD: |
| valuelen = oscl_strlen(_STRLIT_CHAR(PVMF_MIME_AMRWB)) + 1; |
| break; |
| |
| case PVMF_MP3: |
| valuelen = oscl_strlen(_STRLIT_CHAR(PVMF_MIME_MP3)) + 1; |
| break; |
| |
| case PVMF_WMA: |
| valuelen = oscl_strlen(_STRLIT_CHAR(PVMF_MIME_WMA)) + 1; |
| break; |
| |
| default: |
| // Should not enter here |
| OSCL_ASSERT(false); |
| valuelen = 1; |
| break; |
| } |
| |
| // Allocate memory for the strings |
| leavecode = 0; |
| OSCL_TRY(leavecode, |
| KeyVal.key = OSCL_ARRAY_NEW(char, KeyLen); |
| KeyVal.value.pChar_value = OSCL_ARRAY_NEW(char, valuelen); |
| ); |
| |
| if (leavecode == 0) |
| { |
| // Copy the key string |
| oscl_strncpy(KeyVal.key, PVOMXAUDIODECMETADATA_CODECINFO_AUDIO_FORMAT_KEY, oscl_strlen(PVOMXAUDIODECMETADATA_CODECINFO_AUDIO_FORMAT_KEY) + 1); |
| oscl_strncat(KeyVal.key, PVOMXAUDIODECMETADATA_SEMICOLON, oscl_strlen(PVOMXAUDIODECMETADATA_SEMICOLON)); |
| oscl_strncat(KeyVal.key, PVMI_KVPVALTYPE_STRING_CONSTCHAR, oscl_strlen(PVMI_KVPVALTYPE_STRING_CONSTCHAR)); |
| oscl_strncat(KeyVal.key, PVMI_KVPVALTYPE_CHARPTR_STRING_CONSTCHAR, oscl_strlen(PVMI_KVPVALTYPE_CHARPTR_STRING_CONSTCHAR)); |
| KeyVal.key[KeyLen-1] = NULL_TERM_CHAR; |
| // Copy the value |
| switch (((PVMFOMXAudioDecPort*)iInPort)->iFormat) |
| { |
| case PVMF_LATM: |
| oscl_strncpy(KeyVal.value.pChar_value, _STRLIT_CHAR(PVMF_MIME_LATM), valuelen); |
| break; |
| |
| case PVMF_MPEG4_AUDIO: |
| oscl_strncpy(KeyVal.value.pChar_value, _STRLIT_CHAR(PVMF_MIME_MPEG4_AUDIO), valuelen); |
| break; |
| |
| case PVMF_ADIF: |
| oscl_strncpy(KeyVal.value.pChar_value, _STRLIT_CHAR(PVMF_MIME_ADIF), valuelen); |
| break; |
| |
| case PVMF_AMR_IF2: |
| oscl_strncpy(KeyVal.value.pChar_value, _STRLIT_CHAR(PVMF_MIME_AMR_IF2), valuelen); |
| break; |
| |
| case PVMF_AMR_IETF: |
| oscl_strncpy(KeyVal.value.pChar_value, _STRLIT_CHAR(PVMF_MIME_AMR_IETF), valuelen); |
| break; |
| |
| case PVMF_AMR_IETF_COMBINED: |
| oscl_strncpy(KeyVal.value.pChar_value, _STRLIT_CHAR(PVMF_MIME_AMR), valuelen); |
| break; |
| |
| case PVMF_AMRWB_IETF: |
| oscl_strncpy(KeyVal.value.pChar_value, _STRLIT_CHAR(PVMF_MIME_AMRWB_IETF), valuelen); |
| break; |
| |
| case PVMF_AMRWB_IETF_PAYLOAD: |
| oscl_strncpy(KeyVal.value.pChar_value, _STRLIT_CHAR(PVMF_MIME_AMRWB), valuelen); |
| break; |
| |
| case PVMF_MP3: |
| oscl_strncpy(KeyVal.value.pChar_value, _STRLIT_CHAR(PVMF_MIME_MP3), valuelen); |
| break; |
| |
| case PVMF_WMA: |
| oscl_strncpy(KeyVal.value.pChar_value, _STRLIT_CHAR(PVMF_MIME_WMA), valuelen); |
| break; |
| |
| default: |
| // Should not enter here |
| OSCL_ASSERT(false); |
| break; |
| } |
| KeyVal.value.pChar_value[valuelen-1] = NULL_TERM_CHAR; |
| // Set the length and capacity |
| KeyVal.length = valuelen; |
| KeyVal.capacity = valuelen; |
| } |
| else |
| { |
| // Memory allocation failed so clean up |
| if (KeyVal.key) |
| { |
| OSCL_ARRAY_DELETE(KeyVal.key); |
| KeyVal.key = NULL; |
| } |
| if (KeyVal.value.pChar_value) |
| { |
| OSCL_ARRAY_DELETE(KeyVal.value.pChar_value); |
| } |
| break; |
| } |
| } |
| } |
| } |
| |
| if (KeyVal.key != NULL) |
| { |
| leavecode = 0; |
| OSCL_TRY(leavecode, (*valuelistptr).push_back(KeyVal)); |
| if (leavecode != 0) |
| { |
| switch (GetValTypeFromKeyString(KeyVal.key)) |
| { |
| case PVMI_KVPVALTYPE_CHARPTR: |
| if (KeyVal.value.pChar_value != NULL) |
| { |
| OSCL_ARRAY_DELETE(KeyVal.value.pChar_value); |
| KeyVal.value.pChar_value = NULL; |
| } |
| break; |
| |
| default: |
| // Add more case statements if other value types are returned |
| break; |
| } |
| |
| OSCL_ARRAY_DELETE(KeyVal.key); |
| KeyVal.key = NULL; |
| } |
| else |
| { |
| // Increment the counter for number of value entries added to the list |
| ++numentriesadded; |
| } |
| |
| // Check if the max number of value entries were added |
| if (max_entries > 0 && numentriesadded >= max_entries) |
| { |
| break; |
| } |
| |
| } |
| |
| } |
| |
| return PVMFSuccess; |
| |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| bool PVMFOMXAudioDecNode::ReleaseAllPorts() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::ReleaseAllPorts() In")); |
| |
| if (iInPort) |
| { |
| iInPort->ClearMsgQueues(); |
| iInPort->Disconnect(); |
| OSCL_DELETE(((PVMFOMXAudioDecPort*)iInPort)); |
| iInPort = NULL; |
| } |
| |
| if (iOutPort) |
| { |
| iOutPort->ClearMsgQueues(); |
| iOutPort->Disconnect(); |
| OSCL_DELETE(((PVMFOMXAudioDecPort*)iOutPort)); |
| iOutPort = NULL; |
| } |
| |
| return true; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // Clean Up Decoder |
| ///////////////////////////////////////////////////////////////////////////// |
| bool PVMFOMXAudioDecNode::DeleteOMXAudioDecoder() |
| { |
| OMX_ERRORTYPE err; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::DeleteOMXAudioDecoder() In")); |
| |
| if (iOMXAudioDecoder != NULL) |
| { |
| /* Free Component handle. */ |
| err = PV_MasterOMX_FreeHandle(iOMXAudioDecoder); |
| if (err != OMX_ErrorNone) |
| { |
| //Error condition report |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::DeleteOMXAudioDecoder(): Can't free decoder's handle!")); |
| } |
| iOMXAudioDecoder = NULL; |
| |
| }//end of if (iOMXAudioDecoder != NULL) |
| |
| |
| return true; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| void PVMFOMXAudioDecNode::ChangeNodeState(TPVMFNodeInterfaceState aNewState) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::ChangeNodeState() Changing state from %d to %d", iInterfaceState, aNewState)); |
| iInterfaceState = aNewState; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| void PVMFOMXAudioDecNode::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, "PVMFOMXAudioDecNode::freechunkavailable() Memory chunk in INPUT mempool was deallocated, %d out of %d now available", 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, "PVMFOMXAudioDecNode::freechunkavailable() Memory chunk in OUTPUT mempool was deallocated, %d out of %d now available", 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, "PVMFOMXAudioDecNode::freechunkavailable() UNKNOWN mempool ")); |
| |
| } |
| |
| // reschedule |
| if (IsAdded()) |
| RunIfNotReady(); |
| |
| |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| void PVMFOMXAudioDecNode::HandlePortActivity(const PVMFPortActivity &aActivity) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "0x%x PVMFOMXAudioDecNode::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, "PVMFOMXAudioDecNode::PortActivity: IncomingMsgQueueSize=%d", 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 == EPVMFOMXAudioDecNodeProcessingState_WaitForOutgoingQueue) |
| { |
| iProcessingState = EPVMFOMXAudioDecNodeProcessingState_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 PVMFOMXAudioDecNode::PortActivity: Connected port is now ready", this)); |
| RunIfNotReady(); |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| void PVMFOMXAudioDecNode::DoCancelAllCommands(PVMFOMXAudioDecNodeCommand& aCmd) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::DoCancelAllCommands")); |
| |
| //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 PVMFOMXAudioDecNode::DoCancelCommand(PVMFOMXAudioDecNodeCommand& aCmd) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::DoCancelCommand")); |
| |
| //extract the command ID from the parameters. |
| PVMFCommandId id; |
| aCmd.PVMFOMXAudioDecNodeCommandBase::Parse(id); |
| |
| //first check "current" command if any |
| { |
| PVMFOMXAudioDecNodeCommand* cmd = iCurrentCommand.FindById(id); |
| if (cmd) |
| { |
| |
| // if reset is being canceled: |
| if (cmd->iCmd == PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_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. |
| PVMFOMXAudioDecNodeCommand* 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 PVMFOMXAudioDecNode::DoQueryUuid(PVMFOMXAudioDecNodeCommand& aCmd) |
| { |
| //This node supports Query UUID from any state |
| |
| OSCL_String* mimetype; |
| Oscl_Vector<PVUuid, OsclMemAllocator> *uuidvec; |
| bool exactmatch; |
| aCmd.PVMFOMXAudioDecNodeCommandBase::Parse(mimetype, uuidvec, exactmatch); |
| |
| //Try to match the input mimetype against any of |
| //the custom interfaces for this node |
| |
| //Match against custom interface1... |
| if (*mimetype == PVMF_OMX_AUDIO_DEC_NODE_CUSTOM1_MIMETYPE |
| //also match against base mimetypes for custom interface1, |
| //unless exactmatch is set. |
| || (!exactmatch && *mimetype == PVMF_OMX_AUDIO_DEC_NODE_MIMETYPE) |
| || (!exactmatch && *mimetype == PVMF_BASEMIMETYPE)) |
| { |
| |
| PVUuid uuid(PVMF_OMX_AUDIO_DEC_NODE_CUSTOM1_UUID); |
| uuidvec->push_back(uuid); |
| } |
| CommandComplete(iInputCommands, aCmd, PVMFSuccess); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| void PVMFOMXAudioDecNode::DoQueryInterface(PVMFOMXAudioDecNodeCommand& aCmd) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::DoQueryInterface")); |
| PVUuid* uuid; |
| PVInterface** ptr; |
| aCmd.PVMFOMXAudioDecNodeCommandBase::Parse(uuid, ptr); |
| |
| if (*uuid == PVUuid(PVMF_OMX_AUDIO_DEC_NODE_CUSTOM1_UUID)) |
| { |
| addRef(); |
| *ptr = (PVMFOMXAudioDecNodeExtensionInterface*)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); |
| } |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| void PVMFOMXAudioDecNode::addRef() |
| { |
| ++iExtensionRefCount; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| void PVMFOMXAudioDecNode::removeRef() |
| { |
| --iExtensionRefCount; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| bool PVMFOMXAudioDecNode::queryInterface(const PVUuid& uuid, PVInterface*& iface) |
| { |
| PVUuid my_uuid(PVMF_OMX_AUDIO_DEC_NODE_CUSTOM1_UUID); |
| if (uuid == my_uuid) |
| { |
| PVMFOMXAudioDecNodeExtensionInterface* myInterface = OSCL_STATIC_CAST(PVMFOMXAudioDecNodeExtensionInterface*, 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 PVMFOMXAudioDecNode::HandleRepositioning() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleRepositioning() IN")); |
| |
| |
| // 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(iOMXAudioDecoder, &sState); |
| if (err != OMX_ErrorNone) |
| { |
| //Error condition report |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::HandleRepositioning(): Can't get State of decoder - trying to send reposition request!")); |
| |
| 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, "PVMFOMXAudioDecNode::HandleRepositioning() Component State is not executing or paused, do not proceed with repositioning")); |
| |
| 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, "PVMFOMXAudioDecNode::HandleRepositioning() Sending Flush command to component")); |
| |
| // send command to flush all ports (arg is -1) |
| err = OMX_SendCommand(iOMXAudioDecoder, OMX_CommandFlush, -1, NULL); |
| if (err != OMX_ErrorNone) |
| { |
| //Error condition report |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXAudioDecNode::HandleRepositioning(): Can't send flush command - trying to send reposition request!")); |
| |
| sState = OMX_StateInvalid; |
| ReportErrorEvent(PVMFErrResourceConfiguration); |
| ChangeNodeState(EPVMFNodeError); |
| return false; |
| } |
| |
| } |
| |
| if (iIsRepositionDoneReceivedFromComponent) |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXAudioDecNode::HandleRepositioning() Component has flushed both ports, and is done repositioning")); |
| |
| 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, "PVMFOMXAudioDecNode::HandleRepositioning() Component is not yet done repositioning ")); |
| |
| return false; |
| } |
| |
| |
| |
| PVMFStatus PVMFOMXAudioDecNode::CreateLATMParser() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iLogger, PVLOGMSG_INFO, (0, "PVMFOMXAudioDecNode::CreateLATMParser() In")); |
| |
| // First clean up if necessary |
| DeleteLATMParser(); |
| |
| // Instantiate the LATM parser |
| iLATMParser = OSCL_NEW(PV_LATM_Parser, ()); |
| if (!iLATMParser) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXAudioDecNode::CreateLATMParser() LATM parser instantiation failed")); |
| return PVMFErrNoMemory; |
| } |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iLogger, PVLOGMSG_INFO, (0, "PVMFOMXAudioDecNode::CreateLATMParser() Out")); |
| return PVMFSuccess; |
| } |
| |
| PVMFStatus PVMFOMXAudioDecNode::DeleteLATMParser() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iLogger, PVLOGMSG_INFO, (0, "PVMFOMXAudioDecNode::DeleteLATMParser() In")); |
| |
| // Delete LATM parser if there is one |
| if (iLATMParser) |
| { |
| OSCL_DELETE(iLATMParser); |
| iLATMParser = NULL; |
| } |
| |
| if (iLATMConfigBuffer) |
| { |
| oscl_free(iLATMConfigBuffer); |
| iLATMConfigBuffer = NULL; |
| iLATMConfigBufferSize = 0; |
| } |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iLogger, PVLOGMSG_INFO, (0, "PVMFOMXAudioDecNode::DeleteLATMParser() Out")); |
| return PVMFSuccess; |
| } |
| |
| |
| |
| |
| |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| uint32 PVMFOMXAudioDecNode::GetNumMetadataKeys(char* aQueryKeyString) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::GetNumMetadataKeys() called")); |
| |
| uint32 num_entries = 0; |
| |
| if (aQueryKeyString == NULL) |
| { |
| num_entries = iAvailableMetadataKeys.size(); |
| } |
| else |
| { |
| for (uint32 i = 0; i < iAvailableMetadataKeys.size(); i++) |
| { |
| if (pv_mime_strcmp(iAvailableMetadataKeys[i].get_cstr(), aQueryKeyString) >= 0) |
| { |
| num_entries++; |
| } |
| } |
| } |
| return num_entries; // Number of elements |
| |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////////////// |
| void PVMFOMXAudioDecNode::setObserver(PvmiConfigAndCapabilityCmdObserver* aObserver) |
| { |
| OSCL_UNUSED_ARG(aObserver); |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::setObserver()")); |
| // This method is not supported so leave |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXAudioDecNode::setObserver() is not supported!")); |
| OSCL_LEAVE(PVMFErrNotSupported); |
| } |
| |
| |
| PVMFStatus PVMFOMXAudioDecNode::getParametersSync(PvmiMIOSession aSession, PvmiKeyType aIdentifier, PvmiKvp*& aParameters, int& aNumParamElements, PvmiCapabilityContext aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::getParametersSync()")); |
| OSCL_UNUSED_ARG(aSession); |
| |
| return DoCapConfigGetParametersSync(aIdentifier, aParameters, aNumParamElements, aContext); |
| } |
| |
| |
| PVMFStatus PVMFOMXAudioDecNode::releaseParameters(PvmiMIOSession aSession, PvmiKvp* aParameters, int aNumElements) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::releaseParameters()")); |
| OSCL_UNUSED_ARG(aSession); |
| |
| return DoCapConfigReleaseParameters(aParameters, aNumElements); |
| } |
| |
| |
| void PVMFOMXAudioDecNode::createContext(PvmiMIOSession aSession, PvmiCapabilityContext& aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::createContext()")); |
| OSCL_UNUSED_ARG(aSession); |
| OSCL_UNUSED_ARG(aContext); |
| // This method is not supported so leave |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXAudioDecNode::createContext() is not supported!")); |
| OSCL_LEAVE(PVMFErrNotSupported); |
| } |
| |
| |
| void PVMFOMXAudioDecNode::setContextParameters(PvmiMIOSession aSession, PvmiCapabilityContext& aContext, PvmiKvp* aParameters, int aNumParamElements) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::setContextParameters()")); |
| 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, "PVMFOMXAudioDecNode::setContextParameters() is not supported!")); |
| OSCL_LEAVE(PVMFErrNotSupported); |
| } |
| |
| |
| void PVMFOMXAudioDecNode::DeleteContext(PvmiMIOSession aSession, PvmiCapabilityContext& aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::DeleteContext()")); |
| OSCL_UNUSED_ARG(aSession); |
| OSCL_UNUSED_ARG(aContext); |
| // This method is not supported so leave |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXAudioDecNode::DeleteContext() is not supported!")); |
| OSCL_LEAVE(PVMFErrNotSupported); |
| } |
| |
| |
| void PVMFOMXAudioDecNode::setParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters, int aNumElements, PvmiKvp* &aRetKVP) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::setParametersSync()")); |
| OSCL_UNUSED_ARG(aSession); |
| |
| // Complete the request synchronously |
| DoCapConfigSetParameters(aParameters, aNumElements, aRetKVP); |
| } |
| |
| |
| PVMFCommandId PVMFOMXAudioDecNode::setParametersAsync(PvmiMIOSession aSession, PvmiKvp* aParameters, int aNumElements, PvmiKvp*& aRetKVP, OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::setParametersAsync()")); |
| 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, "PVMFOMXAudioDecNode::setParametersAsync() is not supported!")); |
| OSCL_LEAVE(PVMFErrNotSupported); |
| return 0; |
| } |
| |
| |
| uint32 PVMFOMXAudioDecNode::getCapabilityMetric(PvmiMIOSession aSession) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::getCapabilityMetric()")); |
| OSCL_UNUSED_ARG(aSession); |
| // Not supported so return 0 |
| return 0; |
| } |
| |
| |
| PVMFStatus PVMFOMXAudioDecNode::verifyParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters, int aNumElements) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::verifyParametersSync()")); |
| OSCL_UNUSED_ARG(aSession); |
| |
| return DoCapConfigVerifyParameters(aParameters, aNumElements); |
| } |
| |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| uint32 PVMFOMXAudioDecNode::GetNumMetadataValues(PVMFMetadataList& aKeyList) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::GetNumMetadataValues() called")); |
| |
| uint32 numkeys = aKeyList.size(); |
| |
| if (numkeys <= 0) |
| { |
| // Don't do anything |
| return 0; |
| } |
| |
| // Count the number of value entries for the provided key list |
| uint32 numvalentries = 0; |
| for (uint32 lcv = 0; lcv < numkeys; lcv++) |
| { |
| if ((oscl_strcmp(aKeyList[lcv].get_cstr(), PVOMXAUDIODECMETADATA_CODECINFO_AUDIO_CHANNELS_KEY) == 0)) |
| { |
| // Channels |
| if (iNumberOfAudioChannels > 0) |
| { |
| ++numvalentries; |
| } |
| } |
| else if ((oscl_strcmp(aKeyList[lcv].get_cstr(), PVOMXAUDIODECMETADATA_CODECINFO_AUDIO_SAMPLERATE_KEY) == 0) && (iPCMSamplingRate > 0)) |
| { |
| // Sample rate |
| ++numvalentries; |
| } |
| else if ((oscl_strcmp(aKeyList[lcv].get_cstr(), PVOMXAUDIODECMETADATA_CODECINFO_AUDIO_FORMAT_KEY) == 0) && |
| iInPort != NULL) |
| { |
| // Format |
| if ((((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_LATM) || |
| (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_MPEG4_AUDIO) || |
| (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_ADIF) || |
| (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_AMR_IF2) || |
| (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_AMR_IETF) || |
| (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_AMR_IETF_COMBINED) || |
| (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_AMRWB_IETF) || |
| (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_AMRWB_IETF_PAYLOAD) || |
| (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_MP3) || |
| (((PVMFOMXAudioDecPort*)iInPort)->iFormat == PVMF_WMA) |
| |
| ) |
| |
| { |
| ++numvalentries; |
| } |
| } |
| } |
| |
| return numvalentries; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXAudioDecNode::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, "PVMFOMXAudioDecNodeCommand::GetNodeMetadataKeys() called")); |
| |
| PVMFOMXAudioDecNodeCommand cmd; |
| cmd.PVMFOMXAudioDecNodeCommand::Construct(aSessionId, PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_GETNODEMETADATAKEY, &aKeyList, starting_index, max_entries, query_key, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXAudioDecNode::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, "PVMFOMXAudioDecNodeCommand::GetNodeMetadataValue() called")); |
| |
| PVMFOMXAudioDecNodeCommand cmd; |
| cmd.PVMFOMXAudioDecNodeCommand::Construct(aSessionId, PVMFOMXAudioDecNodeCommand::PVOMXAUDIODEC_NODE_CMD_GETNODEMETADATAVALUE, &aKeyList, &aValueList, starting_index, max_entries, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| // From PVMFMetadataExtensionInterface |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PVMFOMXAudioDecNode::ReleaseNodeMetadataKeys(PVMFMetadataList& , uint32 , uint32) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::ReleaseNodeMetadataKeys() called")); |
| //nothing needed-- there's no dynamic allocation in this node's key list |
| return PVMFSuccess; |
| } |
| |
| // From PVMFMetadataExtensionInterface |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PVMFOMXAudioDecNode::ReleaseNodeMetadataValues(Oscl_Vector<PvmiKvp, OsclMemAllocator>& aValueList, uint32 start, uint32 end) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::ReleaseNodeMetadataValues() called")); |
| |
| if (aValueList.size() == 0 || start < 0 || start > end) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXAudioDecNode::ReleaseNodeMetadataValues() Invalid start/end index")); |
| 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 |
| PVMFStatus PVMFOMXAudioDecNode::DoCapConfigGetParametersSync(PvmiKeyType aIdentifier, PvmiKvp*& aParameters, int& aNumParamElements, PvmiCapabilityContext aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::DoCapConfigGetParametersSync() In")); |
| OSCL_UNUSED_ARG(aContext); |
| |
| return PVMFFailure; |
| } |
| |
| |
| PVMFStatus PVMFOMXAudioDecNode::DoCapConfigReleaseParameters(PvmiKvp* aParameters, int aNumElements) |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::DoCapConfigReleaseParameters() Out")); |
| return PVMFSuccess; |
| } |
| |
| |
| void PVMFOMXAudioDecNode::DoCapConfigSetParameters(PvmiKvp* aParameters, int aNumElements, PvmiKvp* &aRetKVP) |
| { |
| |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::DoCapConfigSetParameters() Out")); |
| } |
| |
| |
| PVMFStatus PVMFOMXAudioDecNode::DoCapConfigVerifyParameters(PvmiKvp* aParameters, int aNumElements) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::DoCapConfigVerifyParameters() In")); |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::DoCapConfigVerifyParameters() Out")); |
| return PVMFSuccess; |
| } |
| |
| |
| |
| PVMFStatus PVMFOMXAudioDecNode::DoGetVideoDecNodeParameter(PvmiKvp*& aParameters, int& aNumParamElements, int32 aIndex, PvmiKvpAttr reqattr) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::DoGetVideoDecNodeParameter() In")); |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::DoGetVideoDecNodeParameter() Out")); |
| return PVMFSuccess; |
| } |
| |
| |
| |
| PVMFStatus PVMFOMXAudioDecNode::DoVerifyAndSetVideoDecNodeParameter(PvmiKvp& aParameter, bool aSetParam) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::DoVerifyAndSetVideoDecNodeParameter() In")); |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXAudioDecNode::DoVerifyAndSetVideoDecNodeParameter() Out")); |
| return PVMFSuccess; |
| } |
| |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| void PVMFOMXAudioDecNode::LogDiagnostics() |
| { |
| if (iDiagnosticsLogged == false) |
| { |
| iDiagnosticsLogged = true; |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, iDiagnosticsLogger, PVLOGMSG_INFO, (0, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@")); |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, iDiagnosticsLogger, PVLOGMSG_INFO, (0, "PVMFOMXAudioDecNode - Number of YUV Frames Sent = %d", iSeqNum)); |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, iDiagnosticsLogger, PVLOGMSG_INFO, (0, "PVMFOMXAudioDecNode - TS of last decoded video frame = %d", iOutTimeStamp)); |
| } |
| } |
| |
| // needed for WMA parameter verification |
| bool PVMFOMXAudioDecNode::VerifyParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters, int num_elements) |
| { |
| OSCL_UNUSED_ARG(aSession); |
| OSCL_UNUSED_ARG(num_elements); |
| if (pv_mime_strcmp(aParameters->key, PVMF_BITRATE_VALUE_KEY) == 0) |
| { |
| if (((PVMFOMXAudioDecPort*)iOutPort)->verifyConnectedPortParametersSync(PVMF_BITRATE_VALUE_KEY, &(aParameters->value.uint32_value)) != PVMFSuccess) |
| { |
| return false; |
| } |
| return true; |
| } |
| else if (pv_mime_strcmp(aParameters->key, PVMF_FORMAT_SPECIFIC_INFO_KEY) < 0) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR, (0, "PVMFOMXAudioDecNode::VerifyParametersSync() - Unsupported Key")); |
| OSCL_ASSERT(false); |
| } |
| return true; |
| } |
| |
| |
| |
| |
| |
| |