| /* ------------------------------------------------------------------ |
| * Copyright (C) 1998-2009 PacketVideo |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
| * express or implied. |
| * See the License for the specific language governing permissions |
| * and limitations under the License. |
| * ------------------------------------------------------------------- |
| */ |
| #include "pvmf_omx_enc_node.h" |
| #include "pvlogger.h" |
| #include "oscl_error_codes.h" |
| #include "pvmf_omx_enc_port.h" |
| #include "pv_mime_string_utils.h" |
| #include "oscl_snprintf.h" |
| #include "pvmf_media_cmd.h" |
| #include "pvmf_media_msg_format_ids.h" |
| #include "pvmi_kvp_util.h" |
| |
| #ifdef _DEBUG |
| #include <stdio.h> |
| #endif |
| |
| #include "OMX_Core.h" |
| #include "pvmf_omx_enc_callbacks.h" //used for thin AO in encoder's callbacks |
| #include "pv_omxcore.h" |
| |
| #define CONFIG_SIZE_AND_VERSION(param) \ |
| param.nSize=sizeof(param); \ |
| param.nVersion.s.nVersionMajor = SPECVERSIONMAJOR; \ |
| param.nVersion.s.nVersionMinor = SPECVERSIONMINOR; \ |
| param.nVersion.s.nRevision = SPECREVISION; \ |
| param.nVersion.s.nStep = SPECSTEP; |
| |
| |
| #define CHECK_OMX_ERR_AND_RETURN(Err, str) \ |
| if (Err != OMX_ErrorNone) \ |
| { \ |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, str)); \ |
| } |
| |
| |
| #define PVOMXENC_EXTRA_YUVBUFFER_POOLNUM 3 |
| #define PVOMXENC_MEDIADATA_POOLNUM (PVOMXENCMAXNUMDPBFRAMESPLUS1 + PVOMXENC_EXTRA_YUVBUFFER_POOLNUM) |
| #define PVOMXENC_MEDIADATA_CHUNKSIZE 128 |
| |
| #include "utils/Log.h" |
| #undef LOG_TAG |
| #define LOG_TAG "PVOMXEncNode" |
| |
| const uint32 DEFAULT_VOL_HEADER_LENGTH = 28; |
| const uint8 DEFAULT_VOL_HEADER[DEFAULT_VOL_HEADER_LENGTH] = |
| { |
| 0x00, 0x00, 0x01, 0xB0, 0x08, 0x00, 0x00, 0x01, |
| 0xB5, 0x09, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, |
| 0x01, 0x20, 0x00, 0x84, 0x40, 0xFA, 0x28, 0x2C, |
| 0x20, 0x90, 0xA2, 0x1F |
| }; |
| |
| |
| #ifdef _TEST_AE_ERROR_HANDLING |
| const uint32 FAIL_NODE_CMD_START = 2; |
| const uint32 FAIL_NODE_CMD_STOP = 3; |
| const uint32 FAIL_NODE_CMD_FLUSH = 4; |
| const uint32 FAIL_NODE_CMD_PAUSE = 5; |
| const uint32 FAIL_NODE_CMD_RELEASE_PORT = 7; |
| #endif |
| |
| #define PVMF_OMXENC_NUM_METADATA_VALUES 6 |
| |
| // Constant character strings for metadata keys |
| static const char PVOMXENCMETADATA_CODECINFO_VIDEO_FORMAT_KEY[] = "codec-info/video/format"; |
| static const char PVOMXENCMETADATA_CODECINFO_VIDEO_WIDTH_KEY[] = "codec-info/video/width"; |
| static const char PVOMXENCMETADATA_CODECINFO_VIDEO_HEIGHT_KEY[] = "codec-info/video/height"; |
| static const char PVOMXENCMETADATA_CODECINFO_VIDEO_PROFILE_KEY[] = "codec-info/video/profile"; |
| static const char PVOMXENCMETADATA_CODECINFO_VIDEO_LEVEL_KEY[] = "codec-info/video/level"; |
| static const char PVOMXENCMETADATA_CODECINFO_VIDEO_AVGBITRATE_KEY[] = "codec-info/video/avgbitrate";//(bits per sec) |
| |
| |
| static const char PVOMXENCMETADATA_SEMICOLON[] = ";"; |
| |
| static const char LOG_ID_AUDIO_AMRNB[] = "Audio_AMRNB"; |
| static const char LOG_ID_AUDIO_AMRWB[] = "Audio_AMRWB"; |
| static const char LOG_ID_AUDIO_AAC[] = "Audio_AAC"; |
| static const char LOG_ID_VIDEO_H263[] = "Video_H263"; |
| static const char LOG_ID_VIDEO_M4V[] = "Video_M4V"; |
| static const char LOG_ID_VIDEO_AVC[] = "Video_AVC"; |
| static const char LOG_ID_UNKNOWN[] = "TypeNotSetYet"; |
| |
| // OMX CALLBACKS |
| // 1) AO OMX component running in the same thread as the OMX node |
| // In this case, the callbacks can be called directly from the component |
| // The callback: OMX Component->CallbackEventHandler->EventHandlerProcessing |
| // The callback can perform do RunIfNotReady |
| |
| // 2) Multithreaded component |
| // In this case, the callback is made using the threadsafe callback (TSCB) AO |
| // Component thread : OMX Component->CallbackEventHandler->TSCB(ReceiveEvent) => event is queued |
| // Node thread : dequeue event => TSCB(ProcessEvent)->ProcessCallbackEventHandler->EventHandlerProcessing |
| |
| |
| |
| // callback for Event Handler - in multithreaded case, event is queued to be processed later |
| // in AO case, event is processed immediately by calling EventHandlerProcessing |
| OMX_ERRORTYPE CallbackEventHandlerEnc(OMX_OUT OMX_HANDLETYPE aComponent, |
| OMX_OUT OMX_PTR aAppData, |
| OMX_OUT OMX_EVENTTYPE aEvent, |
| OMX_OUT OMX_U32 aData1, |
| OMX_OUT OMX_U32 aData2, |
| OMX_OUT OMX_PTR aEventData) |
| { |
| |
| PVMFOMXEncNode *Node = (PVMFOMXEncNode *) aAppData; |
| |
| if (Node->IsComponentMultiThreaded()) |
| { |
| // allocate the memory for the callback event specific data |
| //EventHandlerSpecificData* ED = (EventHandlerSpecificData*) oscl_malloc(sizeof (EventHandlerSpecificData)); |
| EventHandlerSpecificData* ED = (EventHandlerSpecificData*) Node->iThreadSafeHandlerEventHandler->iMemoryPool->allocate(sizeof(EventHandlerSpecificData)); |
| |
| // pack the relevant data into the structure |
| ED->hComponent = aComponent; |
| ED->pAppData = aAppData; |
| ED->eEvent = aEvent; |
| ED->nData1 = aData1; |
| ED->nData2 = aData2; |
| ED->pEventData = aEventData; |
| |
| // convert the pointer into OsclAny ptr |
| OsclAny* P = (OsclAny*) ED; |
| |
| |
| // CALL the generic callback AO API: |
| Node->iThreadSafeHandlerEventHandler->ReceiveEvent(P); |
| |
| return OMX_ErrorNone; |
| } |
| else |
| { |
| |
| OMX_ERRORTYPE status; |
| status = Node->EventHandlerProcessing(aComponent, aAppData, aEvent, aData1, aData2, aEventData); |
| return status; |
| } |
| |
| } |
| |
| |
| // callback for EmptyBufferDone - in multithreaded case, event is queued to be processed later |
| // in AO case, event is processed immediately by calling EmptyBufferDoneProcessing |
| OMX_ERRORTYPE CallbackEmptyBufferDoneEnc(OMX_OUT OMX_HANDLETYPE aComponent, |
| OMX_OUT OMX_PTR aAppData, |
| OMX_OUT OMX_BUFFERHEADERTYPE* aBuffer) |
| { |
| |
| PVMFOMXEncNode *Node = (PVMFOMXEncNode *) aAppData; |
| if (Node->IsComponentMultiThreaded()) |
| { |
| |
| // allocate the memory for the callback event specific data |
| //EmptyBufferDoneSpecificData* ED = (EmptyBufferDoneSpecificData*) oscl_malloc(sizeof (EmptyBufferDoneSpecificData)); |
| EmptyBufferDoneSpecificData* ED = (EmptyBufferDoneSpecificData*) Node->iThreadSafeHandlerEmptyBufferDone->iMemoryPool->allocate(sizeof(EmptyBufferDoneSpecificData)); |
| |
| // pack the relevant data into the structure |
| ED->hComponent = aComponent; |
| ED->pAppData = aAppData; |
| ED->pBuffer = aBuffer; |
| |
| // convert the pointer into OsclAny ptr |
| OsclAny* P = (OsclAny*) ED; |
| |
| // CALL the generic callback AO API: |
| Node->iThreadSafeHandlerEmptyBufferDone->ReceiveEvent(P); |
| |
| return OMX_ErrorNone; |
| } |
| else |
| { |
| OMX_ERRORTYPE status; |
| status = Node->EmptyBufferDoneProcessing(aComponent, aAppData, aBuffer); |
| return status; |
| } |
| |
| } |
| |
| // callback for FillBufferDone - in multithreaded case, event is queued to be processed later |
| // in AO case, event is processed immediately by calling FillBufferDoneProcessing |
| OMX_ERRORTYPE CallbackFillBufferDoneEnc(OMX_OUT OMX_HANDLETYPE aComponent, |
| OMX_OUT OMX_PTR aAppData, |
| OMX_OUT OMX_BUFFERHEADERTYPE* aBuffer) |
| { |
| PVMFOMXEncNode *Node = (PVMFOMXEncNode *) aAppData; |
| if (Node->IsComponentMultiThreaded()) |
| { |
| |
| // allocate the memory for the callback event specific data |
| //FillBufferDoneSpecificData* ED = (FillBufferDoneSpecificData*) oscl_malloc(sizeof (FillBufferDoneSpecificData)); |
| FillBufferDoneSpecificData* ED = (FillBufferDoneSpecificData*) Node->iThreadSafeHandlerFillBufferDone->iMemoryPool->allocate(sizeof(FillBufferDoneSpecificData)); |
| |
| // pack the relevant data into the structure |
| ED->hComponent = aComponent; |
| ED->pAppData = aAppData; |
| ED->pBuffer = aBuffer; |
| |
| // convert the pointer into OsclAny ptr |
| OsclAny* P = (OsclAny*) ED; |
| |
| // CALL the generic callback AO API: |
| Node->iThreadSafeHandlerFillBufferDone->ReceiveEvent(P); |
| |
| return OMX_ErrorNone; |
| } |
| else |
| { |
| OMX_ERRORTYPE status; |
| status = Node->FillBufferDoneProcessing(aComponent, aAppData, aBuffer); |
| return status; |
| } |
| |
| } |
| |
| // Callback processing in multithreaded case - dequeued event - call EventHandlerProcessing |
| OsclReturnCode PVMFOMXEncNode::ProcessCallbackEventHandler_MultiThreaded(OsclAny* P) |
| { |
| |
| // re-cast the pointer |
| |
| EventHandlerSpecificData* ED = (EventHandlerSpecificData*) P; |
| |
| OMX_HANDLETYPE aComponent = ED->hComponent; |
| OMX_PTR aAppData = ED->pAppData; |
| OMX_EVENTTYPE aEvent = ED->eEvent; |
| OMX_U32 aData1 = ED->nData1; |
| OMX_U32 aData2 = ED->nData2; |
| OMX_PTR aEventData = ED->pEventData; |
| |
| |
| EventHandlerProcessing(aComponent, aAppData, aEvent, aData1, aData2, aEventData); |
| |
| |
| // release the allocated memory when no longer needed |
| |
| iThreadSafeHandlerEventHandler->iMemoryPool->deallocate(ED); |
| ED = NULL; |
| |
| return OsclSuccess; |
| } |
| |
| |
| |
| // Callback processing in multithreaded case - dequeued event - call EmptyBufferDoneProcessing |
| OsclReturnCode PVMFOMXEncNode::ProcessCallbackEmptyBufferDone_MultiThreaded(OsclAny* P) |
| { |
| |
| |
| // re-cast the pointer |
| EmptyBufferDoneSpecificData* ED = (EmptyBufferDoneSpecificData*) P; |
| |
| OMX_HANDLETYPE aComponent = ED->hComponent; |
| OMX_PTR aAppData = ED->pAppData; |
| OMX_BUFFERHEADERTYPE* aBuffer = ED->pBuffer; |
| |
| EmptyBufferDoneProcessing(aComponent, aAppData, aBuffer); |
| |
| // release the allocated memory when no longer needed |
| |
| iThreadSafeHandlerEmptyBufferDone->iMemoryPool->deallocate(ED); |
| ED = NULL; |
| |
| return OsclSuccess; |
| } |
| |
| |
| // Callback processing in multithreaded case - dequeued event - call FillBufferDoneProcessing |
| OsclReturnCode PVMFOMXEncNode::ProcessCallbackFillBufferDone_MultiThreaded(OsclAny* P) |
| { |
| |
| // re-cast the pointer |
| FillBufferDoneSpecificData* ED = (FillBufferDoneSpecificData*) P; |
| |
| OMX_HANDLETYPE aComponent = ED->hComponent; |
| OMX_PTR aAppData = ED->pAppData; |
| OMX_BUFFERHEADERTYPE* aBuffer = ED->pBuffer; |
| |
| |
| FillBufferDoneProcessing(aComponent, aAppData, aBuffer); |
| |
| |
| // release the allocated memory when no longer needed |
| |
| iThreadSafeHandlerFillBufferDone->iMemoryPool->deallocate(ED); |
| ED = NULL; |
| |
| return OsclSuccess; |
| } |
| ///////////////////////////////////////////////////////////////////////////// |
| // Class Destructor |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFOMXEncNode::~PVMFOMXEncNode() |
| { |
| LogDiagnostics(); |
| |
| //Clearup encoder |
| DeleteOMXEncoder(); |
| |
| // Cleanup callback AOs and Mempools |
| if (iThreadSafeHandlerEventHandler) |
| { |
| OSCL_DELETE(iThreadSafeHandlerEventHandler); |
| iThreadSafeHandlerEventHandler = NULL; |
| } |
| if (iThreadSafeHandlerEmptyBufferDone) |
| { |
| OSCL_DELETE(iThreadSafeHandlerEmptyBufferDone); |
| iThreadSafeHandlerEmptyBufferDone = NULL; |
| } |
| if (iThreadSafeHandlerFillBufferDone) |
| { |
| OSCL_DELETE(iThreadSafeHandlerFillBufferDone); |
| iThreadSafeHandlerFillBufferDone = NULL; |
| } |
| |
| if (iMediaDataMemPool) |
| { |
| iMediaDataMemPool->removeRef(); |
| iMediaDataMemPool = NULL; |
| } |
| |
| if (iOutBufMemoryPool) |
| { |
| iOutBufMemoryPool->removeRef(); |
| iOutBufMemoryPool = NULL; |
| } |
| |
| ipFixedSizeBufferAlloc = NULL; |
| if(ipExternalInputBufferAllocatorInterface) |
| { |
| ipExternalInputBufferAllocatorInterface->removeRef(); |
| ipExternalInputBufferAllocatorInterface = NULL; |
| } |
| |
| if (iInBufMemoryPool) |
| { |
| iInBufMemoryPool->removeRef(); |
| iInBufMemoryPool = NULL; |
| } |
| |
| if (in_ctrl_struct_ptr) |
| { |
| oscl_free(in_ctrl_struct_ptr); |
| in_ctrl_struct_ptr = NULL; |
| } |
| |
| if (in_buff_hdr_ptr) |
| { |
| oscl_free(in_buff_hdr_ptr); |
| in_buff_hdr_ptr = NULL; |
| } |
| |
| if (out_ctrl_struct_ptr) |
| { |
| oscl_free(out_ctrl_struct_ptr); |
| out_ctrl_struct_ptr = NULL; |
| } |
| |
| if (out_buff_hdr_ptr) |
| { |
| oscl_free(out_buff_hdr_ptr); |
| out_buff_hdr_ptr = NULL; |
| } |
| |
| //Thread logoff |
| if (IsAdded()) |
| { |
| RemoveFromScheduler(); |
| iIsAdded = false; |
| } |
| |
| //Cleanup allocated interfaces |
| |
| //Cleanup allocated ports |
| ReleaseAllPorts(); |
| |
| //Cleanup commands |
| //The command queues are self-deleting, but we want to |
| //notify the observer of unprocessed commands. |
| while (!iCurrentCommand.empty()) |
| { |
| CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFFailure); |
| } |
| while (!iInputCommands.empty()) |
| { |
| CommandComplete(iInputCommands, iInputCommands.front(), PVMFFailure); |
| } |
| |
| if (iNALSizeArray != NULL) |
| { |
| oscl_free(iNALSizeArray); |
| } |
| |
| if (iNALPtrArray != NULL) |
| { |
| oscl_free(iNALPtrArray); |
| } |
| |
| //Release Input buffer |
| iDataIn.Unbind(); |
| |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // Add AO to the scheduler |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PVMFOMXEncNode::ThreadLogon() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iLogger, PVLOGMSG_INFO, (0, "PVMFOMXEncNode:ThreadLogon")); |
| |
| switch (iInterfaceState) |
| { |
| case EPVMFNodeCreated: |
| if (!IsAdded()) |
| { |
| AddToScheduler(); |
| iIsAdded = true; |
| } |
| |
| SetState(EPVMFNodeIdle); |
| return PVMFSuccess; |
| // break; This break statement was removed to avoid compiler warning for Unreachable Code |
| default: |
| return PVMFErrInvalidState; |
| // break; This break statement was removed to avoid compiler warning for Unreachable Code |
| } |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // Remove AO from the scheduler |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PVMFOMXEncNode::ThreadLogoff() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iLogger, PVLOGMSG_INFO, (0, "PVMFOMXEncNode-%s::ThreadLogoff", iNodeTypeId)); |
| |
| switch (iInterfaceState) |
| { |
| case EPVMFNodeIdle: |
| if (IsAdded()) |
| { |
| RemoveFromScheduler(); |
| iIsAdded = false; |
| } |
| iLogger = NULL; |
| SetState(EPVMFNodeCreated); |
| return PVMFSuccess; |
| // break; This break statement was removed to avoid compiler warning for Unreachable Code |
| |
| default: |
| return PVMFErrInvalidState; |
| // break; This break statement was removed to avoid compiler warning for Unreachable Code |
| } |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PVMFOMXEncNode::GetCapability(PVMFNodeCapability& aNodeCapability) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::GetCapability() called", iNodeTypeId)); |
| |
| aNodeCapability = iCapability; |
| return PVMFSuccess; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFPortIter* PVMFOMXEncNode::GetPorts(const PVMFPortFilter* aFilter) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::GetPorts() %s called", iNodeTypeId)); |
| |
| OSCL_UNUSED_ARG(aFilter); |
| |
| return NULL; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXEncNode::QueueCommandL(PVMFOMXEncNodeCommand& aCmd) |
| { |
| PVMFCommandId id; |
| |
| id = iInputCommands.AddL(aCmd); |
| |
| if (iInputCommands.size() == 1) |
| { |
| //wakeup the AO all the rest of input commands will reschedule the AO in Run |
| RunIfNotReady(); |
| } |
| return id; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXEncNode::QueryUUID(PVMFSessionId s, const PvmfMimeString& aMimeType, |
| Oscl_Vector<PVUuid, PVMFOMXEncNodeAllocator>& aUuids, |
| bool aExactUuidsOnly, |
| const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::QueryUUID() called", iNodeTypeId)); |
| PVMFOMXEncNodeCommand cmd; |
| cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_QUERYUUID, aMimeType, aUuids, aExactUuidsOnly, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXEncNode::QueryInterface(PVMFSessionId s, const PVUuid& aUuid, |
| PVInterface*& aInterfacePtr, |
| const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::QueryInterface() called", iNodeTypeId)); |
| PVMFOMXEncNodeCommand cmd; |
| cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_QUERYINTERFACE, aUuid, aInterfacePtr, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXEncNode::RequestPort(PVMFSessionId s, int32 aPortTag, const PvmfMimeString* aPortConfig, const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::RequestPort() called", iNodeTypeId)); |
| PVMFOMXEncNodeCommand cmd; |
| |
| // IMPORTANT NOTE - ENGINE IS SENDING THE MIME TYPE FOR THE ENCODER INPUT/OUTPUT FORMAT THRU THE PORT PARAMETER |
| cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMF_GENERIC_NODE_REQUESTPORT, aPortTag, aPortConfig, aContext); |
| return QueueCommandL(cmd); |
| |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PVMFOMXEncNode::ReleasePort(PVMFSessionId s, PVMFPortInterface& aPort, const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::ReleasePort() called", iNodeTypeId)); |
| PVMFOMXEncNodeCommand cmd; |
| cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_RELEASEPORT, aPort, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXEncNode::Init(PVMFSessionId s, const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::Init() called", iNodeTypeId)); |
| PVMFOMXEncNodeCommand cmd; |
| cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_INIT, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXEncNode::Prepare(PVMFSessionId s, const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::Prepare() called", iNodeTypeId)); |
| PVMFOMXEncNodeCommand cmd; |
| cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_PREPARE, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXEncNode::Start(PVMFSessionId s, const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::Start() called", iNodeTypeId)); |
| PVMFOMXEncNodeCommand cmd; |
| cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_START, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXEncNode::Stop(PVMFSessionId s, const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::Stop() called", iNodeTypeId)); |
| PVMFOMXEncNodeCommand cmd; |
| cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_STOP, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXEncNode::Flush(PVMFSessionId s, const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::Flush() called", iNodeTypeId)); |
| PVMFOMXEncNodeCommand cmd; |
| cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_FLUSH, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXEncNode::Pause(PVMFSessionId s, const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::Pause() called", iNodeTypeId)); |
| PVMFOMXEncNodeCommand cmd; |
| cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_PAUSE, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXEncNode::Reset(PVMFSessionId s, const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::Reset() called", iNodeTypeId)); |
| PVMFOMXEncNodeCommand cmd; |
| cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_RESET, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXEncNode::CancelAllCommands(PVMFSessionId s, const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::CancelAllCommands() called", iNodeTypeId)); |
| PVMFOMXEncNodeCommand cmd; |
| cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_CANCELALL, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMFOMXEncNode::CancelCommand(PVMFSessionId s, PVMFCommandId aCmdId, const OsclAny* aContext) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::CancelCommand() called", iNodeTypeId)); |
| PVMFOMXEncNodeCommand cmd; |
| cmd.PVMFOMXEncNodeCommandBase::Construct(s, PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_CANCELCMD, aCmdId, aContext); |
| return QueueCommandL(cmd); |
| } |
| |
| |
| |
| |
| |
| ///////////////////// |
| // Private Section // |
| ///////////////////// |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // Class Constructor |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFOMXEncNode::PVMFOMXEncNode(int32 aPriority) : |
| OsclActiveObject(aPriority, "PVMFOMXEncNode"), |
| iInPort(NULL), |
| iOutPort(NULL), |
| iOutBufMemoryPool(NULL), |
| iMediaDataMemPool(NULL), |
| iOMXComponentOutputBufferSize(0), |
| iOutputAllocSize(0), |
| iNumOutstandingOutputBuffers(0), |
| iNumOutstandingInputBuffers(0), |
| iProcessingState(EPVMFOMXEncNodeProcessingState_Idle), |
| iOMXEncoder(NULL), |
| iSendBOS(false), |
| iStreamID(0), |
| iBOSTimestamp(0), |
| iSeqNum(0), |
| iSeqNum_In(0), |
| iIsAdded(true), |
| iLogger(NULL), |
| iDataPathLogger(NULL), |
| iClockLogger(NULL), |
| iExtensionRefCount(0), |
| iEndOfDataReached(false), |
| iEndOfDataTimestamp(0), |
| iDiagnosticsLogger(NULL), |
| iDiagnosticsLogged(false), |
| iAvgBitrateValue(0), |
| iResetInProgress(false), |
| iResetMsgSent(false), |
| iStopInResetMsgSent(false), |
| ipExternalInputBufferAllocatorInterface(NULL), |
| ipFixedSizeBufferAlloc(NULL) |
| { |
| iInterfaceState = EPVMFNodeCreated; |
| |
| |
| // Allocate memory for VOL header |
| uint refCounterSize = oscl_mem_aligned_size(sizeof(OsclRefCounterDA)); |
| uint VolHdrSize = refCounterSize + DEFAULT_VOL_HEADER_LENGTH; |
| uint8 *memBufferVOLHeader = NULL; |
| |
| uint ParamSetSize = refCounterSize + DEFAULT_PARAMS_SET_LENGTH; |
| uint8 *memBufferParamSet = NULL; |
| |
| |
| int32 err; |
| OSCL_TRY(err, |
| |
| //Create the input command queue. Use a reserve to avoid lots of |
| //dynamic memory allocation. |
| iInputCommands.Construct(PVMF_OMXENC_NODE_COMMAND_ID_START, PVMF_OMXENC_NODE_COMMAND_VECTOR_RESERVE); |
| |
| //Create the "current command" queue. It will only contain one |
| //command at a time, so use a reserve of 1. |
| iCurrentCommand.Construct(0, 1); |
| |
| //Set the node capability data. |
| //This node can support an unlimited number of ports. |
| iCapability.iCanSupportMultipleInputPorts = false; |
| iCapability.iCanSupportMultipleOutputPorts = false; |
| iCapability.iHasMaxNumberOfPorts = true; |
| iCapability.iMaxNumberOfPorts = 2; |
| |
| // video output |
| iCapability.iOutputFormatCapability.push_back(PVMF_MIME_H264_VIDEO_MP4); |
| iCapability.iOutputFormatCapability.push_back(PVMF_MIME_H264_VIDEO_RAW); |
| //iCapability.iOutputFormatCapability.push_back(PVMF_MIME_H264_VIDEO); |
| iCapability.iOutputFormatCapability.push_back(PVMF_MIME_M4V); |
| iCapability.iOutputFormatCapability.push_back(PVMF_MIME_H2631998); |
| iCapability.iOutputFormatCapability.push_back(PVMF_MIME_H2632000); |
| //iCapability.iOutputFormatCapability.push_back(PVMF_MIME_WMV); |
| // audio output |
| iCapability.iOutputFormatCapability.push_back(PVMF_MIME_AMR_IETF); |
| iCapability.iOutputFormatCapability.push_back(PVMF_MIME_AMRWB_IETF); |
| iCapability.iOutputFormatCapability.push_back(PVMF_MIME_AMR_IF2); |
| iCapability.iOutputFormatCapability.push_back(PVMF_MIME_ADTS); |
| iCapability.iOutputFormatCapability.push_back(PVMF_MIME_ADIF); |
| iCapability.iOutputFormatCapability.push_back(PVMF_MIME_MPEG4_AUDIO); |
| |
| // video input |
| iCapability.iInputFormatCapability.push_back(PVMF_MIME_YUV420); |
| iCapability.iInputFormatCapability.push_back(PVMF_MIME_YUV422); |
| iCapability.iInputFormatCapability.push_back(PVMF_MIME_YUV422_INTERLEAVED_UYVY); |
| iCapability.iInputFormatCapability.push_back(PVMF_MIME_YUV422_INTERLEAVED_YUYV); |
| iCapability.iInputFormatCapability.push_back(PVMF_MIME_RGB24); |
| iCapability.iInputFormatCapability.push_back(PVMF_MIME_RGB12); |
| |
| // audio input |
| iCapability.iInputFormatCapability.push_back(PVMF_MIME_PCM16); |
| |
| |
| |
| iAvailableMetadataKeys.reserve(PVMF_OMXENC_NUM_METADATA_VALUES); |
| iAvailableMetadataKeys.clear(); |
| |
| // for VOL header |
| memBufferVOLHeader = (uint8*)iAlloc.allocate(VolHdrSize); |
| if (!memBufferVOLHeader) |
| { |
| OSCL_LEAVE(PVMFErrNoMemory); |
| } |
| |
| memBufferParamSet = (uint8*) iAlloc.allocate(ParamSetSize); |
| if (!memBufferParamSet) |
| { |
| OSCL_LEAVE(PVMFErrNoMemory); |
| } |
| |
| ); |
| |
| // Save default VOL header |
| oscl_memset(memBufferVOLHeader, 0, DEFAULT_VOL_HEADER_LENGTH); |
| OsclMemoryFragment volHeader; |
| OsclRefCounter* refCounterVOLHeader = new(memBufferVOLHeader) OsclRefCounterDA(memBufferVOLHeader, |
| (OsclDestructDealloc*)&iAlloc); |
| memBufferVOLHeader += refCounterSize; |
| volHeader.ptr = memBufferVOLHeader; |
| oscl_memcpy(volHeader.ptr, (OsclAny*)DEFAULT_VOL_HEADER, DEFAULT_VOL_HEADER_LENGTH); |
| volHeader.len = DEFAULT_VOL_HEADER_LENGTH; |
| iVolHeader = OsclRefCounterMemFrag(volHeader, refCounterVOLHeader, DEFAULT_VOL_HEADER_LENGTH); |
| |
| |
| // construct SPS&PPS placeholder |
| oscl_memset(memBufferParamSet, 0, DEFAULT_PARAMS_SET_LENGTH); |
| OsclMemoryFragment paramSet; |
| OsclRefCounter* refCounterParamSet = new(memBufferParamSet) OsclRefCounterDA(memBufferParamSet, |
| (OsclDestructDealloc*)&iAlloc); |
| memBufferParamSet += refCounterSize; |
| paramSet.ptr = memBufferParamSet; |
| paramSet.len = DEFAULT_PARAMS_SET_LENGTH; |
| |
| iParamSet = OsclRefCounterMemFrag(paramSet, refCounterParamSet, DEFAULT_PARAMS_SET_LENGTH); |
| |
| // initialize length and number of sps/ppss |
| iParamSet.getMemFrag().len = 0; |
| iNumPPSs = 0; |
| iNumSPSs = 0; |
| iSpsPpsSequenceOver = false; |
| iFirstNAL = false; //set this to false so that mp4 can proceed without a problem. |
| // in case of AVC, this flag will be set after spspps |
| |
| iNALSizeArray = NULL; |
| iNALPtrArray = NULL; |
| iNALSizeArrayMaxElems = 0; |
| iNumNALs = 0; |
| iFirstNALStartCodeSize = 0; |
| |
| iThreadSafeHandlerEventHandler = NULL; |
| iThreadSafeHandlerEmptyBufferDone = NULL; |
| iThreadSafeHandlerFillBufferDone = NULL; |
| |
| iInBufMemoryPool = NULL; |
| iOutBufMemoryPool = NULL; |
| |
| in_ctrl_struct_ptr = NULL; |
| in_buff_hdr_ptr = NULL; |
| out_ctrl_struct_ptr = NULL; |
| out_buff_hdr_ptr = NULL; |
| |
| // init to some value |
| iOMXComponentOutputBufferSize = 0; |
| iNumOutputBuffers = 0; |
| iOMXComponentInputBufferSize = 0; |
| iNumInputBuffers = 0; |
| |
| iDoNotSendOutputBuffersDownstreamFlag = false; |
| iDoNotSaveInputBuffersFlag = false; |
| |
| |
| iOutputBuffersFreed = true;// buffers have not been created yet, so they can be considered freed |
| iInputBuffersFreed = true; |
| |
| // dynamic port reconfig init vars |
| iSecondPortReportedChange = false; |
| iDynamicReconfigInProgress = false; |
| |
| // EOS flag init |
| iIsEOSSentToComponent = false; |
| iIsEOSReceivedFromComponent = false; |
| |
| // init state of component |
| iCurrentEncoderState = OMX_StateInvalid; |
| |
| iTimeStampOut = 0; |
| iTimeStampPrevious = 0; |
| iBufferLenOut = 0; |
| iBufferLenPrevious = 0; |
| iEndOfFrameFlagPrevious = 0; |
| iKeyFrameFlagPrevious = 0; |
| iEndOfNALFlagPrevious = 0; |
| |
| |
| iEndOfFrameFlagOut = 0; |
| iKeyFrameFlagOut = 0; |
| iEndOfNALFlagOut = 0; |
| |
| //if timescale value is 1 000 000 - it means that |
| //timestamp is expressed in units of 1/10^6 (i.e. microseconds) |
| |
| iTimeScale = 1000000; |
| iInTimeScale = 1000; |
| iOutTimeScale = 1000; |
| |
| iInputTimestampClock.set_timescale(iInTimeScale); // keep the timescale set to input timestamp |
| |
| |
| |
| // counts output frames (for logging) |
| iFrameCounter = 0; |
| iInFormat = PVMF_MIME_FORMAT_UNKNOWN; |
| iOutFormat = PVMF_MIME_FORMAT_UNKNOWN; |
| |
| // zero out encoder param structure |
| |
| oscl_memset(&iVideoInputFormat, 0, sizeof(iVideoInputFormat)); |
| |
| // set default values |
| iVideoInputFormat.iFrameWidth = DEFAULT_FRAME_WIDTH; |
| iVideoInputFormat.iFrameHeight = DEFAULT_FRAME_HEIGHT; |
| iVideoInputFormat.iFrameRate = (float)DEFAULT_FRAME_RATE; |
| iVideoInputFormat.iFrameOrientation = 0; |
| |
| oscl_memset(&iVideoEncodeParam, 0, sizeof(iVideoEncodeParam)); |
| |
| iVideoEncodeParam.iEncodeID = 0; |
| iVideoEncodeParam.iNumLayer = 1; |
| iVideoEncodeParam.iFrameWidth[0] = DEFAULT_FRAME_WIDTH; |
| iVideoEncodeParam.iFrameHeight[0] = DEFAULT_FRAME_HEIGHT; |
| iVideoEncodeParam.iBitRate[0] = DEFAULT_BITRATE; |
| iVideoEncodeParam.iFrameRate[0] = (float)DEFAULT_FRAME_RATE; |
| iVideoEncodeParam.iFrameQuality = 10; |
| iVideoEncodeParam.iSceneDetection = false; |
| iVideoEncodeParam.iRVLCEnable = false; |
| iVideoEncodeParam.iIFrameInterval = DEFAULT_I_FRAME_INTERVAL; |
| iVideoEncodeParam.iBufferDelay = (float)0.2; |
| iVideoEncodeParam.iShortHeader = false; |
| iVideoEncodeParam.iDataPartitioning = false; |
| iVideoEncodeParam.iResyncMarker = true; |
| |
| // set the default rate control type to variable bit rate control |
| // since it has better performance |
| iVideoEncodeParam.iRateControlType = PVMFVEN_RATE_CONTROL_VBR; |
| iVideoEncodeParam.iIquant[0] = 15; |
| iVideoEncodeParam.iPquant[0] = 12; |
| iVideoEncodeParam.iBquant[0] = 12; |
| iVideoEncodeParam.iSearchRange = 16; |
| iVideoEncodeParam.iMV8x8 = false; |
| iVideoEncodeParam.iMVHalfPel = true; |
| iVideoEncodeParam.iPacketSize = 256; |
| iVideoEncodeParam.iNoCurrentSkip = false; |
| iVideoEncodeParam.iNoFrameSkip = false; |
| iVideoEncodeParam.iClipDuration = 0; |
| iVideoEncodeParam.iProfileLevel = EI_CORE_LEVEL2; |
| /////////////////AVC SPECIFIC/////////////////////////// |
| iVideoEncodeParam.iEncMode = EI_ENCMODE_RECORDER; |
| iVideoEncodeParam.iAVCProfile = EI_PROFILE_BASELINE; |
| iVideoEncodeParam.iAVCLevel = EI_LEVEL_11; |
| |
| |
| oscl_memset(&iAudioInputFormat, 0, sizeof(iAudioInputFormat)); |
| // Currently, set according to AMR values |
| iAudioInputFormat.iInputInterleaveMode = EINTERLEAVE_LR; |
| iAudioInputFormat.iInputBitsPerSample = 16; |
| iAudioInputFormat.iInputNumChannels = 1; |
| iAudioInputFormat.iInputSamplingRate = 8000; |
| |
| oscl_memset(&iAudioEncodeParam, 0, sizeof(iAudioEncodeParam)); |
| |
| iAudioEncodeParam.iMaxNumOutputFramesPerBuffer = MAX_NUM_AMR_FRAMES_PER_BUFFER; |
| iAudioEncodeParam.iAMRBitrate = GSM_AMR_12_2; |
| iAudioEncodeParam.iOutputBitrate = 24000; |
| iAudioEncodeParam.iOutputNumChannels = iAudioInputFormat.iInputNumChannels; |
| iAudioEncodeParam.iOutputSamplingRate = iAudioInputFormat.iInputSamplingRate; |
| |
| |
| #ifdef _TEST_AE_ERROR_HANDLING |
| iErrorHandlingInit = false; |
| iErrorHandlingEncodeCount = 0; |
| iCountFrames = 0; |
| iErrorDataPathStall = 0; |
| iErrorNodeCmd = 0; |
| iErrorConfigHeader = false; |
| iErrorEncodeFlag = 0; |
| #endif |
| |
| iInputTimestampClock.set_clock(iBOSTimestamp, 0); |
| iOMXTicksTimestamp = ConvertTimestampIntoOMXTicks(iInputTimestampClock); |
| |
| sendYuvFsi = true; |
| |
| iNodeTypeId = LOG_ID_UNKNOWN; |
| iLogger = PVLogger::GetLoggerObject("PVMFOMXEncNode"); |
| iRunlLogger = PVLogger::GetLoggerObject("Run.PVMFOMXEncNode"); |
| iDataPathLogger = PVLogger::GetLoggerObject("datapath"); |
| iClockLogger = PVLogger::GetLoggerObject("clock"); |
| iDiagnosticsLogger = PVLogger::GetLoggerObject("pvplayerdiagnostics.encnode.OMXEncnode"); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // Local Run Routine |
| ///////////////////////////////////////////////////////////////////////////// |
| void PVMFOMXEncNode::Run() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::Run() In", iNodeTypeId)); |
| |
| // if reset is in progress, call DoReset again until Reset Msg is sent |
| if ((iResetInProgress == true) && |
| (iResetMsgSent == false) && |
| (iCurrentCommand.size() > 0) && |
| (iCurrentCommand.front().iCmd == PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_RESET) |
| ) |
| { |
| DoReset(iCurrentCommand.front()); |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVMFOMXEncNode-%s::Run() - Calling DoReset", iNodeTypeId)); |
| return; // don't do anything else |
| } |
| //Check for NODE commands... |
| if (!iInputCommands.empty()) |
| { |
| if (ProcessCommand(iInputCommands.front())) |
| { |
| if (iInterfaceState != EPVMFNodeCreated |
| && (!iInputCommands.empty() || (iInPort && (iInPort->IncomingMsgQueueSize() > 0)) || |
| (iDataIn.GetRep() != NULL))) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVMFOMXEncNode-%s::Run() - rescheduling after process command", iNodeTypeId)); |
| RunIfNotReady(); |
| } |
| return; |
| } |
| |
| if (!iInputCommands.empty()) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVMFOMXEncNode-%s::Run() - rescheduling to process more commands", iNodeTypeId)); |
| RunIfNotReady(); |
| } |
| } |
| else |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVMFOMXEncNode-%s::Run() - Input commands empty", iNodeTypeId)); |
| } |
| |
| if (((iCurrentCommand.size() == 0) && (iInterfaceState != EPVMFNodeStarted)) || |
| ((iCurrentCommand.size() > 0) && (iCurrentCommand.front().iCmd == PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_START) && (iInterfaceState != EPVMFNodeStarted))) |
| { |
| // rescheduling because of input data will be handled in Command Processing Part |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVMFOMXEncNode-%s::Run() - Node not in Started state yet", iNodeTypeId)); |
| return; |
| } |
| |
| |
| // Process port activity, push out all outgoing messages |
| if (iOutPort) |
| { |
| while (iOutPort->OutgoingMsgQueueSize()) |
| { |
| // if port is busy it is going to wakeup from port ready event |
| if (!ProcessOutgoingMsg(iOutPort)) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVMFOMXEncNode-%s::Run() - Outgoing Port Busy, cannot send more msgs", iNodeTypeId)); |
| break; |
| } |
| } |
| } |
| int loopCount = 0; |
| #if (PVLOGGER_INST_LEVEL >= PVLOGMSG_INST_REL) |
| uint32 startticks = OsclTickCount::TickCount(); |
| uint32 starttime = OsclTickCount::TicksToMsec(startticks); |
| #endif |
| do // Try to consume all the data from the Input port |
| { |
| // Process port activity if there is no input data that is being processed |
| // Do not accept any input if EOS needs to be sent out |
| if (iInPort && (iInPort->IncomingMsgQueueSize() > 0) && (iDataIn.GetRep() == NULL) && !iEndOfDataReached) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVMFOMXEncNode-%s::Run() - Getting more input", iNodeTypeId)); |
| if (!ProcessIncomingMsg(iInPort)) |
| { |
| //Re-schedule to come back. |
| RunIfNotReady(); |
| return; |
| } |
| } |
| |
| if (iSendBOS) |
| { |
| SendBeginOfMediaStreamCommand(); |
| } |
| |
| // If in init or ready to encode state, process data in the input port if there is input available and input buffers are present |
| // (note: at EOS, iDataIn will not be available) |
| if ((iDataIn.GetRep() != NULL) || |
| ((iNumOutstandingOutputBuffers < iNumOutputBuffers) && |
| (iProcessingState == EPVMFOMXEncNodeProcessingState_ReadyToEncode) && |
| (iResetMsgSent == false)) || |
| ((iDynamicReconfigInProgress == true) && (iResetMsgSent == false)) |
| ) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, |
| (0, "PVMFOMXEncNode-%s::Run() - Calling HandleProcessingState", iNodeTypeId)); |
| |
| // input data is available, that means there is data to be encoded |
| if (HandleProcessingState() != PVMFSuccess) |
| { |
| // If HandleProcessingState does not return Success, we must wait for an event |
| // no point in rescheduling |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, |
| (0, "PVMFOMXEncNode-%s::Run() - HandleProcessingState did not return Success", iNodeTypeId)); |
| return; |
| } |
| } |
| loopCount++; |
| } |
| while (iInPort && |
| (((iInPort->IncomingMsgQueueSize() > 0) || (iDataIn.GetRep() != NULL)) && (iNumOutstandingInputBuffers < iNumInputBuffers)) |
| && (!iEndOfDataReached) |
| && (iResetMsgSent == false) |
| ); |
| #if (PVLOGGER_INST_LEVEL >= PVLOGMSG_INST_REL) |
| uint32 endticks = OsclTickCount::TickCount(); |
| uint32 endtime = OsclTickCount::TicksToMsec(endticks); |
| uint32 timeinloop; |
| timeinloop = (endtime - starttime); |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iRunlLogger, PVLOGMSG_INFO, |
| (0, "PVMFOMXEncNode-%s::Run() - LoopCount = %d, Time spent in loop(in ms) = %d, iNumOutstandingInputBuffers = %d, iNumOutstandingOutputBuffers = %d ", iNodeTypeId, |
| loopCount, timeinloop, iNumOutstandingInputBuffers, iNumOutstandingOutputBuffers)); |
| #endif |
| // EOS processing: |
| // first send an empty buffer to OMX component and mark the EOS flag |
| // wait for the OMX component to send async event to indicate that it has reached this EOS buffer |
| // then, create and send the EOS message downstream |
| |
| if (iEndOfDataReached && !iDynamicReconfigInProgress) |
| { |
| |
| // if EOS was not sent yet and we have an available input buffer, send EOS buffer to component |
| if (!iIsEOSSentToComponent && (iNumOutstandingInputBuffers < iNumInputBuffers)) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, |
| (0, "PVMFOMXEncNode-%s::Run() - Sending EOS marked buffer To Component ", iNodeTypeId)); |
| |
| iIsEOSSentToComponent = true; |
| |
| |
| // if the component is not yet initialized or if it's in the middle of port reconfig, |
| // don't send EOS buffer to component. It does not care. Just set the flag as if we received |
| // EOS from the component to enable sending EOS downstream |
| if (iProcessingState != EPVMFOMXEncNodeProcessingState_ReadyToEncode) |
| { |
| |
| iIsEOSReceivedFromComponent = true; |
| } |
| else if (!SendEOSBufferToOMXComponent()) |
| { |
| // for some reason, Component can't receive the EOS buffer |
| // it could be that it is not initialized yet (because EOS could be the first msg). In this case, |
| // send the EOS downstream anyway |
| iIsEOSReceivedFromComponent = true; |
| } |
| } |
| |
| // DV: we must wait for event (acknowledgment from component) |
| // before sending EOS downstream. This is because OMX Component will send |
| // the EOS event only after processing remaining buffers |
| |
| if (iIsEOSReceivedFromComponent) |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, |
| (0, "PVMFOMXEncNode-%s::Run() - Received EOS from component, Sending EOS msg downstream ", iNodeTypeId)); |
| |
| if (iOutPort && iOutPort->IsOutgoingQueueBusy()) |
| { |
| // note: we already tried to empty the outgoing q. If it's still busy, |
| // it means that output port is busy. Just return and wait for the port to become free. |
| // this will wake up the node and it will send out a msg from the q etc. |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, |
| (0, "PVMFOMXEncNode-%s::Run() - - EOS cannot be sent downstream, outgoing queue busy - wait", iNodeTypeId)); |
| return; |
| } |
| |
| if (SendEndOfTrackCommand()) // this will only q the EOS |
| { |
| // EOS send downstream OK, so reset the flag |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, |
| (0, "PVMFOMXEncNode-%s::Run() - EOS was queued to be sent downstream", iNodeTypeId)); |
| |
| iEndOfDataReached = false; // to resume normal processing, reset the flags |
| iIsEOSSentToComponent = false; |
| iIsEOSReceivedFromComponent = false; |
| |
| RunIfNotReady(); // Run again to send out the EOS msg from the outgoing q, and resume |
| // normal processing |
| |
| // END OF STREAM EVENT reported by the downstream node. |
| //ReportInfoEvent(PVMFInfoEndOfData); |
| } |
| } |
| else |
| { |
| // keep sending output buffers, it's possible that the component needs to flush output |
| // data at the end |
| while (iNumOutstandingOutputBuffers < iNumOutputBuffers) |
| { |
| if (!SendOutputBufferToOMXComponent()) |
| break; |
| } |
| } |
| |
| } |
| |
| |
| //Check for flash command complition... |
| if (iInPort && iOutPort && (iCurrentCommand.size() > 0) && |
| (iCurrentCommand.front().iCmd == PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_FLUSH) && |
| (iInPort->IncomingMsgQueueSize() == 0) && |
| (iOutPort->OutgoingMsgQueueSize() == 0) && |
| (iDataIn.GetRep() == NULL) && |
| (iNumOutstandingOutputBuffers == iNumOutputBuffers) && // all output buffers are with the component or outstanding |
| (iNumOutstandingInputBuffers == 0) // all input buffers were processed and returned. These 2 conditions mean the component is idle |
| ) |
| { |
| //flush command is almost completed |
| //Debug check-- all the port queues should be empty at this point. |
| OMX_ERRORTYPE err = OMX_ErrorNone; |
| OMX_STATETYPE sState = OMX_StateInvalid; |
| |
| OSCL_ASSERT(iInPort->IncomingMsgQueueSize() == 0 && iOutPort->OutgoingMsgQueueSize() == 0); |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVMFOMXEncNode-%s::Run() - Flush pending", iNodeTypeId)); |
| |
| // now, drive the state of the omx component to IDLE - wait for the callback from the component and send cmd complete from there |
| iDataIn.Unbind(); |
| iPreviousMediaData.Unbind(); // make sure nothing is holding this data |
| if ((iOutFormat == PVMF_MIME_H264_VIDEO_MP4) || (iOutFormat == PVMF_MIME_H264_VIDEO_RAW)) |
| { |
| // prepare for next start |
| iFirstNAL = true; |
| } |
| |
| // Clear the data flags |
| |
| iEndOfDataReached = false; |
| iIsEOSSentToComponent = false; |
| iIsEOSReceivedFromComponent = false; |
| |
| |
| iDoNotSendOutputBuffersDownstreamFlag = true; // stop sending output buffers downstream |
| iDoNotSaveInputBuffersFlag = true; |
| |
| |
| //Get state of OpenMAX encoder |
| err = OMX_GetState(iOMXEncoder, &sState); |
| if (err != OMX_ErrorNone) |
| { |
| //Error condition report |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXEncNode-%s::Run(): Flush pending - Can't get State of encoder!", iNodeTypeId)); |
| |
| sState = OMX_StateInvalid; |
| } |
| |
| if ((sState == OMX_StateExecuting) || (sState == OMX_StatePause)) |
| { |
| /* Change state to OMX_StateIdle from OMX_StateExecuting or OMX_StatePause. */ |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::Run(): Flush pending: Changing Component State Executing->Idle or Pause->Idle", iNodeTypeId)); |
| |
| if (iOutPort) iOutPort->ClearMsgQueues(); |
| |
| err = OMX_SendCommand(iOMXEncoder, OMX_CommandStateSet, OMX_StateIdle, NULL); |
| if (err != OMX_ErrorNone) |
| { |
| //Error condition report |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXEncNode-%s::Run(): Flush pending : Can't send StateSet command to encoder!", iNodeTypeId)); |
| |
| CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFErrInvalidState); |
| return; |
| } |
| |
| // prevent the node from sending more buffers etc. |
| // if port reconfiguration is in process, let the state remain one of the port config states |
| // if there is a start command, we can do it seemlessly (by continuing the port reconfig) |
| if (iProcessingState == EPVMFOMXEncNodeProcessingState_ReadyToEncode) |
| iProcessingState = EPVMFOMXEncNodeProcessingState_Stopping; |
| |
| } |
| else |
| { |
| //Error condition report |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXEncNode-%s::Run(): Flush pending : Encoder is not in the Executing or Pause state!", iNodeTypeId)); |
| |
| CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFErrInvalidState); |
| return; |
| } |
| |
| |
| } |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::Run() Out", iNodeTypeId)); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // This routine will dispatch recived commands |
| ///////////////////////////////////////////////////////////////////////////// |
| bool PVMFOMXEncNode::ProcessCommand(PVMFOMXEncNodeCommand& aCmd) |
| { |
| //normally this node will not start processing one command |
| //until the prior one is finished. However, a hi priority |
| //command such as Cancel must be able to interrupt a command |
| //in progress. |
| if (!iCurrentCommand.empty() && !aCmd.hipri()) |
| return false; |
| |
| switch (aCmd.iCmd) |
| { |
| case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_QUERYUUID: |
| DoQueryUuid(aCmd); |
| break; |
| |
| case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_QUERYINTERFACE: |
| DoQueryInterface(aCmd); |
| break; |
| |
| case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_REQUESTPORT: |
| DoRequestPort(aCmd); |
| break; |
| |
| case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_RELEASEPORT: |
| DoReleasePort(aCmd); |
| break; |
| |
| case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_INIT: |
| DoInit(aCmd); |
| break; |
| |
| case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_PREPARE: |
| DoPrepare(aCmd); |
| break; |
| |
| case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_START: |
| DoStart(aCmd); |
| break; |
| |
| case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_STOP: |
| DoStop(aCmd); |
| break; |
| |
| case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_FLUSH: |
| DoFlush(aCmd); |
| break; |
| |
| case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_PAUSE: |
| DoPause(aCmd); |
| break; |
| |
| case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_RESET: |
| DoReset(aCmd); |
| break; |
| |
| case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_CANCELCMD: |
| DoCancelCommand(aCmd); |
| break; |
| |
| case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_CANCELALL: |
| DoCancelAllCommands(aCmd); |
| break; |
| |
| case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_GETNODEMETADATAKEY: |
| { |
| PVMFStatus retval = DoGetNodeMetadataKey(aCmd); |
| CommandComplete(iInputCommands, aCmd, retval); |
| } |
| break; |
| |
| case PVMFOMXEncNodeCommand::PVOMXENC_NODE_CMD_GETNODEMETADATAVALUE: |
| { |
| PVMFStatus retval = DoGetNodeMetadataValue(aCmd); |
| CommandComplete(iInputCommands, aCmd, retval); |
| } |
| break; |
| |
| default://unknown command type |
| CommandComplete(iInputCommands, aCmd, PVMFFailure); |
| break; |
| } |
| |
| return true; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // This routine will process incomming message from the port |
| ///////////////////////////////////////////////////////////////////////////// |
| bool PVMFOMXEncNode::ProcessIncomingMsg(PVMFPortInterface* aPort) |
| { |
| //Called by the AO to process one buffer off the port's |
| //incoming data queue. This routine will dequeue and |
| //dispatch the data. |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "0x%x PVMFOMXEncNode-%s::ProcessIncomingMsg: aPort=0x%x", this, iNodeTypeId, aPort)); |
| |
| PVMFStatus status = PVMFFailure; |
| |
| |
| //#define SIMULATE_BOS |
| #ifdef SIMULATE_BOS |
| |
| if (((PVMFOMXEncPort*)aPort)->iNumFramesConsumed == 6)) |
| { |
| |
| PVMFSharedMediaCmdPtr BOSCmdPtr = PVMFMediaCmd::createMediaCmd(); |
| |
| // Set the format ID to BOS |
| BOSCmdPtr->setFormatID(PVMF_MEDIA_CMD_BOS_FORMAT_ID); |
| |
| // Set the timestamp |
| BOSCmdPtr->setTimestamp(201); |
| BOSCmdPtr->setStreamID(0); |
| |
| // Convert to media message and send it out |
| PVMFSharedMediaMsgPtr mediaMsgOut; |
| convertToPVMFMediaCmdMsg(mediaMsgOut, BOSCmdPtr); |
| |
| //store the stream id and time stamp of bos message |
| iStreamID = mediaMsgOut->getStreamID(); |
| iBOSTimestamp = mediaMsgOut->getTimestamp(); |
| |
| iInputTimestampClock.set_clock(iBOSTimestamp, 0); |
| iOMXTicksTimestamp = ConvertTimestampIntoOMXTicks(iInputTimestampClock); |
| |
| iSendBOS = true; |
| |
| #ifdef _DEBUG |
| printf("PVMFOMXEncNode-%s::ProcessIncomingMsg() SIMULATED BOS\n", iNodeTypeId); |
| #endif |
| ((PVMFOMXEncPort*)aPort)->iNumFramesConsumed++; |
| return true; |
| |
| } |
| #endif |
| //#define SIMULATE_PREMATURE_EOS |
| #ifdef SIMULATE_PREMATURE_EOS |
| if (((PVMFOMXEncPort*)aPort)->iNumFramesConsumed == 5) |
| { |
| PVMFSharedMediaCmdPtr EOSCmdPtr = PVMFMediaCmd::createMediaCmd(); |
| |
| // Set the format ID to EOS |
| EOSCmdPtr->setFormatID(PVMF_MEDIA_CMD_EOS_FORMAT_ID); |
| |
| // Set the timestamp |
| EOSCmdPtr->setTimestamp(200); |
| |
| // Convert to media message and send it out |
| PVMFSharedMediaMsgPtr mediaMsgOut; |
| convertToPVMFMediaCmdMsg(mediaMsgOut, EOSCmdPtr); |
| |
| ((PVMFOMXEncPort*)aPort)->iNumFramesConsumed++; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::ProcessIncomingMsg: SIMULATED EOS", iNodeTypeId)); |
| #ifdef _DEBUG |
| printf("PVMFOMXEncNode-%s::ProcessIncomingMsg() SIMULATED EOS\n", iNodeTypeId); |
| #endif |
| // Set EOS flag |
| iEndOfDataReached = true; |
| // Save the timestamp for the EOS cmd |
| iEndOfDataTimestamp = mediaMsgOut->getTimestamp(); |
| |
| return true; |
| } |
| |
| #endif |
| |
| |
| |
| PVMFSharedMediaMsgPtr msg; |
| |
| status = aPort->DequeueIncomingMsg(msg); |
| if (status != PVMFSuccess) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "0x%x PVMFOMXEncNode-%s::ProcessIncomingMsg: Error - DequeueIncomingMsg failed", this, iNodeTypeId)); |
| return false; |
| } |
| |
| if (msg->getFormatID() == PVMF_MEDIA_CMD_BOS_FORMAT_ID) |
| { |
| //store the stream id and time stamp of bos message |
| iStreamID = msg->getStreamID(); |
| iBOSTimestamp = msg->getTimestamp(); |
| |
| // we need to initialize the timestamp here - so that updates later on are accurate (in terms of rollover etc) |
| iInputTimestampClock.set_clock(iBOSTimestamp, 0); |
| iOMXTicksTimestamp = ConvertTimestampIntoOMXTicks(iInputTimestampClock); |
| |
| iSendBOS = true; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::ProcessIncomingMsg: Received BOS stream %d, timestamp %d", iNodeTypeId, iStreamID, iBOSTimestamp)); |
| ((PVMFOMXEncPort*)aPort)->iNumFramesConsumed++; |
| return true; |
| } |
| else if (msg->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID) |
| { |
| // Set EOS flag |
| iEndOfDataReached = true; |
| // Save the timestamp for the EOS cmd |
| iEndOfDataTimestamp = msg->getTimestamp(); |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::ProcessIncomingMsg: Received EOS", iNodeTypeId)); |
| |
| ((PVMFOMXEncPort*)aPort)->iNumFramesConsumed++; |
| return true; // do not do conversion into media data, just set the flag and leave |
| } |
| |
| convertToPVMFMediaData(iDataIn, msg); |
| |
| |
| iCurrFragNum = 0; // for new message, reset the fragment counter |
| |
| |
| ((PVMFOMXEncPort*)aPort)->iNumFramesConsumed++; |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::ProcessIncomingMsg() Received %d frames", iNodeTypeId, ((PVMFOMXEncPort*)aPort)->iNumFramesConsumed)); |
| |
| //return true if we processed an activity... |
| return true; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // This routine will process outgoing message by sending it into output the port |
| ///////////////////////////////////////////////////////////////////////////// |
| bool PVMFOMXEncNode::ProcessOutgoingMsg(PVMFPortInterface* aPort) |
| { |
| //Called by the AO to process one message off the outgoing |
| //message queue for the given port. This routine will |
| //try to send the data to the connected port. |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "0x%x PVMFOMXEncNode-%s::ProcessOutgoingMsg: aPort=0x%x", this, iNodeTypeId, aPort)); |
| |
| PVMFStatus status = aPort->Send(); |
| if (status == PVMFErrBusy) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, |
| (0, "0x%x PVMFOMXEncNode-%s::ProcessOutgoingMsg: Connected port goes into busy state", this, iNodeTypeId)); |
| } |
| |
| //Report any unexpected failure in port processing... |
| //(the InvalidState error happens when port input is suspended, |
| //so don't report it.) |
| if (status != PVMFErrBusy |
| && status != PVMFSuccess |
| && status != PVMFErrInvalidState) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "0x%x PVMFOMXEncNode-%s::ProcessOutgoingMsg: Error - ProcessPortActivity failed. port=0x%x, type=%d", |
| this, iNodeTypeId, iOutPort, PVMF_PORT_ACTIVITY_OUTGOING_MSG)); |
| ReportErrorEvent(PVMFErrPortProcessing); |
| } |
| |
| //return true if we processed an activity... |
| return (status != PVMFErrBusy); |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // This routine will process received data usign State Machine |
| ///////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PVMFOMXEncNode::HandleProcessingState() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::HandleProcessingState() In", iNodeTypeId)); |
| |
| PVMFStatus status = PVMFSuccess; |
| |
| switch (iProcessingState) |
| { |
| |
| // The FOLLOWING 4 states handle Dynamic Port Reconfiguration |
| case EPVMFOMXEncNodeProcessingState_PortReconfig: |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> Sending Port Disable Command", iNodeTypeId)); |
| |
| // port reconfiguration is required. Only one port at a time is disabled and then re-enabled after buffer resizing |
| OMX_SendCommand(iOMXEncoder, OMX_CommandPortDisable, iPortIndexForDynamicReconfig, NULL); |
| // the port will now start returning outstanding buffers |
| // set the flag to prevent output from going downstream (in case of output port being reconfigd) |
| // set the flag to prevent input from being saved and returned to component (in case of input port being reconfigd) |
| // set the state to wait for port saying it is disabled |
| if (iPortIndexForDynamicReconfig == iOutputPortIndex) |
| { |
| iDoNotSendOutputBuffersDownstreamFlag = true; |
| } |
| else if (iPortIndexForDynamicReconfig == iInputPortIndex) |
| { |
| iDoNotSaveInputBuffersFlag = true; |
| |
| } |
| iProcessingState = EPVMFOMXEncNodeProcessingState_WaitForBufferReturn; |
| |
| |
| // fall through to the next case to check if all buffers are already back |
| } |
| |
| case EPVMFOMXEncNodeProcessingState_WaitForBufferReturn: |
| { |
| // as buffers are coming back, Run may be called, wait until all buffers are back, then Free them all |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> WaitForBufferReturn ", iNodeTypeId)); |
| // check if it's output port being reconfigured |
| if (iPortIndexForDynamicReconfig == iOutputPortIndex) |
| { |
| // if all buffers have returned, free them |
| if (iNumOutstandingOutputBuffers == 0) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> all output buffers are back, free them", iNodeTypeId)); |
| if (false == iOutputBuffersFreed) |
| { |
| if (!FreeBuffersFromComponent(iOutBufMemoryPool, // allocator |
| iOutputAllocSize, // size to allocate from pool (hdr only or hdr+ buffer) |
| iNumOutputBuffers, // number of buffers |
| iOutputPortIndex, // port idx |
| false // this is not input |
| )) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> Cannot free output buffers ", iNodeTypeId)); |
| |
| SetState(EPVMFNodeError); |
| ReportErrorEvent(PVMFErrNoMemory); |
| return PVMFErrNoMemory; |
| } |
| } |
| // if the callback (that port is disabled) has not arrived yet, wait for it |
| // if it has arrived, it will set the state to PortReEnable |
| if (iProcessingState != EPVMFOMXEncNodeProcessingState_PortReEnable) |
| iProcessingState = EPVMFOMXEncNodeProcessingState_WaitForPortDisable; |
| |
| status = PVMFSuccess; // allow rescheduling of the node potentially |
| } |
| else |
| status = PVMFErrNoMemory; // must wait for buffers to come back. No point in automatic rescheduling |
| // but each buffer will reschedule the node when it comes in |
| } |
| else |
| { |
| // this is input port |
| |
| // if all buffers have returned, free them |
| if (iNumOutstandingInputBuffers == 0) |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> all input buffers are back, free them", iNodeTypeId)); |
| if (false == iInputBuffersFreed) |
| { |
| if (!FreeBuffersFromComponent(iInBufMemoryPool, // allocator |
| iInputAllocSize, // size to allocate from pool (hdr only or hdr+ buffer) |
| iNumInputBuffers, // number of buffers |
| iInputPortIndex, // port idx |
| true // this is input |
| )) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> Cannot free input buffers ", iNodeTypeId)); |
| |
| SetState(EPVMFNodeError); |
| ReportErrorEvent(PVMFErrNoMemory); |
| return PVMFErrNoMemory; |
| |
| } |
| } |
| // if the callback (that port is disabled) has not arrived yet, wait for it |
| // if it has arrived, it will set the state to PortReEnable |
| if (iProcessingState != EPVMFOMXEncNodeProcessingState_PortReEnable) |
| iProcessingState = EPVMFOMXEncNodeProcessingState_WaitForPortDisable; |
| |
| status = PVMFSuccess; // allow rescheduling of the node |
| } |
| else |
| status = PVMFErrNoMemory; // must wait for buffers to come back. No point in automatic |
| // rescheduling. Each buffer will reschedule the node |
| // when it comes in |
| } |
| |
| |
| // the state will be changed to PortReEnable once we get confirmation that Port was actually disabled |
| break; |
| } |
| |
| case EPVMFOMXEncNodeProcessingState_WaitForPortDisable: |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> wait for port disable callback", iNodeTypeId)); |
| // do nothing. Just wait for the port to become disabled (we'll get event from component, which will |
| // transition the state to PortReEnable |
| status = PVMFErrNoMemory; // prevent Rescheduling the node |
| break; |
| } |
| |
| case EPVMFOMXEncNodeProcessingState_PortReEnable: |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> Sending reenable port command", iNodeTypeId)); |
| // set the port index so that we get parameters for the proper port |
| iParamPort.nPortIndex = iPortIndexForDynamicReconfig; |
| // iParamPort.nVersion = OMX_VERSION; |
| |
| // get new parameters of the port |
| OMX_GetParameter(iOMXEncoder, OMX_IndexParamPortDefinition, &iParamPort); |
| |
| // send command for port re-enabling (for this to happen, we must first recreate the buffers) |
| OMX_SendCommand(iOMXEncoder, OMX_CommandPortEnable, iPortIndexForDynamicReconfig, NULL); |
| |
| // is this output port? |
| if (iPortIndexForDynamicReconfig == iOutputPortIndex) |
| { |
| iOMXComponentOutputBufferSize = ((iParamPort.format.video.nFrameWidth + 15) & (~15)) * ((iParamPort.format.video.nFrameHeight + 15) & (~15)) * 3 / 2; |
| |
| // check the new buffer size |
| if (iInPort) |
| { |
| if (((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H264_VIDEO || |
| ((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H264_VIDEO_MP4 || |
| ((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H264_VIDEO_RAW || |
| ((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_M4V || |
| ((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H2631998 || |
| ((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_H2632000) |
| { |
| iOMXComponentOutputBufferSize = ((iParamPort.format.video.nFrameWidth + 15) & (~15)) * ((iParamPort.format.video.nFrameHeight + 15) & (~15)) * 3 / 2; |
| } |
| else if (((PVMFOMXEncPort*)iInPort)->iFormat == PVMF_MIME_WMV) |
| { |
| // This is a requirement for the WMV encoder that we have currently |
| iOMXComponentOutputBufferSize = ((iParamPort.format.video.nFrameWidth + 3) & (~3)) * (iParamPort.format.video.nFrameHeight) * 3 / 2; |
| } |
| else |
| { |
| OSCL_ASSERT(false); |
| } |
| } |
| // set the new width / height |
| iYUVWidth = iParamPort.format.video.nFrameWidth; |
| iYUVHeight = iParamPort.format.video.nFrameHeight; |
| |
| if (iOMXComponentOutputBufferSize < iParamPort.nBufferSize) |
| iOMXComponentOutputBufferSize = iParamPort.nBufferSize; |
| |
| // do we need to increase the number of buffers? |
| if (iNumOutputBuffers < iParamPort.nBufferCountMin) |
| iNumOutputBuffers = iParamPort.nBufferCountMin; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::HandleProcessingState() new output buffers %d, size %d", iNodeTypeId, iNumOutputBuffers, iOMXComponentOutputBufferSize)); |
| |
| /* Allocate output buffers */ |
| if (!CreateOutMemPool(iNumOutputBuffers)) |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> Cannot allocate output buffers ", iNodeTypeId)); |
| |
| SetState(EPVMFNodeError); |
| ReportErrorEvent(PVMFErrNoMemory); |
| return PVMFErrNoMemory; |
| } |
| |
| if (!ProvideBuffersToComponent(iOutBufMemoryPool, // allocator |
| iOutputAllocSize, // size to allocate from pool (hdr only or hdr+ buffer) |
| iNumOutputBuffers, // number of buffers |
| iOMXComponentOutputBufferSize, // actual buffer size |
| iOutputPortIndex, // port idx |
| iOMXComponentSupportsExternalOutputBufferAlloc, // can component use OMX_UseBuffer |
| false // this is not input |
| )) |
| { |
| |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> Cannot provide output buffers to component", iNodeTypeId)); |
| |
| SetState(EPVMFNodeError); |
| ReportErrorEvent(PVMFErrNoMemory); |
| return PVMFErrNoMemory; |
| |
| } |
| |
| // do not drop output any more, i.e. enable output to be sent downstream |
| iDoNotSendOutputBuffersDownstreamFlag = false; |
| |
| |
| } |
| else |
| { |
| // this is input port |
| |
| iOMXComponentInputBufferSize = iParamPort.nBufferSize; |
| // do we need to increase the number of buffers? |
| if (iNumInputBuffers < iParamPort.nBufferCountMin) |
| iNumInputBuffers = iParamPort.nBufferCountMin; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::HandleProcessingState() new buffers %d, size %d", iNodeTypeId, iNumInputBuffers, iOMXComponentInputBufferSize)); |
| |
| /* Allocate input buffers */ |
| if (!CreateInputMemPool(iNumInputBuffers)) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> Cannot allocate new input buffers to component", iNodeTypeId)); |
| |
| SetState(EPVMFNodeError); |
| ReportErrorEvent(PVMFErrNoMemory); |
| return PVMFErrNoMemory; |
| } |
| |
| if (!ProvideBuffersToComponent(iInBufMemoryPool, // allocator |
| iInputAllocSize, // size to allocate from pool (hdr only or hdr+ buffer) |
| iNumInputBuffers, // number of buffers |
| iOMXComponentInputBufferSize, // actual buffer size |
| iInputPortIndex, // port idx |
| iOMXComponentSupportsExternalInputBufferAlloc, // can component use OMX_UseBuffer |
| true // this is input |
| )) |
| { |
| |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> Cannot provide new input buffers to component", iNodeTypeId)); |
| |
| SetState(EPVMFNodeError); |
| ReportErrorEvent(PVMFErrNoMemory); |
| return PVMFErrNoMemory; |
| |
| } |
| // do not drop partially consumed input |
| iDoNotSaveInputBuffersFlag = false; |
| |
| |
| } |
| |
| // if the callback that the port was re-enabled has not arrived yet, wait for it |
| // if it has arrived, it will set the state to either PortReconfig or to ReadyToEncode |
| if (iProcessingState != EPVMFOMXEncNodeProcessingState_PortReconfig && |
| iProcessingState != EPVMFOMXEncNodeProcessingState_ReadyToEncode) |
| iProcessingState = EPVMFOMXEncNodeProcessingState_WaitForPortEnable; |
| |
| status = PVMFSuccess; // allow rescheduling of the node |
| break; |
| } |
| |
| case EPVMFOMXEncNodeProcessingState_WaitForPortEnable: |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::HandleProcessingState() Port Reconfiguration -> wait for port enable callback", iNodeTypeId)); |
| // do nothing. Just wait for the port to become enabled (we'll get event from component, which will |
| // transition the state to ReadyToEncode |
| status = PVMFErrNoMemory; // prevent ReScheduling |
| break; |
| } |
| |
| // NORMAL DATA FLOW STATE: |
| case EPVMFOMXEncNodeProcessingState_ReadyToEncode: |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::HandleProcessingState() Ready To Encode start", iNodeTypeId)); |
| // In normal data flow and decoding state |
| // Send all available output buffers to the encoder |
| |
| while (iNumOutstandingOutputBuffers < iNumOutputBuffers) |
| { |
| // grab buffer header from the mempool if possible, and send to component |
| if (!SendOutputBufferToOMXComponent()) |
| |
| break; |
| |
| } |
| |
| |
| // next, see if partially consumed input buffer needs to be resent back to OMX component |
| // NOTE: it is not allowed that the component returns more than 1 partially consumed input buffers |
| // i.e. if a partially consumed input buffer is returned, it is assumed that the OMX component |
| // will be waiting to get data |
| |
| if (iInputBufferToResendToComponent != NULL) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, |
| (0, "PVMFOMXEncNode-%s::HandleProcessingState() Sending previous - partially consumed input back to the OMX component", iNodeTypeId)); |
| |
| OMX_EmptyThisBuffer(iOMXEncoder, iInputBufferToResendToComponent); |
| iInputBufferToResendToComponent = NULL; // do this only once |
| } |
| else if ((iNumOutstandingInputBuffers < iNumInputBuffers) && (iDataIn.GetRep() != NULL)) |
| { |
| // try to get an input buffer header |
| // and send the input data over to the component |
| SendInputBufferToOMXComponent(); |
| } |
| |
| status = PVMFSuccess; |
| break; |
| |
| |
| } |
| case EPVMFOMXEncNodeProcessingState_Stopping: |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::HandleProcessingState() Stopping -> wait for Component to move from Executing->Idle", iNodeTypeId)); |
| |
| |
| status = PVMFErrNoMemory; // prevent rescheduling |
| break; |
| } |
| |
| case EPVMFOMXEncNodeProcessingState_WaitForOutgoingQueue: |
| status = PVMFErrNoMemory; |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::HandleProcessingState() Do nothing since waiting for output port queue to become available", iNodeTypeId)); |
| break; |
| |
| default: |
| break; |
| } |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFOMXEncNode-%s::HandleProcessingState() Out", iNodeTypeId)); |
| |
| return status; |
| |
| } |
| ///////////////////////////////////////////////////////////////////////////// |
| bool PVMFOMXEncNode::SendOutputBufferToOMXComponent() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SendOutputBufferToOMXComponent() In", iNodeTypeId)); |
| |
| |
| OutputBufCtrlStruct *output_buf = NULL; |
| int32 errcode = 0; |
| uint32 ii; |
| |
| // try to get output buffer header |
| OSCL_TRY(errcode, output_buf = (OutputBufCtrlStruct *) iOutBufMemoryPool->allocate(iOutputAllocSize)); |
| if (errcode != 0) |
| { |
| if (errcode == OsclErrNoResources) |
| { |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, |
| PVLOGMSG_DEBUG, (0, "PVMFOMXEncNode-%s::SendOutputBufferToOMXComponent() No more output buffers in the mempool", iNodeTypeId)); |
| |
| iOutBufMemoryPool->notifyfreechunkavailable(*this, (OsclAny *) iOutBufMemoryPool); // To signal when next deallocate() is called on mempool |
| |
| return false; |
| } |
| else |
| { |
| // Memory allocation for the pool failed |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXEncNode-%s::SendOutputBufferToOMXComponent() Output mempool error", iNodeTypeId)); |
| |
| |
| SetState(EPVMFNodeError); |
| ReportErrorEvent(PVMFErrNoMemory); |
| return false; |
| } |
| |
| } |
| |
| //for every allocated buffer, make sure you notify when buffer is released. Keep track of allocated buffers |
| // use mempool as context to recognize which buffer (input or output) was returned |
| iOutBufMemoryPool->notifyfreechunkavailable(*this, (OsclAny *)iOutBufMemoryPool); |
| iNumOutstandingOutputBuffers++; |
| |
| for (ii = 0; ii < iNumOutputBuffers; ii++) |
| { |
| if (output_buf == out_ctrl_struct_ptr[ii]) |
| { |
| break; |
| } |
| } |
| |
| if (ii == iNumOutputBuffers) |
| return false; |
| |
| output_buf->pBufHdr = (OMX_BUFFERHEADERTYPE *)out_buff_hdr_ptr[ii]; |
| |
| |
| |
| output_buf->pBufHdr->nFilledLen = 0; // make sure you tell OMX component buffer is empty |
| output_buf->pBufHdr->nOffset = 0; |
| output_buf->pBufHdr->pAppPrivate = output_buf; // set pAppPrivate to be pointer to output_buf |
| // (this is context for future release of this buffer to the mempool) |
| // this was done during buffer creation, but still repeat just in case |
| |
| output_buf->pBufHdr->nFlags = 0; // zero out the flags |
| OMX_FillThisBuffer(iOMXEncoder, output_buf->pBufHdr); |
| |
| |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SendOutputBufferToOMXComponent() Out", iNodeTypeId)); |
| |
| return true; |
| } |
| //////////////////////////////////////////////////////////////////////////////// |
| bool PVMFOMXEncNode::NegotiateVideoComponentParameters() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoParameters() In", iNodeTypeId)); |
| |
| OMX_ERRORTYPE Err; |
| OMX_CONFIG_ROTATIONTYPE InputRotationType; |
| |
| // first get the number of ports and port indices |
| OMX_PORT_PARAM_TYPE VideoPortParameters; |
| uint32 NumPorts; |
| uint32 ii; |
| |
| // get starting number |
| CONFIG_SIZE_AND_VERSION(VideoPortParameters); |
| |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoInit, &VideoPortParameters); |
| NumPorts = VideoPortParameters.nPorts; // must be at least 2 of them (in&out) |
| |
| if (Err != OMX_ErrorNone || NumPorts < 2) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() There is insuffucient (%d) ports", iNodeTypeId, NumPorts)); |
| return false; |
| } |
| |
| |
| // loop through video ports starting from the starting index to find index of the first input port |
| for (ii = VideoPortParameters.nStartPortNumber ; ii < VideoPortParameters.nStartPortNumber + NumPorts; ii++) |
| { |
| // get port parameters, and determine if it is input or output |
| // if there are more than 2 ports, the first one we encounter that has input direction is picked |
| |
| |
| CONFIG_SIZE_AND_VERSION(iParamPort); |
| //port |
| iParamPort.nPortIndex = ii; // iInputPortIndex; //OMF_MC_H264D_PORT_INDEX_OF_STREAM; |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamPortDefinition, &iParamPort); |
| |
| if (Err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem negotiating with port %d ", iNodeTypeId, ii)); |
| |
| return false; |
| } |
| |
| if (iParamPort.eDir == OMX_DirInput) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Found Input port index %d ", iNodeTypeId, ii)); |
| |
| iInputPortIndex = ii; |
| break; |
| } |
| } |
| if (ii == VideoPortParameters.nStartPortNumber + NumPorts) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Cannot find any input port ", iNodeTypeId)); |
| return false; |
| } |
| |
| |
| // loop through video ports starting from the starting index to find index of the first output port |
| for (ii = VideoPortParameters.nStartPortNumber ; ii < VideoPortParameters.nStartPortNumber + NumPorts; ii++) |
| { |
| // get port parameters, and determine if it is input or output |
| // if there are more than 2 ports, the first one we encounter that has output direction is picked |
| |
| |
| CONFIG_SIZE_AND_VERSION(iParamPort); |
| //port |
| iParamPort.nPortIndex = ii; |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamPortDefinition, &iParamPort); |
| |
| if (Err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem negotiating with port %d ", iNodeTypeId, ii)); |
| |
| return false; |
| } |
| |
| if (iParamPort.eDir == OMX_DirOutput) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Found Output port index %d ", iNodeTypeId, ii)); |
| |
| iOutputPortIndex = ii; |
| break; |
| } |
| } |
| if (ii == VideoPortParameters.nStartPortNumber + NumPorts) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Cannot find any output port ", iNodeTypeId)); |
| return false; |
| } |
| |
| |
| |
| // now get input parameters |
| |
| |
| //INPUT PORT |
| |
| // first check if encode parameters have been set correctly |
| if ((0 == iVideoEncodeParam.iFrameWidth[0]) || |
| (0 == iVideoEncodeParam.iFrameHeight[0]) || |
| (0 == iVideoEncodeParam.iFrameRate[0]) || |
| (0 == iVideoEncodeParam.iBitRate[0]) || |
| (0 == iVideoInputFormat.iFrameWidth) || |
| (0 == iVideoInputFormat.iFrameHeight) || |
| (0 == iVideoInputFormat.iFrameRate) |
| ) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Encode parameters not set correctly", iNodeTypeId)); |
| return false; |
| } |
| |
| // first of all, check if the port supports the adequate port format |
| OMX_VIDEO_PARAM_PORTFORMATTYPE Video_port_format; |
| OMX_COLOR_FORMATTYPE DesiredPortColorFormat; |
| |
| if (iInFormat == PVMF_MIME_RGB24) |
| { |
| DesiredPortColorFormat = OMX_COLOR_Format24bitRGB888; |
| } |
| else if (iInFormat == PVMF_MIME_RGB12) |
| { |
| DesiredPortColorFormat = OMX_COLOR_Format12bitRGB444; |
| } |
| else if (iInFormat == PVMF_MIME_YUV420) |
| { |
| //TODO: get color format from MIO. JJ 03/09/09 |
| DesiredPortColorFormat = OMX_COLOR_FormatYUV420SemiPlanar; |
| //DesiredPortColorFormat = OMX_COLOR_FormatYUV420Planar; |
| } |
| else if (iInFormat == PVMF_MIME_YUV422_INTERLEAVED_UYVY) |
| { |
| DesiredPortColorFormat = OMX_COLOR_FormatCbYCrY; |
| } |
| else if (iInFormat == PVMF_MIME_YUV422_INTERLEAVED_YUYV) |
| { |
| DesiredPortColorFormat = OMX_COLOR_FormatYCbYCr; |
| } |
| else |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem with input port %d color format", iNodeTypeId, iInputPortIndex)); |
| return false; |
| } |
| |
| CONFIG_SIZE_AND_VERSION(Video_port_format); |
| |
| Video_port_format.nPortIndex = iInputPortIndex; // set input port as target |
| |
| // loop over supported formats until we hit the one we want |
| // or until the component has no more supported formats (in which case it returns OMX_ErrorNoMore |
| Err = OMX_ErrorNone; |
| Video_port_format.nIndex = 0; //init the format counter |
| while (OMX_ErrorNone == Err) |
| { |
| |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoPortFormat, &Video_port_format); |
| if ((OMX_ErrorNone != Err)) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem getting port format for input port %d or no desired port format found", iNodeTypeId, iInputPortIndex)); |
| return false; |
| } |
| |
| if ((Video_port_format.eColorFormat == DesiredPortColorFormat)) |
| break; |
| |
| Video_port_format.nIndex ++; |
| } |
| |
| // OK, we've found the desired format, set it as the one used |
| Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoPortFormat, &Video_port_format); |
| if ((OMX_ErrorNone != Err)) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem setting port format for input port %d ", iNodeTypeId, iInputPortIndex)); |
| return false; |
| } |
| |
| |
| |
| CONFIG_SIZE_AND_VERSION(iParamPort); |
| iParamPort.nPortIndex = iInputPortIndex; |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamPortDefinition, &iParamPort); |
| if (Err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem negotiating with input port %d ", iNodeTypeId, iInputPortIndex)); |
| return false; |
| } |
| |
| if (iInFormat == PVMF_MIME_RGB24) |
| { |
| iOMXComponentInputBufferSize = (iVideoInputFormat.iFrameWidth * iVideoInputFormat.iFrameHeight * 3); |
| iParamPort.format.video.eColorFormat = OMX_COLOR_Format24bitRGB888; |
| } |
| else if (iInFormat == PVMF_MIME_RGB12) |
| { |
| iOMXComponentInputBufferSize = (iVideoInputFormat.iFrameWidth * iVideoInputFormat.iFrameHeight * 2); |
| iParamPort.format.video.eColorFormat = OMX_COLOR_Format12bitRGB444; |
| } |
| else if (iInFormat == PVMF_MIME_YUV420) |
| { |
| iOMXComponentInputBufferSize = (iVideoInputFormat.iFrameWidth * iVideoInputFormat.iFrameHeight * 3) >> 1; |
| //TODO: get color format from MIO. JJ 03/09/09 |
| iParamPort.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar; |
| //iParamPort.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar; |
| } |
| else if (iInFormat == PVMF_MIME_YUV422_INTERLEAVED_UYVY) |
| { |
| iOMXComponentInputBufferSize = iVideoInputFormat.iFrameWidth * iVideoInputFormat.iFrameHeight * 2; |
| iParamPort.format.video.eColorFormat = OMX_COLOR_FormatCbYCrY; |
| } |
| else if (iInFormat == PVMF_MIME_YUV422_INTERLEAVED_YUYV) |
| { |
| iOMXComponentInputBufferSize = iVideoInputFormat.iFrameWidth * iVideoInputFormat.iFrameHeight * 2; |
| iParamPort.format.video.eColorFormat = OMX_COLOR_FormatYCbYCr; |
| } |
| else |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem with input port %d color format", iNodeTypeId, iInputPortIndex)); |
| return false; |
| } |
| |
| //The input buffer size is a read-only parameter and the encoder component needs to adjust it. |
| // We (the client) determine the size of the buffers based on width/height - |
| // the component doesn't know width/height yet |
| |
| //iParamPort.nBufferSize = iOMXComponentInputBufferSize; |
| |
| // set the width and height of video frame and input framerate |
| |
| iParamPort.format.video.nFrameWidth = iVideoInputFormat.iFrameWidth; |
| iParamPort.format.video.nFrameHeight = iVideoInputFormat.iFrameHeight; |
| // This is Q16 value, so shift by 16 first and cast to preserve accuracy |
| iParamPort.format.video.xFramerate = (uint32)(iVideoInputFormat.iFrameRate * (1 << 16)); |
| |
| // indicate that input is uncompressed so that color format is valid |
| iParamPort.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; |
| |
| |
| // let the component decide about the number of input buffers |
| iNumInputBuffers = iParamPort.nBufferCountActual; |
| |
| // do we need to increase the number of buffers? |
| if (iNumInputBuffers < iParamPort.nBufferCountMin) |
| iNumInputBuffers = iParamPort.nBufferCountMin; |
| |
| |
| /* OMX_UseBuffer, ie. if OMX client instead of OMX component is to allocate buffers, |
| * if the buffers are allocated in MIO, check MIO allocator the max number of buffers; |
| * else (the buffer is allocated by OMX client itself) floor the number of buffers to NUMBER_INPUT_BUFFER |
| * validate with OMX component whether it is ok with the number decided above. |
| * Note: the spec says in OMX_UseBuffer, the OMX client can decide number of input buffers. |
| */ |
| if(iOMXComponentSupportsExternalInputBufferAlloc) |
| { |
| ipExternalInputBufferAllocatorInterface = NULL; |
| PvmiKvp* kvp = NULL; |
| int numKvp = 0; |
| PvmiKeyType aIdentifier = (PvmiKeyType)PVMF_BUFFER_ALLOCATOR_KEY; |
| int32 err, err1; |
| OSCL_TRY(err, ((PVMFOMXEncPort*)iInPort)->pvmiGetBufferAllocatorSpecificInfoSync(aIdentifier, kvp, numKvp);); |
| |
| if ((err == OsclErrNone) && (NULL != kvp)) |
| { |
| ipExternalInputBufferAllocatorInterface = (PVInterface*) kvp->value.key_specific_value; |
| |
| if (ipExternalInputBufferAllocatorInterface) |
| { |
| PVInterface* pTempPVInterfacePtr = NULL; |
| |
| OSCL_TRY(err, ipExternalInputBufferAllocatorInterface->queryInterface(PVMFFixedSizeBufferAllocUUID, pTempPVInterfacePtr);); |
| |
| OSCL_TRY(err1, ((PVMFOMXEncPort*)iInPort)->releaseParametersSync(kvp, numKvp);); |
| OSCL_FIRST_CATCH_ANY(err1, |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, |
| (0, "PVMFOMXEncNode-%s::NegotiateComponentParameters() - Unable to Release Parameters", iNodeTypeId)); |
| ); |
| |
| if ((err == OsclErrNone) && (NULL != pTempPVInterfacePtr)) |
| { |
| ipFixedSizeBufferAlloc = OSCL_STATIC_CAST(PVMFFixedSizeBufferAlloc*, pTempPVInterfacePtr); |
| |
| uint32 iNumBuffers = ipFixedSizeBufferAlloc->getNumBuffers(); |
| uint32 iBufferSize = ipFixedSizeBufferAlloc->getBufferSize(); |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, |
| (0, "PVMFOMXEncNode-%s iNumBuffers %d iBufferSize %d iOMXComponentInputBufferSize %d iParamPort.nBufferCountMin %d", iNodeTypeId, iNumBuffers , iBufferSize , iOMXComponentInputBufferSize, iParamPort.nBufferCountMin ) ); |
| |
| //TODO should let camera decide number of buffers. |
| if ((iNumBuffers < iParamPort.nBufferCountMin) || (iBufferSize < iOMXComponentInputBufferSize )) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMFOMXEncNode-%s::NegotiateComponentParameters() - not enough buffer. Got %d x %d. Require %d x %d", iNodeTypeId, iNumBuffers , iBufferSize , iOMXComponentInputBufferSize, iParamPort.nBufferCountMin)); |
| //ipFixedSizeBufferAlloc = NULL; |
| |
| ipExternalInputBufferAllocatorInterface->removeRef(); |
| ipExternalInputBufferAllocatorInterface = NULL; |
| } |
| else |
| { |
| iNumInputBuffers = iNumBuffers; |
| iOMXComponentInputBufferSize = iBufferSize; |
| } |
| } |
| else |
| { |
| ipExternalInputBufferAllocatorInterface->removeRef(); |
| ipExternalInputBufferAllocatorInterface = NULL; |
| |
| } |
| } |
| } |
| } |
| |
| // if component allows us to allocate buffers, we'll decide how many to allocate |
| if (iOMXComponentSupportsExternalInputBufferAlloc && (iParamPort.nBufferCountMin < NUMBER_INPUT_BUFFER)) |
| { |
| if(NULL == ipFixedSizeBufferAlloc) |
| { |
| // preset the number of input buffers |
| iNumInputBuffers = NUMBER_INPUT_BUFFER; |
| } |
| } |
| |
| // set the number of input buffer |
| iParamPort.nBufferCountActual = iNumInputBuffers; |
| |
| // set the number of actual input buffers |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Inport buffers %d,size %d", iNodeTypeId, iNumInputBuffers, iOMXComponentInputBufferSize)); |
| |
| // lock in the input port parameters |
| CONFIG_SIZE_AND_VERSION(iParamPort); |
| Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamPortDefinition, &iParamPort); |
| if (Err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem setting parameters in input port %d ", iNodeTypeId, iInputPortIndex)); |
| return false; |
| } |
| |
| |
| //////////////////// OUTPUT PORT ////////////////////////////////////////////// |
| CONFIG_SIZE_AND_VERSION(Video_port_format); |
| |
| Video_port_format.nPortIndex = iOutputPortIndex; // set output port as target |
| OMX_VIDEO_CODINGTYPE DesiredPortFormat = OMX_VIDEO_CodingUnused; |
| if (iOutFormat == PVMF_MIME_M4V) |
| { |
| DesiredPortFormat = OMX_VIDEO_CodingMPEG4; |
| } |
| else if (iOutFormat == PVMF_MIME_H2631998 || |
| iOutFormat == PVMF_MIME_H2632000) |
| { |
| DesiredPortFormat = OMX_VIDEO_CodingH263; |
| } |
| else if (iOutFormat == PVMF_MIME_H264_VIDEO_RAW || |
| iOutFormat == PVMF_MIME_H264_VIDEO_MP4) |
| { |
| DesiredPortFormat = OMX_VIDEO_CodingAVC; |
| } |
| else |
| { |
| DesiredPortFormat = OMX_VIDEO_CodingUnused; |
| } |
| |
| if (DesiredPortFormat == OMX_VIDEO_CodingUnused) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem with output port %d format", iNodeTypeId, iOutputPortIndex)); |
| return false; |
| } |
| // loop over supported formats until we hit the one we want |
| // or until the component has no more supported formats (in which case it returns OMX_ErrorNoMore |
| Err = OMX_ErrorNone; |
| Video_port_format.nIndex = 0; //init the format counter |
| while (OMX_ErrorNone == Err) |
| { |
| |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoPortFormat, &Video_port_format); |
| if ((OMX_ErrorNone != Err)) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem getting port format for output port %d or no desired port format found", iNodeTypeId, iOutputPortIndex)); |
| return false; |
| } |
| |
| if ((Video_port_format.eCompressionFormat == DesiredPortFormat)) |
| break; |
| |
| Video_port_format.nIndex ++; |
| } |
| |
| // OK, we've found the desired format, set it as the one used |
| Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoPortFormat, &Video_port_format); |
| if ((OMX_ErrorNone != Err)) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem setting port format for output port %d ", iNodeTypeId, iOutputPortIndex)); |
| return false; |
| } |
| |
| |
| |
| |
| //Port 1 for output port |
| CONFIG_SIZE_AND_VERSION(iParamPort); |
| iParamPort.nPortIndex = iOutputPortIndex; |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamPortDefinition, &iParamPort); |
| if (Err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem negotiating with output port %d ", iNodeTypeId, iOutputPortIndex)); |
| return false; |
| } |
| |
| // let the component decide num output buffers |
| iNumOutputBuffers = iParamPort.nBufferCountActual; |
| |
| |
| //check the number |
| if (iNumOutputBuffers < iParamPort.nBufferCountMin) |
| iNumOutputBuffers = iParamPort.nBufferCountMin; |
| |
| |
| // set the number ourselves |
| if (iOMXComponentSupportsExternalOutputBufferAlloc && (iParamPort.nBufferCountMin < NUMBER_OUTPUT_BUFFER)) |
| { |
| iNumOutputBuffers = NUMBER_OUTPUT_BUFFER; |
| } |
| |
| iParamPort.nBufferCountActual = iNumOutputBuffers; |
| |
| |
| // set the output (target) bitrate, framerate, width/height etc. |
| iParamPort.format.video.nFrameWidth = iVideoEncodeParam.iFrameWidth[0]; |
| iParamPort.format.video.nFrameHeight = iVideoEncodeParam.iFrameHeight[0]; |
| // Q16 value, cast after the shift to preserve the accuracy. |
| iParamPort.format.video.xFramerate = (uint32)(iVideoEncodeParam.iFrameRate[0] * (1 << 16)); |
| |
| iParamPort.format.video.nBitrate = iVideoEncodeParam.iBitRate[0]; |
| iParamPort.format.video.eColorFormat = OMX_COLOR_FormatUnused; |
| |
| if (iOutFormat == PVMF_MIME_M4V) |
| { |
| iParamPort.format.video.eCompressionFormat = OMX_VIDEO_CodingMPEG4; |
| } |
| else if (iOutFormat == PVMF_MIME_H2631998 || |
| iOutFormat == PVMF_MIME_H2632000) |
| { |
| iParamPort.format.video.eCompressionFormat = OMX_VIDEO_CodingH263; |
| } |
| else if (iOutFormat == PVMF_MIME_H264_VIDEO_RAW || |
| iOutFormat == PVMF_MIME_H264_VIDEO_MP4) |
| { |
| iParamPort.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC; |
| } |
| else |
| { |
| iParamPort.format.video.eCompressionFormat = OMX_VIDEO_CodingAutoDetect; |
| } |
| |
| CONFIG_SIZE_AND_VERSION(iParamPort); |
| Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamPortDefinition, &iParamPort); |
| if (Err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem setting parameters in output port %d ", iNodeTypeId, iOutputPortIndex)); |
| return false; |
| } |
| |
| //ask for the calculated buffer size |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamPortDefinition, &iParamPort); |
| if (Err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem negotiating with output port %d ", iNodeTypeId, iOutputPortIndex)); |
| return false; |
| } |
| |
| iOMXComponentOutputBufferSize = iParamPort.nBufferSize; |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Outport buffers %d size %d", iNodeTypeId, iNumOutputBuffers, iOMXComponentOutputBufferSize)); |
| |
| CONFIG_SIZE_AND_VERSION(InputRotationType); |
| InputRotationType.nPortIndex = iInputPortIndex; |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexConfigCommonRotate, &InputRotationType); |
| if (Err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem getting OMX_IndexConfigCommonRotate param ", iNodeTypeId)); |
| } |
| |
| //Set the OMX_CONFIG_ROTATIONTYPE parameters |
| InputRotationType.nRotation = ((iVideoInputFormat.iFrameOrientation == 1) ? 180 : 0); |
| Err = OMX_SetParameter(iOMXEncoder, OMX_IndexConfigCommonRotate, &InputRotationType); |
| if (Err != OMX_ErrorNone) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::NegotiateVideoComponentParameters() Problem setting OMX_IndexConfigCommonRotate param ", iNodeTypeId)); |
| } |
| |
| |
| // now call codec specific parameter setting |
| bool status = true; |
| if (iOutFormat == PVMF_MIME_M4V) |
| { |
| status = SetMP4EncoderParameters(); |
| } |
| else if (iOutFormat == PVMF_MIME_H2631998 || |
| iOutFormat == PVMF_MIME_H2632000) |
| { |
| status = SetH263EncoderParameters(); |
| } |
| else if (iOutFormat == PVMF_MIME_H264_VIDEO_RAW || |
| iOutFormat == PVMF_MIME_H264_VIDEO_MP4) |
| { |
| status = SetH264EncoderParameters(); |
| } |
| |
| return status; |
| } |
| bool PVMFOMXEncNode::SetMP4EncoderParameters() |
| { |
| OMX_ERRORTYPE Err = OMX_ErrorNone; |
| |
| OMX_VIDEO_PARAM_MPEG4TYPE Mpeg4Type; |
| OMX_VIDEO_PARAM_BITRATETYPE BitRateType; |
| OMX_VIDEO_PARAM_QUANTIZATIONTYPE QuantParam; |
| OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE ErrCorrType; |
| |
| // DV: VALUES HERE ARE FOR THE MOST PART HARDCODED BASED ON PV DEFAULTS |
| OMX_VIDEO_PARAM_MOTIONVECTORTYPE MotionVector; |
| OMX_VIDEO_PARAM_INTRAREFRESHTYPE RefreshParam; |
| |
| |
| CONFIG_SIZE_AND_VERSION(Mpeg4Type); |
| Mpeg4Type.nPortIndex = iOutputPortIndex; |
| |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoMpeg4, &Mpeg4Type); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId)); |
| } |
| |
| |
| //Set the OMX_VIDEO_PARAM_MPEG4TYPE parameters |
| |
| Mpeg4Type.nPortIndex = iOutputPortIndex; |
| // extra parameters - hardcoded |
| Mpeg4Type.nSliceHeaderSpacing = 0; |
| Mpeg4Type.bSVH = OMX_FALSE; //((iEncoderParam.iContentType == EI_H263)? true: false); |
| Mpeg4Type.bGov = OMX_FALSE; // disable or enable GOV header |
| // extra parameters - hardcoded |
| Mpeg4Type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP; |
| |
| |
| // params based on iFrame interval |
| if (iVideoEncodeParam.iIFrameInterval == -1) // encode only one frame |
| { |
| Mpeg4Type.nPFrames = 0xFFFFFFFF; |
| } |
| else if (iVideoEncodeParam.iIFrameInterval == 0) // no P frames |
| { |
| Mpeg4Type.nPFrames = 0; |
| Mpeg4Type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI; // maps to only supporting I-frames |
| } |
| else |
| { |
| Mpeg4Type.nPFrames = (OMX_U32)(iVideoEncodeParam.iIFrameInterval * iVideoEncodeParam.iFrameRate[0] - 1); |
| } |
| |
| // extra parameters - hardcoded |
| Mpeg4Type.nBFrames = 0; |
| Mpeg4Type.nIDCVLCThreshold = 0; |
| Mpeg4Type.bACPred = OMX_TRUE; |
| Mpeg4Type.nMaxPacketSize = iVideoEncodeParam.iPacketSize; |
| Mpeg4Type.nTimeIncRes = 1000; // (in relation to (should be higher than) frame rate ) |
| Mpeg4Type.nHeaderExtension = 0; |
| Mpeg4Type.bReversibleVLC = ((iVideoEncodeParam.iRVLCEnable == true) ? OMX_TRUE : OMX_FALSE); |
| |
| switch (iVideoEncodeParam.iProfileLevel) |
| { |
| |
| case EI_SIMPLE_LEVEL0: |
| Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileSimple; |
| Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level0; |
| break; |
| |
| case EI_SIMPLE_LEVEL1: |
| Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileSimple; |
| Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level1; |
| break; |
| |
| case EI_SIMPLE_LEVEL2: |
| Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileSimple; |
| Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level2; |
| break; |
| |
| case EI_SIMPLE_LEVEL3: |
| Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileSimple; |
| Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level3; |
| break; |
| |
| case EI_CORE_LEVEL1: |
| Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileCore; |
| Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level1; |
| break; |
| |
| case EI_CORE_LEVEL2: |
| Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileCore; |
| Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level2; |
| break; |
| |
| case EI_SIMPLE_SCALABLE_LEVEL0: |
| Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileSimpleScalable; |
| Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level0; |
| break; |
| |
| case EI_SIMPLE_SCALABLE_LEVEL1: |
| Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileSimpleScalable; |
| Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level1; |
| break; |
| |
| case EI_SIMPLE_SCALABLE_LEVEL2: |
| Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileSimpleScalable; |
| Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level2; |
| break; |
| |
| case EI_CORE_SCALABLE_LEVEL1: |
| Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileCoreScalable; |
| Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level1; |
| break; |
| |
| case EI_CORE_SCALABLE_LEVEL2: |
| Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileCoreScalable; |
| Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level2; |
| break; |
| |
| case EI_CORE_SCALABLE_LEVEL3: |
| Mpeg4Type.eProfile = OMX_VIDEO_MPEG4ProfileCoreScalable; |
| Mpeg4Type.eLevel = OMX_VIDEO_MPEG4Level3; |
| break; |
| |
| } |
| |
| Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoMpeg4, &Mpeg4Type); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId)); |
| } |
| |
| //OMX_VIDEO_PARAM_BITRATETYPE Settings |
| CONFIG_SIZE_AND_VERSION(BitRateType); |
| |
| BitRateType.nPortIndex = iOutputPortIndex; |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoBitrate, &BitRateType); |
| |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId)); |
| } |
| |
| //Set the parameters now |
| BitRateType.nPortIndex = iOutputPortIndex; |
| BitRateType.eControlRate = static_cast<OMX_VIDEO_CONTROLRATETYPE>(iVideoEncodeParam.iRateControlType); |
| BitRateType.nTargetBitrate = iVideoEncodeParam.iBitRate[0]; |
| Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoBitrate, &BitRateType); |
| |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId)); |
| } |
| |
| //OMX_VIDEO_PARAM_QUANTIZATIONTYPE Settings |
| if (BitRateType.eControlRate == OMX_Video_ControlRateDisable) |
| { |
| CONFIG_SIZE_AND_VERSION(QuantParam); |
| QuantParam.nPortIndex = iOutputPortIndex; |
| |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoQuantization, &QuantParam); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId)); |
| } |
| |
| //Set the parameters now |
| QuantParam.nPortIndex = iOutputPortIndex; |
| QuantParam.nQpI = DEFAULT_OMX_MP4ENC_QPI; |
| QuantParam.nQpP = DEFAULT_OMX_MP4ENC_QPP; |
| QuantParam.nQpB = DEFAULT_OMX_MP4ENC_QPB; |
| Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoQuantization, &QuantParam); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId)); |
| } |
| } |
| |
| |
| |
| //OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE Settings (For streaming/2-way) |
| |
| CONFIG_SIZE_AND_VERSION(ErrCorrType); |
| ErrCorrType.nPortIndex = iOutputPortIndex; |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoErrorCorrection, &ErrCorrType); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId)); |
| } |
| |
| //Set the parameters now |
| ErrCorrType.nPortIndex = iOutputPortIndex; |
| ErrCorrType.bEnableDataPartitioning = ((iVideoEncodeParam.iDataPartitioning == true) ? OMX_TRUE : OMX_FALSE); |
| ErrCorrType.bEnableResync = ((iVideoEncodeParam.iResyncMarker == true) ? OMX_TRUE : OMX_FALSE); |
| |
| // extra parameters - hardcoded |
| ErrCorrType.bEnableHEC = OMX_FALSE; |
| ErrCorrType.nResynchMarkerSpacing = iVideoEncodeParam.iPacketSize; |
| ErrCorrType.bEnableRVLC = ((iVideoEncodeParam.iRVLCEnable == true) ? OMX_TRUE : OMX_FALSE); // corresponds to encode param rvlcEnable |
| |
| Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoErrorCorrection, &ErrCorrType); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId)); |
| } |
| |
| |
| //OMX_VIDEO_PARAM_MOTIONVECTORTYPE Settings |
| CONFIG_SIZE_AND_VERSION(MotionVector); |
| MotionVector.nPortIndex = iOutputPortIndex; |
| |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoMotionVector, &MotionVector); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId)); |
| } |
| |
| MotionVector.nPortIndex = iOutputPortIndex; |
| |
| // extra parameters - hardcoded |
| MotionVector.sXSearchRange = iVideoEncodeParam.iSearchRange; |
| MotionVector.sYSearchRange = iVideoEncodeParam.iSearchRange; |
| MotionVector.bFourMV = ((iVideoEncodeParam.iMV8x8 == true) ? OMX_TRUE : OMX_FALSE); |
| MotionVector.eAccuracy = ((iVideoEncodeParam.iMVHalfPel == true) ? OMX_Video_MotionVectorHalfPel : OMX_Video_MotionVectorPixel); |
| MotionVector.bUnrestrictedMVs = OMX_TRUE; |
| |
| Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoMotionVector, &MotionVector); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId)); |
| } |
| |
| |
| //OMX_VIDEO_PARAM_INTRAREFRESHTYPE Settings |
| CONFIG_SIZE_AND_VERSION(RefreshParam); |
| RefreshParam.nPortIndex = iOutputPortIndex; |
| |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoIntraRefresh, &RefreshParam); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId)); |
| } |
| |
| // extra parameters - hardcoded based on PV defaults |
| RefreshParam.nPortIndex = iOutputPortIndex; |
| RefreshParam.eRefreshMode = OMX_VIDEO_IntraRefreshBoth; |
| RefreshParam.nCirMBs = iVideoEncodeParam.iNumIntraMBRefresh; |
| |
| Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoIntraRefresh, &RefreshParam); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetMP4EncoderParameters Parameter Invalid", iNodeTypeId)); |
| } |
| |
| return true; |
| } |
| |
| bool PVMFOMXEncNode::SetH263EncoderParameters() |
| { |
| |
| OMX_ERRORTYPE Err = OMX_ErrorNone; |
| |
| OMX_VIDEO_PARAM_H263TYPE H263Type; |
| OMX_VIDEO_PARAM_BITRATETYPE BitRateType; |
| OMX_VIDEO_PARAM_QUANTIZATIONTYPE QuantParam; |
| OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE ErrCorrType; |
| |
| // DV: VALUES HERE ARE FOR THE MOST PART HARDCODED BASED ON PV DEFAULTS |
| OMX_VIDEO_PARAM_MOTIONVECTORTYPE MotionVector; |
| OMX_VIDEO_PARAM_INTRAREFRESHTYPE RefreshParam; |
| |
| |
| CONFIG_SIZE_AND_VERSION(H263Type); |
| H263Type.nPortIndex = iOutputPortIndex; |
| |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoH263, &H263Type); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_GetParameter() failed for index(0x%x)", iNodeTypeId, OMX_IndexParamVideoH263)); |
| } |
| |
| |
| //Set the OMX_VIDEO_PARAM_H263TYPE parameters |
| |
| //DV: Here, we only set the nPFrames and AllowedFrameTypes, i.e. iIFrameInterval related variables |
| |
| H263Type.nPortIndex = iOutputPortIndex; |
| |
| H263Type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP; |
| if (iVideoEncodeParam.iIFrameInterval == -1) // encode only one I frame followed by P frames |
| { |
| H263Type.nPFrames = 0xFFFFFFFF; |
| } |
| else if (iVideoEncodeParam.iIFrameInterval == 0) // no P frames |
| { |
| H263Type.nPFrames = 0; |
| H263Type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI; // maps to only supporting I-frames |
| } |
| else |
| { |
| H263Type.nPFrames = (OMX_U32)(iVideoEncodeParam.iIFrameInterval * iVideoEncodeParam.iFrameRate[0] - 1); |
| } |
| |
| // extra parameters - hardcoded |
| H263Type.nBFrames = 0; |
| H263Type.eProfile = OMX_VIDEO_H263ProfileBaseline; |
| |
| // the supported level is up to OMX_VIDEO_H263Level45 |
| if (H263Type.eLevel > OMX_VIDEO_H263Level45) |
| { |
| H263Type.eLevel = OMX_VIDEO_H263Level45; |
| } |
| H263Type.bPLUSPTYPEAllowed = OMX_FALSE; |
| H263Type.bForceRoundingTypeToZero = OMX_FALSE; |
| H263Type.nPictureHeaderRepetition = 0; |
| H263Type.nGOBHeaderInterval = 0; |
| |
| Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoH263, &H263Type); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_SetParameter() failed for index(0x%x)", iNodeTypeId, OMX_IndexParamVideoH263)); |
| } |
| |
| //OMX_VIDEO_PARAM_BITRATETYPE Settings |
| CONFIG_SIZE_AND_VERSION(BitRateType); |
| |
| BitRateType.nPortIndex = iOutputPortIndex; |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoBitrate, &BitRateType); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_GetParameter() failed for index(0x%x)", iNodeTypeId, OMX_IndexParamVideoBitrate)); |
| } |
| |
| //Set the parameters now |
| BitRateType.nPortIndex = iOutputPortIndex; |
| BitRateType.eControlRate = static_cast<OMX_VIDEO_CONTROLRATETYPE>(iVideoEncodeParam.iRateControlType); |
| BitRateType.nTargetBitrate = iVideoEncodeParam.iBitRate[0]; |
| Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoBitrate, &BitRateType); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_SetParameter() failed for index(0x%x)", iNodeTypeId, OMX_IndexParamVideoBitrate)); |
| } |
| |
| |
| //OMX_VIDEO_PARAM_QUANTIZATIONTYPE Settings |
| if (BitRateType.eControlRate == OMX_Video_ControlRateDisable) |
| { |
| CONFIG_SIZE_AND_VERSION(QuantParam); |
| QuantParam.nPortIndex = iOutputPortIndex; |
| |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoQuantization, &QuantParam); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_GetParameter() failed for index(0x%x", iNodeTypeId, OMX_IndexParamVideoQuantization)); |
| } |
| |
| //Set the parameters now |
| QuantParam.nPortIndex = iOutputPortIndex; |
| QuantParam.nQpI = DEFAULT_OMX_MP4ENC_QPI; |
| QuantParam.nQpP = DEFAULT_OMX_MP4ENC_QPP; |
| QuantParam.nQpB = DEFAULT_OMX_MP4ENC_QPB; |
| Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoQuantization, &QuantParam); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_SetParameter() failed for index(0x%x)", iNodeTypeId, OMX_IndexParamVideoQuantization)); |
| } |
| } |
| |
| |
| //OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE Settings (For streaming/2-way) |
| |
| CONFIG_SIZE_AND_VERSION(ErrCorrType); |
| ErrCorrType.nPortIndex = iOutputPortIndex; |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoErrorCorrection, &ErrCorrType); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_GetParameter() faile for index(0x%x)", iNodeTypeId, OMX_IndexParamVideoErrorCorrection)); |
| } |
| |
| //Set the parameters now |
| ErrCorrType.nPortIndex = iOutputPortIndex; |
| //if (iVideoEncodeParam.iContentType == EI_M4V_STREAMING) |
| //{ |
| // ErrCorrType.bEnableDataPartitioning = OMX_TRUE; |
| //} |
| //else |
| //{ |
| // ErrCorrType.bEnableDataPartitioning = OMX_FALSE; |
| //} |
| ErrCorrType.bEnableHEC = OMX_FALSE; |
| ErrCorrType.bEnableResync = OMX_FALSE; |
| ErrCorrType.nResynchMarkerSpacing = 0; |
| ErrCorrType.bEnableRVLC = OMX_FALSE; // corresponds to encode param rvlcEnable |
| Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoErrorCorrection, &ErrCorrType); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_SetParameter() failed for index(0x%x)", iNodeTypeId, OMX_IndexParamVideoErrorCorrection)); |
| } |
| |
| |
| |
| //OMX_VIDEO_PARAM_MOTIONVECTORTYPE Settings |
| CONFIG_SIZE_AND_VERSION(MotionVector); |
| MotionVector.nPortIndex = iOutputPortIndex; |
| |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoMotionVector, &MotionVector); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_GetParameter() failed for index(0x%x)", iNodeTypeId, OMX_IndexParamVideoMotionVector)); |
| } |
| |
| // extra parameters - hardcoded |
| MotionVector.sXSearchRange = iVideoEncodeParam.iSearchRange; |
| MotionVector.sYSearchRange = iVideoEncodeParam.iSearchRange; |
| MotionVector.bFourMV = OMX_FALSE; |
| MotionVector.eAccuracy = ((iVideoEncodeParam.iMVHalfPel == true) ? OMX_Video_MotionVectorHalfPel : OMX_Video_MotionVectorPixel); |
| MotionVector.bUnrestrictedMVs = OMX_FALSE; |
| |
| |
| Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoMotionVector, &MotionVector); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_SetParameter() failed for index(0x%x", iNodeTypeId, OMX_IndexParamVideoMotionVector)); |
| } |
| |
| |
| //OMX_VIDEO_PARAM_INTRAREFRESHTYPE Settings |
| |
| CONFIG_SIZE_AND_VERSION(RefreshParam); |
| RefreshParam.nPortIndex = iOutputPortIndex; |
| |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoIntraRefresh, &RefreshParam); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_GetParameter() failed for index(0x%x)", iNodeTypeId, OMX_IndexParamVideoIntraRefresh)); |
| } |
| |
| // extra parameters - hardcoded based on PV defaults |
| RefreshParam.nPortIndex = iOutputPortIndex; |
| RefreshParam.eRefreshMode = OMX_VIDEO_IntraRefreshBoth; |
| RefreshParam.nCirMBs = iVideoEncodeParam.iNumIntraMBRefresh; |
| |
| |
| Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoIntraRefresh, &RefreshParam); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetH263EncoderParameters OMX_SetParameter() failed for index(0x%x)", iNodeTypeId, OMX_IndexParamVideoIntraRefresh)); |
| } |
| |
| return true; |
| } |
| |
| bool PVMFOMXEncNode::SetH264EncoderParameters() |
| { |
| OMX_ERRORTYPE Err = OMX_ErrorNone; |
| |
| OMX_VIDEO_PARAM_AVCTYPE H264Type; |
| OMX_VIDEO_PARAM_BITRATETYPE BitRateType; |
| OMX_VIDEO_PARAM_QUANTIZATIONTYPE QuantParam; |
| |
| // to be refined |
| OMX_VIDEO_PARAM_MOTIONVECTORTYPE MotionVector; |
| OMX_VIDEO_PARAM_INTRAREFRESHTYPE RefreshParam; |
| OMX_VIDEO_PARAM_VBSMCTYPE VbsmcType; |
| |
| |
| CONFIG_SIZE_AND_VERSION(H264Type); |
| H264Type.nPortIndex = iOutputPortIndex; |
| |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoAvc, &H264Type); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetH264EncoderParameters Parameter Invalid", iNodeTypeId)); |
| } |
| |
| |
| H264Type.nPortIndex = iOutputPortIndex; |
| |
| H264Type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP; |
| if (iVideoEncodeParam.iIFrameInterval == -1) // encode only one I frame followed by P frames |
| { |
| H264Type.nPFrames = 0xFFFFFFFF; |
| } |
| else if (iVideoEncodeParam.iIFrameInterval == 0) // no P frames |
| { |
| H264Type.nPFrames = 0; |
| H264Type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI; // maps to only supporting I-frames |
| } |
| else |
| { |
| H264Type.nPFrames = (OMX_U32)(iVideoEncodeParam.iIFrameInterval * iVideoEncodeParam.iFrameRate[0] - 1); |
| } |
| |
| // extra parameters -hardcoded |
| H264Type.nSliceHeaderSpacing = 0; |
| H264Type.nBFrames = 0; |
| H264Type.bUseHadamard = OMX_TRUE; |
| H264Type.nRefFrames = 1; |
| H264Type.nRefIdx10ActiveMinus1 = 0; |
| H264Type.nRefIdx11ActiveMinus1 = 0; |
| H264Type.bEnableUEP = OMX_FALSE; |
| H264Type.bEnableFMO = OMX_FALSE; |
| H264Type.bEnableASO = OMX_FALSE; |
| H264Type.bEnableRS = OMX_FALSE; |
| //H264Type.eProfile = OMX_VIDEO_AVCProfileBaseline; |
| //H264Type.eLevel = OMX_VIDEO_AVCLevel1b; |
| H264Type.bFrameMBsOnly = OMX_TRUE; |
| H264Type.bMBAFF = OMX_FALSE; |
| H264Type.bEntropyCodingCABAC = OMX_FALSE; |
| H264Type.bWeightedPPrediction = OMX_FALSE; |
| H264Type.bconstIpred = OMX_FALSE; |
| H264Type.bDirect8x8Inference = OMX_FALSE; |
| H264Type.bDirectSpatialTemporal = OMX_FALSE; |
| H264Type.nCabacInitIdc = 0; |
| H264Type.eLoopFilterMode = OMX_VIDEO_AVCLoopFilterEnable; |
| |
| |
| Err = OMX_SetParameter(iOMXEncoder, OMX_IndexParamVideoAvc, &H264Type); |
| if (OMX_ErrorNone != Err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMFOMXEncNode-%s::SetH264EncoderParameters Parameter Invalid", iNodeTypeId)); |
| } |
| |
| |
| //OMX_VIDEO_PARAM_BITRATETYPE Settings |
| CONFIG_SIZE_AND_VERSION(BitRateType); |
| |
| BitRateType.nPortIndex = iOutputPortIndex; |
| Err = OMX_GetParameter(iOMXEncoder, OMX_IndexParamVideoBitrate, &BitRateType); |
| |