| /* ------------------------------------------------------------------ |
| * 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 "oscl_base.h" |
| #include "omx_types.h" |
| #include "pv_omxdefs.h" |
| #include "omx_avc_component.h" |
| |
| #if PROXY_INTERFACE |
| #include "omx_proxy_interface.h" |
| #endif |
| |
| // Use default DLL entry point |
| #ifndef OSCL_DLL_H_INCLUDED |
| #include "oscl_dll.h" |
| #endif |
| |
| OSCL_DLL_ENTRY_POINT_DEFAULT() |
| |
| // This function is called by OMX_GetHandle and it creates an instance of the avc component AO |
| OSCL_EXPORT_REF OMX_ERRORTYPE AvcOmxComponentFactory(OMX_OUT OMX_HANDLETYPE* pHandle, OMX_IN OMX_PTR pAppData, OMX_IN OMX_PTR pProxy , OMX_STRING aOmxLibName, OMX_PTR &aOmxLib, OMX_PTR aOsclUuid, OMX_U32 &aRefCount) |
| { |
| OSCL_UNUSED_ARG(aOmxLibName); |
| OSCL_UNUSED_ARG(aOmxLib); |
| OSCL_UNUSED_ARG(aOsclUuid); |
| OSCL_UNUSED_ARG(aRefCount); |
| |
| OpenmaxAvcAO* pOpenmaxAOType; |
| OMX_ERRORTYPE Status; |
| |
| // move InitAvcOmxComponentFields content to actual constructor |
| |
| pOpenmaxAOType = (OpenmaxAvcAO*) OSCL_NEW(OpenmaxAvcAO, ()); |
| |
| if (NULL == pOpenmaxAOType) |
| { |
| return OMX_ErrorInsufficientResources; |
| } |
| |
| //Call the construct component to initialize OMX types |
| Status = pOpenmaxAOType->ConstructComponent(pAppData, pProxy); |
| |
| *pHandle = pOpenmaxAOType->GetOmxHandle(); |
| |
| return Status; |
| /////////////////////////////////////////////////////////////////////////////////////// |
| } |
| |
| // This function is called by OMX_FreeHandle when component AO needs to be destroyed |
| OSCL_EXPORT_REF OMX_ERRORTYPE AvcOmxComponentDestructor(OMX_IN OMX_HANDLETYPE pHandle, OMX_PTR &aOmxLib, OMX_PTR aOsclUuid, OMX_U32 &aRefCount) |
| { |
| OSCL_UNUSED_ARG(aOmxLib); |
| OSCL_UNUSED_ARG(aOsclUuid); |
| OSCL_UNUSED_ARG(aRefCount); |
| |
| // get pointer to component AO |
| OpenmaxAvcAO* pOpenmaxAOType = (OpenmaxAvcAO*)((OMX_COMPONENTTYPE*)pHandle)->pComponentPrivate; |
| |
| // clean up decoder, OMX component stuff |
| pOpenmaxAOType->DestroyComponent(); |
| |
| // destroy the AO class |
| OSCL_DELETE(pOpenmaxAOType); |
| |
| return OMX_ErrorNone; |
| } |
| |
| #if DYNAMIC_LOAD_OMX_AVC_COMPONENT |
| class OsclSharedLibraryInterface; |
| class AvcOmxSharedLibraryInterface: public OsclSharedLibraryInterface, |
| public OmxSharedLibraryInterface |
| |
| { |
| public: |
| static AvcOmxSharedLibraryInterface *Instance() |
| { |
| static AvcOmxSharedLibraryInterface omxinterface; |
| return &omxinterface; |
| }; |
| |
| OsclAny *QueryOmxComponentInterface(const OsclUuid& aOmxTypeId, const OsclUuid& aInterfaceId) |
| { |
| if (PV_OMX_AVCDEC_UUID == aOmxTypeId) |
| { |
| if (PV_OMX_CREATE_INTERFACE == aInterfaceId) |
| { |
| return ((OsclAny*)(&AvcOmxComponentFactory)); |
| } |
| else if (PV_OMX_DESTROY_INTERFACE == aInterfaceId) |
| { |
| return ((OsclAny*)(&AvcOmxComponentDestructor)); |
| } |
| } |
| return NULL; |
| }; |
| OsclAny *SharedLibraryLookup(const OsclUuid& aInterfaceId) |
| { |
| if (aInterfaceId == PV_OMX_SHARED_INTERFACE) |
| { |
| return OSCL_STATIC_CAST(OmxSharedLibraryInterface*, this); |
| } |
| return NULL; |
| }; |
| |
| private: |
| AvcOmxSharedLibraryInterface() {}; |
| }; |
| |
| // function to obtain the interface object from the shared library |
| extern "C" |
| { |
| OSCL_EXPORT_REF OsclAny* PVGetInterface() |
| { |
| return AvcOmxSharedLibraryInterface::Instance(); |
| } |
| } |
| |
| #endif |
| |
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| OMX_ERRORTYPE OpenmaxAvcAO::ConstructComponent(OMX_PTR pAppData, OMX_PTR pProxy) |
| { |
| ComponentPortType* pInPort, *pOutPort; |
| OMX_ERRORTYPE Status; |
| |
| iNumPorts = 2; |
| iOmxComponent.nSize = sizeof(OMX_COMPONENTTYPE); |
| iOmxComponent.pComponentPrivate = (OMX_PTR) this; // pComponentPrivate points to THIS component AO class |
| ipComponentProxy = pProxy; |
| iOmxComponent.pApplicationPrivate = pAppData; // init the App data |
| |
| |
| #if PROXY_INTERFACE |
| iPVCapabilityFlags.iIsOMXComponentMultiThreaded = OMX_TRUE; |
| |
| iOmxComponent.SendCommand = OpenmaxAvcAO::BaseComponentProxySendCommand; |
| iOmxComponent.GetParameter = OpenmaxAvcAO::BaseComponentProxyGetParameter; |
| iOmxComponent.SetParameter = OpenmaxAvcAO::BaseComponentProxySetParameter; |
| iOmxComponent.GetConfig = OpenmaxAvcAO::BaseComponentProxyGetConfig; |
| iOmxComponent.SetConfig = OpenmaxAvcAO::BaseComponentProxySetConfig; |
| iOmxComponent.GetExtensionIndex = OpenmaxAvcAO::BaseComponentProxyGetExtensionIndex; |
| iOmxComponent.GetState = OpenmaxAvcAO::BaseComponentProxyGetState; |
| iOmxComponent.UseBuffer = OpenmaxAvcAO::BaseComponentProxyUseBuffer; |
| iOmxComponent.AllocateBuffer = OpenmaxAvcAO::BaseComponentProxyAllocateBuffer; |
| iOmxComponent.FreeBuffer = OpenmaxAvcAO::BaseComponentProxyFreeBuffer; |
| iOmxComponent.EmptyThisBuffer = OpenmaxAvcAO::BaseComponentProxyEmptyThisBuffer; |
| iOmxComponent.FillThisBuffer = OpenmaxAvcAO::BaseComponentProxyFillThisBuffer; |
| |
| #else |
| iPVCapabilityFlags.iIsOMXComponentMultiThreaded = OMX_FALSE; |
| |
| iOmxComponent.SendCommand = OpenmaxAvcAO::BaseComponentSendCommand; |
| iOmxComponent.GetParameter = OpenmaxAvcAO::BaseComponentGetParameter; |
| iOmxComponent.SetParameter = OpenmaxAvcAO::BaseComponentSetParameter; |
| iOmxComponent.GetConfig = OpenmaxAvcAO::BaseComponentGetConfig; |
| iOmxComponent.SetConfig = OpenmaxAvcAO::BaseComponentSetConfig; |
| iOmxComponent.GetExtensionIndex = OpenmaxAvcAO::BaseComponentGetExtensionIndex; |
| iOmxComponent.GetState = OpenmaxAvcAO::BaseComponentGetState; |
| iOmxComponent.UseBuffer = OpenmaxAvcAO::BaseComponentUseBuffer; |
| iOmxComponent.AllocateBuffer = OpenmaxAvcAO::BaseComponentAllocateBuffer; |
| iOmxComponent.FreeBuffer = OpenmaxAvcAO::BaseComponentFreeBuffer; |
| iOmxComponent.EmptyThisBuffer = OpenmaxAvcAO::BaseComponentEmptyThisBuffer; |
| iOmxComponent.FillThisBuffer = OpenmaxAvcAO::BaseComponentFillThisBuffer; |
| #endif |
| |
| iOmxComponent.SetCallbacks = OpenmaxAvcAO::BaseComponentSetCallbacks; |
| iOmxComponent.nVersion.s.nVersionMajor = SPECVERSIONMAJOR; |
| iOmxComponent.nVersion.s.nVersionMinor = SPECVERSIONMINOR; |
| iOmxComponent.nVersion.s.nRevision = SPECREVISION; |
| iOmxComponent.nVersion.s.nStep = SPECSTEP; |
| |
| // PV capability |
| iPVCapabilityFlags.iOMXComponentSupportsExternalInputBufferAlloc = OMX_TRUE; |
| iPVCapabilityFlags.iOMXComponentSupportsExternalOutputBufferAlloc = OMX_TRUE; |
| iPVCapabilityFlags.iOMXComponentSupportsMovableInputBuffers = OMX_TRUE; |
| iPVCapabilityFlags.iOMXComponentSupportsPartialFrames = OMX_TRUE; |
| iPVCapabilityFlags.iOMXComponentNeedsNALStartCode = OMX_FALSE; |
| iPVCapabilityFlags.iOMXComponentCanHandleIncompleteFrames = OMX_TRUE; |
| |
| if (ipAppPriv) |
| { |
| oscl_free(ipAppPriv); |
| ipAppPriv = NULL; |
| } |
| |
| ipAppPriv = (ComponentPrivateType*) oscl_malloc(sizeof(ComponentPrivateType)); |
| if (NULL == ipAppPriv) |
| { |
| return OMX_ErrorInsufficientResources; |
| } |
| |
| //Construct base class now |
| Status = ConstructBaseComponent(pAppData); |
| |
| if (OMX_ErrorNone != Status) |
| { |
| return Status; |
| } |
| |
| /** Domain specific section for the ports. */ |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.eDomain = OMX_PortDomainVideo; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.format.video.cMIMEType = (OMX_STRING)"video/Avc"; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.format.video.pNativeRender = 0; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.format.video.bFlagErrorConcealment = OMX_FALSE; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.format.video.eColorFormat = OMX_COLOR_FormatUnused; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.format.video.nFrameWidth = 176; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.format.video.nFrameHeight = 144; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.format.video.nBitrate = 64000; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.format.video.xFramerate = (15 << 16); |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.eDir = OMX_DirInput; |
| //Set to a default value, will change later during setparameter call |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.nBufferCountActual = NUMBER_INPUT_BUFFER_AVC; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.nBufferCountMin = 1; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.nBufferSize = INPUT_BUFFER_SIZE_AVC; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.bEnabled = OMX_TRUE; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.bPopulated = OMX_FALSE; |
| |
| |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.eDomain = OMX_PortDomainVideo; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.format.video.cMIMEType = (OMX_STRING)"raw"; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.format.video.pNativeRender = 0; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.format.video.bFlagErrorConcealment = OMX_FALSE; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.format.video.nFrameWidth = 176; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.format.video.nFrameHeight = 144; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.format.video.nBitrate = 64000; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.format.video.xFramerate = (15 << 16); |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.eDir = OMX_DirOutput; |
| //Set to a default value, will change later during setparameter call |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.nBufferCountActual = NUMBER_OUTPUT_BUFFER_AVC |
| ; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.nBufferCountMin = 1; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.nBufferSize = 176 * 144 * 3 / 2; //Don't use OUTPUT_BUFFER_SIZE_AVC, just use QCIF (as default) |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.bEnabled = OMX_TRUE; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.bPopulated = OMX_FALSE; |
| |
| //Default values for Avc video param port |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->VideoAvc.eProfile = OMX_VIDEO_AVCProfileBaseline; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->VideoAvc.eLevel = OMX_VIDEO_AVCLevel1; |
| |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->ProfileLevel.nProfileIndex = 0; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->ProfileLevel.eProfile = OMX_VIDEO_AVCProfileBaseline; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->ProfileLevel.eLevel = OMX_VIDEO_AVCLevel1; |
| |
| iPortTypesParam.nPorts = 2; |
| iPortTypesParam.nStartPortNumber = 0; |
| |
| pInPort = (ComponentPortType*) ipPorts[OMX_PORT_INPUTPORT_INDEX]; |
| pOutPort = (ComponentPortType*) ipPorts[OMX_PORT_OUTPUTPORT_INDEX]; |
| |
| pInPort->ActualNumPortFormatsSupported = 1; |
| |
| //OMX_VIDEO_PARAM_PORTFORMATTYPE INPUT PORT SETTINGS |
| //On input port for index 0 |
| SetHeader(&pInPort->VideoParam[0], sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE)); |
| pInPort->VideoParam[0].nPortIndex = 0; |
| pInPort->VideoParam[0].nIndex = 0; |
| pInPort->VideoParam[0].eCompressionFormat = OMX_VIDEO_CodingAVC; |
| pInPort->VideoParam[0].eColorFormat = OMX_COLOR_FormatUnused; |
| |
| pOutPort->ActualNumPortFormatsSupported = 1; |
| |
| //OMX_VIDEO_PARAM_PORTFORMATTYPE OUTPUT PORT SETTINGS |
| //On output port for index 0 |
| SetHeader(&pOutPort->VideoParam[0], sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE)); |
| pOutPort->VideoParam[0].nPortIndex = 1; |
| pOutPort->VideoParam[0].nIndex = 0; |
| pOutPort->VideoParam[0].eCompressionFormat = OMX_VIDEO_CodingUnused; |
| pOutPort->VideoParam[0].eColorFormat = OMX_COLOR_FormatYUV420Planar; |
| |
| iDecodeReturn = OMX_FALSE; |
| |
| if (ipAvcDec) |
| { |
| OSCL_DELETE(ipAvcDec); |
| ipAvcDec = NULL; |
| } |
| |
| ipAvcDec = OSCL_NEW(AvcDecoder_OMX, ()); |
| if (ipAvcDec == NULL) |
| { |
| return OMX_ErrorInsufficientResources; |
| } |
| |
| oscl_memset(ipAvcDec, 0, sizeof(AvcDecoder_OMX)); |
| |
| #if PROXY_INTERFACE |
| |
| ((ProxyApplication_OMX*)ipComponentProxy)->ComponentSendCommand = BaseComponentSendCommand; |
| ((ProxyApplication_OMX*)ipComponentProxy)->ComponentGetParameter = BaseComponentGetParameter; |
| ((ProxyApplication_OMX*)ipComponentProxy)->ComponentSetParameter = BaseComponentSetParameter; |
| ((ProxyApplication_OMX*)ipComponentProxy)->ComponentGetConfig = BaseComponentGetConfig; |
| ((ProxyApplication_OMX*)ipComponentProxy)->ComponentSetConfig = BaseComponentSetConfig; |
| ((ProxyApplication_OMX*)ipComponentProxy)->ComponentGetExtensionIndex = BaseComponentGetExtensionIndex; |
| ((ProxyApplication_OMX*)ipComponentProxy)->ComponentGetState = BaseComponentGetState; |
| ((ProxyApplication_OMX*)ipComponentProxy)->ComponentUseBuffer = BaseComponentUseBuffer; |
| ((ProxyApplication_OMX*)ipComponentProxy)->ComponentAllocateBuffer = BaseComponentAllocateBuffer; |
| ((ProxyApplication_OMX*)ipComponentProxy)->ComponentFreeBuffer = BaseComponentFreeBuffer; |
| ((ProxyApplication_OMX*)ipComponentProxy)->ComponentEmptyThisBuffer = BaseComponentEmptyThisBuffer; |
| ((ProxyApplication_OMX*)ipComponentProxy)->ComponentFillThisBuffer = BaseComponentFillThisBuffer; |
| |
| #endif |
| |
| return OMX_ErrorNone; |
| } |
| |
| |
| /** This function is called by the omx core when the component |
| * is disposed by the IL client with a call to FreeHandle(). |
| * \param Component, the component to be disposed |
| */ |
| |
| OMX_ERRORTYPE OpenmaxAvcAO::DestroyComponent() |
| { |
| if (iIsInit != OMX_FALSE) |
| { |
| ComponentDeInit(); |
| } |
| |
| //Destroy the base class now |
| DestroyBaseComponent(); |
| |
| if (ipAvcDec) |
| { |
| OSCL_DELETE(ipAvcDec); |
| ipAvcDec = NULL; |
| } |
| |
| if (ipAppPriv) |
| { |
| ipAppPriv->CompHandle = NULL; |
| |
| oscl_free(ipAppPriv); |
| ipAppPriv = NULL; |
| } |
| |
| return OMX_ErrorNone; |
| } |
| |
| |
| /* This function will be called in case of buffer management without marker bit present |
| * The purpose is to copy the current input buffer into a big temporary buffer, so that |
| * an incomplete/partial frame is never passed to the decoder library for decode |
| */ |
| void OpenmaxAvcAO::ComponentBufferMgmtWithoutMarker() |
| { |
| //This common routine has been written in the base class |
| TempInputBufferMgmtWithoutMarker(); |
| } |
| |
| |
| |
| void OpenmaxAvcAO::ProcessData() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : ProcessData IN")); |
| if (!iEndOfFrameFlag) |
| { |
| DecodeWithoutMarker(); |
| } |
| else |
| { |
| DecodeWithMarker(); |
| } |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : ProcessData OUT")); |
| } |
| |
| |
| /* Decoding function for input buffers without end of frame flag marked */ |
| void OpenmaxAvcAO::DecodeWithoutMarker() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : DecodeWithoutMarker IN")); |
| |
| QueueType* pInputQueue = ipPorts[OMX_PORT_INPUTPORT_INDEX]->pBufferQueue; |
| QueueType* pOutputQueue = ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->pBufferQueue; |
| ComponentPortType* pOutPort = ipPorts[OMX_PORT_OUTPUTPORT_INDEX]; |
| OMX_COMPONENTTYPE * pHandle = &iOmxComponent; |
| |
| OMX_U8* pOutBuffer; |
| OMX_U32 OutputLength; |
| OMX_U8* pTempInBuffer; |
| OMX_U32 TempInLength; |
| OMX_BOOL MarkerFlag = OMX_FALSE; |
| OMX_TICKS TempTimestamp; |
| OMX_BOOL ResizeNeeded = OMX_FALSE; |
| |
| OMX_U32 TempInputBufferSize = (2 * sizeof(uint8) * (ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.nBufferSize)); |
| OMX_U32 CurrWidth = ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.format.video.nFrameWidth; |
| OMX_U32 CurrHeight = ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.format.video.nFrameHeight; |
| |
| |
| if ((!iIsInputBufferEnded) || ((iEndofStream) || (0 != iTempInputBufferLength))) |
| { |
| //Check whether prev output bufer has been released or not |
| if (OMX_TRUE == iNewOutBufRequired) |
| { |
| //Check whether a new output buffer is available or not |
| if (0 == (GetQueueNumElem(pOutputQueue))) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : DecodeWithoutMarker OUT output buffer unavailable")); |
| //Store the mark data for output buffer, as it will be overwritten next time |
| if (NULL != ipTargetComponent) |
| { |
| ipTempTargetComponent = ipTargetComponent; |
| iTempTargetMarkData = iTargetMarkData; |
| iMarkPropagate = OMX_TRUE; |
| } |
| return; |
| } |
| |
| ipOutputBuffer = (OMX_BUFFERHEADERTYPE*) DeQueue(pOutputQueue); |
| if (NULL == ipOutputBuffer) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : DecodeWithoutMarker Error, output buffer dequeue returned NULL, OUT")); |
| return; |
| } |
| |
| //Do not proceed if the output buffer can't fit the YUV data |
| if (ipOutputBuffer->nAllocLen < (OMX_U32)(((CurrWidth + 15)&(~15)) * ((CurrHeight + 15)&(~15)) * 3 / 2)) |
| { |
| ipOutputBuffer->nFilledLen = 0; |
| ReturnOutputBuffer(ipOutputBuffer, pOutPort); |
| ipOutputBuffer = NULL; |
| return; |
| } |
| ipOutputBuffer->nFilledLen = 0; |
| iNewOutBufRequired = OMX_FALSE; |
| } |
| |
| |
| /* Code for the marking buffer. Takes care of the OMX_CommandMarkBuffer |
| * command and hMarkTargetComponent as given by the specifications |
| */ |
| if (NULL != ipMark) |
| { |
| ipOutputBuffer->hMarkTargetComponent = ipMark->hMarkTargetComponent; |
| ipOutputBuffer->pMarkData = ipMark->pMarkData; |
| ipMark = NULL; |
| } |
| |
| if ((OMX_TRUE == iMarkPropagate) && (ipTempTargetComponent != ipTargetComponent)) |
| { |
| ipOutputBuffer->hMarkTargetComponent = ipTempTargetComponent; |
| ipOutputBuffer->pMarkData = iTempTargetMarkData; |
| ipTempTargetComponent = NULL; |
| iMarkPropagate = OMX_FALSE; |
| } |
| else if (ipTargetComponent != NULL) |
| { |
| ipOutputBuffer->hMarkTargetComponent = ipTargetComponent; |
| ipOutputBuffer->pMarkData = iTargetMarkData; |
| ipTargetComponent = NULL; |
| iMarkPropagate = OMX_FALSE; |
| } |
| //Mark buffer code ends here |
| |
| pOutBuffer = ipOutputBuffer->pBuffer; |
| OutputLength = 0; |
| |
| pTempInBuffer = ipTempInputBuffer + iTempConsumedLength; |
| TempInLength = iTempInputBufferLength; |
| |
| //Output buffer is passed as a short pointer |
| iDecodeReturn = ipAvcDec->AvcDecodeVideo_OMX(pOutBuffer, (OMX_U32*) & OutputLength, |
| &(pTempInBuffer), |
| &TempInLength, |
| &(ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam), |
| &iFrameCount, |
| MarkerFlag, &TempTimestamp, &ResizeNeeded); |
| |
| ipOutputBuffer->nFilledLen = OutputLength; |
| |
| //offset not required in our case, set it to zero |
| ipOutputBuffer->nOffset = 0; |
| |
| //Set the timestamp equal to the input buffer timestamp |
| ipOutputBuffer->nTimeStamp = iFrameTimestamp; |
| |
| iTempConsumedLength += (iTempInputBufferLength - TempInLength); |
| iTempInputBufferLength = TempInLength; |
| |
| //If decoder returned error, report it to the client via a callback |
| if (!iDecodeReturn && OMX_FALSE == iEndofStream) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : DecodeWithoutMarker ErrorStreamCorrupt callback send")); |
| |
| (*(ipCallbacks->EventHandler)) |
| (pHandle, |
| iCallbackData, |
| OMX_EventError, |
| OMX_ErrorStreamCorrupt, |
| 0, |
| NULL); |
| } |
| |
| |
| //Do not decode if big buffer is less than half the size |
| if (TempInLength < (TempInputBufferSize >> 1)) |
| { |
| iIsInputBufferEnded = OMX_TRUE; |
| iNewInBufferRequired = OMX_TRUE; |
| } |
| |
| if (ResizeNeeded == OMX_TRUE) |
| { |
| OMX_COMPONENTTYPE* pHandle = (OMX_COMPONENTTYPE*) ipAppPriv->CompHandle; |
| |
| iResizePending = OMX_TRUE; |
| (*(ipCallbacks->EventHandler)) |
| (pHandle, |
| iCallbackData, |
| OMX_EventPortSettingsChanged, //The command was completed |
| OMX_PORT_OUTPUTPORT_INDEX, |
| 0, |
| NULL); |
| } |
| |
| /* If EOS flag has come from the client & there are no more |
| * input buffers to decode, send the callback to the client |
| */ |
| if (OMX_TRUE == iEndofStream) |
| { |
| if ((0 == iTempInputBufferLength) && !iDecodeReturn) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : DecodeWithoutMarker EOS callback send")); |
| |
| (*(ipCallbacks->EventHandler)) |
| (pHandle, |
| iCallbackData, |
| OMX_EventBufferFlag, |
| 1, |
| OMX_BUFFERFLAG_EOS, |
| NULL); |
| |
| iNewInBufferRequired = OMX_TRUE; |
| iEndofStream = OMX_FALSE; |
| |
| ipOutputBuffer->nFlags |= OMX_BUFFERFLAG_EOS; |
| |
| ReturnOutputBuffer(ipOutputBuffer, pOutPort); |
| ipOutputBuffer = NULL; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : DecodeWithoutMarker OUT")); |
| |
| return; |
| } |
| } |
| |
| //Send the output buffer back when it has some data in it |
| if (ipOutputBuffer->nFilledLen > 0) |
| { |
| ReturnOutputBuffer(ipOutputBuffer, pOutPort); |
| ipOutputBuffer = NULL; |
| } |
| |
| /* If there is some more processing left with current buffers, re-schedule the AO |
| * Do not go for more than one round of processing at a time. |
| * This may block the AO longer than required. |
| */ |
| if ((ResizeNeeded == OMX_FALSE) && ((TempInLength != 0) || (GetQueueNumElem(pInputQueue) > 0)) |
| && ((GetQueueNumElem(pOutputQueue) > 0) || (OMX_FALSE == iNewOutBufRequired))) |
| { |
| RunIfNotReady(); |
| } |
| } |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : DecodeWithoutMarker OUT")); |
| return; |
| } |
| |
| |
| /* Decoding function for input buffers with end of frame flag marked */ |
| void OpenmaxAvcAO::DecodeWithMarker() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : DecodeWithMarker IN")); |
| |
| OMX_COMPONENTTYPE *pHandle = &iOmxComponent; |
| QueueType* pInputQueue = ipPorts[OMX_PORT_INPUTPORT_INDEX]->pBufferQueue; |
| QueueType* pOutputQueue = ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->pBufferQueue; |
| |
| ComponentPortType* pInPort = ipPorts[OMX_PORT_INPUTPORT_INDEX]; |
| ComponentPortType* pOutPort = ipPorts[OMX_PORT_OUTPUTPORT_INDEX]; |
| |
| OMX_U8* pOutBuffer; |
| OMX_U32 OutputLength; |
| OMX_BOOL MarkerFlag = OMX_TRUE; |
| OMX_BOOL Status; |
| OMX_BOOL ResizeNeeded = OMX_FALSE; |
| |
| OMX_U32 CurrWidth = ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.format.video.nFrameWidth; |
| OMX_U32 CurrHeight = ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.format.video.nFrameHeight; |
| |
| if ((!iIsInputBufferEnded) || (iEndofStream)) |
| { |
| //Check whether prev output bufer has been released or not |
| if (OMX_TRUE == iNewOutBufRequired) |
| { |
| //Check whether a new output buffer is available or not |
| if (0 == (GetQueueNumElem(pOutputQueue))) |
| { |
| iNewInBufferRequired = OMX_FALSE; |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : DecodeWithMarker OUT output buffer unavailable")); |
| return; |
| } |
| |
| ipOutputBuffer = (OMX_BUFFERHEADERTYPE*) DeQueue(pOutputQueue); |
| if (NULL == ipOutputBuffer) |
| { |
| iNewInBufferRequired = OMX_FALSE; |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : DecodeWithMarker Error, output buffer dequeue returned NULL, OUT")); |
| return; |
| } |
| |
| //Do not proceed if the output buffer can't fit the YUV data |
| if (ipOutputBuffer->nAllocLen < (OMX_U32)(((CurrWidth + 15)&(~15)) * ((CurrHeight + 15)&(~15)) * 3 / 2)) |
| { |
| ipOutputBuffer->nFilledLen = 0; |
| ReturnOutputBuffer(ipOutputBuffer, pOutPort); |
| ipOutputBuffer = NULL; |
| return; |
| } |
| ipOutputBuffer->nFilledLen = 0; |
| iNewOutBufRequired = OMX_FALSE; |
| } |
| |
| /* Code for the marking buffer. Takes care of the OMX_CommandMarkBuffer |
| * command and hMarkTargetComponent as given by the specifications |
| */ |
| if (NULL != ipMark) |
| { |
| ipOutputBuffer->hMarkTargetComponent = ipMark->hMarkTargetComponent; |
| ipOutputBuffer->pMarkData = ipMark->pMarkData; |
| ipMark = NULL; |
| } |
| |
| if (NULL != ipTargetComponent) |
| { |
| ipOutputBuffer->hMarkTargetComponent = ipTargetComponent; |
| ipOutputBuffer->pMarkData = iTargetMarkData; |
| ipTargetComponent = NULL; |
| |
| } |
| //Mark buffer code ends here |
| |
| pOutBuffer = ipOutputBuffer->pBuffer; |
| OutputLength = 0; |
| |
| if (iInputCurrLength > 0) |
| { |
| //Store the input timestamp into a temp variable |
| ipAvcDec->CurrInputTimestamp = iFrameTimestamp; |
| |
| //Output buffer is passed as a short pointer |
| iDecodeReturn = ipAvcDec->AvcDecodeVideo_OMX(pOutBuffer, (OMX_U32*) & OutputLength, |
| &(ipFrameDecodeBuffer), |
| &(iInputCurrLength), |
| &(ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam), |
| &iFrameCount, |
| MarkerFlag, |
| &(ipOutputBuffer->nTimeStamp), &ResizeNeeded); |
| |
| ipOutputBuffer->nFilledLen = OutputLength; |
| //offset not required in our case, set it to zero |
| ipOutputBuffer->nOffset = 0; |
| |
| if (ResizeNeeded == OMX_TRUE) |
| { |
| OMX_COMPONENTTYPE* pHandle = (OMX_COMPONENTTYPE*) ipAppPriv->CompHandle; |
| |
| // set the flag. Do not process any more frames until |
| // IL Client sends PortDisable event (thus starting the procedure for |
| // dynamic port reconfiguration) |
| iResizePending = OMX_TRUE; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : Sending the PortSettings Changed Callback")); |
| |
| (*(ipCallbacks->EventHandler)) |
| (pHandle, |
| iCallbackData, |
| OMX_EventPortSettingsChanged, //The command was completed |
| OMX_PORT_OUTPUTPORT_INDEX, |
| 0, |
| NULL); |
| } |
| |
| |
| //If decoder returned error, report it to the client via a callback |
| if (!iDecodeReturn && OMX_FALSE == iEndofStream) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : DecodeWithMarker ErrorStreamCorrupt callback send")); |
| |
| (*(ipCallbacks->EventHandler)) |
| (pHandle, |
| iCallbackData, |
| OMX_EventError, |
| OMX_ErrorStreamCorrupt, |
| 0, |
| NULL); |
| } |
| |
| |
| if (0 == iInputCurrLength) |
| { |
| ipInputBuffer->nFilledLen = 0; |
| ReturnInputBuffer(ipInputBuffer, pInPort); |
| iNewInBufferRequired = OMX_TRUE; |
| iIsInputBufferEnded = OMX_TRUE; |
| ipInputBuffer = NULL; |
| } |
| else |
| { |
| iNewInBufferRequired = OMX_FALSE; |
| } |
| } |
| else if (iEndofStream == OMX_FALSE) |
| { |
| // it's possible that after partial frame assembly, the input buffer still remains empty (due to |
| // client erroneously sending such buffers). This may cause error in processing/returning buffers |
| // This code adds robustness in the sense that it returns such buffer to the client |
| |
| ipInputBuffer->nFilledLen = 0; |
| ReturnInputBuffer(ipInputBuffer, pInPort); |
| ipInputBuffer = NULL; |
| iNewInBufferRequired = OMX_TRUE; |
| iIsInputBufferEnded = OMX_TRUE; |
| } |
| |
| |
| /* If EOS flag has come from the client & there are no more |
| * input buffers to decode, send the callback to the client*/ |
| if (OMX_TRUE == iEndofStream) |
| { |
| if (!iDecodeReturn) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : DecodeWithMarker EOS callback send")); |
| |
| (*(ipCallbacks->EventHandler)) |
| (pHandle, |
| iCallbackData, |
| OMX_EventBufferFlag, |
| 1, |
| OMX_BUFFERFLAG_EOS, |
| NULL); |
| |
| iNewInBufferRequired = OMX_TRUE; |
| iEndofStream = OMX_FALSE; |
| |
| ipOutputBuffer->nFlags |= OMX_BUFFERFLAG_EOS; |
| ReturnOutputBuffer(ipOutputBuffer, pOutPort); |
| ipOutputBuffer = NULL; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : DecodeWithMarker OUT")); |
| |
| return; |
| } |
| else if (iDecodeReturn) |
| { |
| Status = ipAvcDec->FlushOutput_OMX(pOutBuffer, &OutputLength, &(ipOutputBuffer->nTimeStamp), pOutPort->PortParam.format.video.nFrameWidth, pOutPort->PortParam.format.video.nFrameHeight); |
| ipOutputBuffer->nFilledLen = OutputLength; |
| |
| ipOutputBuffer->nOffset = 0; |
| |
| if (OMX_FALSE != Status) |
| { |
| ReturnOutputBuffer(ipOutputBuffer, pOutPort); |
| ipOutputBuffer = NULL; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : DecodeWithMarker OUT")); |
| RunIfNotReady(); |
| return; |
| } |
| else |
| { |
| iDecodeReturn = OMX_FALSE; |
| RunIfNotReady(); |
| } |
| } |
| } |
| |
| //Send the output buffer back when it has some data in it |
| if (ipOutputBuffer->nFilledLen > 0) |
| { |
| ReturnOutputBuffer(ipOutputBuffer, pOutPort); |
| ipOutputBuffer = NULL; |
| } |
| |
| |
| /* If there is some more processing left with current buffers, re-schedule the AO |
| * Do not go for more than one round of processing at a time. |
| * This may block the AO longer than required. |
| */ |
| if ((ResizeNeeded == OMX_FALSE) && ((iInputCurrLength != 0) || (GetQueueNumElem(pInputQueue) > 0)) |
| && ((GetQueueNumElem(pOutputQueue) > 0) || (OMX_FALSE == iNewOutBufRequired))) |
| { |
| RunIfNotReady(); |
| } |
| } |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : DecodeWithMarker OUT")); |
| return; |
| } |
| |
| |
| void OpenmaxAvcAO::ComponentGetRolesOfComponent(OMX_STRING* aRoleString) |
| { |
| *aRoleString = (OMX_STRING)"video_decoder.avc"; |
| } |
| |
| |
| |
| //Component object constructor |
| OpenmaxAvcAO::OpenmaxAvcAO() |
| { |
| ipAvcDec = NULL; |
| |
| if (!IsAdded()) |
| { |
| AddToScheduler(); |
| } |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : constructed")); |
| } |
| |
| |
| //Component object destructor |
| OpenmaxAvcAO::~OpenmaxAvcAO() |
| { |
| if (IsAdded()) |
| { |
| RemoveFromScheduler(); |
| } |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : destructed")); |
| } |
| |
| |
| /** The Initialization function |
| */ |
| OMX_ERRORTYPE OpenmaxAvcAO::ComponentInit() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : ComponentInit IN")); |
| |
| OMX_ERRORTYPE Status = OMX_ErrorNone; |
| |
| if (OMX_TRUE == iIsInit) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : ComponentInit error incorrect operation")); |
| return OMX_ErrorIncorrectStateOperation; |
| } |
| iIsInit = OMX_TRUE; |
| |
| //avc lib init |
| if (!iCodecReady) |
| { |
| Status = ipAvcDec->AvcDecInit_OMX(); |
| iCodecReady = OMX_TRUE; |
| } |
| |
| iInputCurrLength = 0; |
| //Used in dynamic port reconfiguration |
| iFrameCount = 0; |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : ComponentInit OUT")); |
| |
| return Status; |
| |
| } |
| |
| /** This function is called upon a transition to the idle or invalid state. |
| * Also it is called by the AvcComponentDestructor() function |
| */ |
| OMX_ERRORTYPE OpenmaxAvcAO::ComponentDeInit() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : ComponentDeInit IN")); |
| |
| OMX_ERRORTYPE Status = OMX_ErrorNone; |
| |
| iIsInit = OMX_FALSE; |
| |
| if (iCodecReady) |
| { |
| Status = ipAvcDec->AvcDecDeinit_OMX(); |
| iCodecReady = OMX_FALSE; |
| } |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAvcAO : ComponentDeInit OUT")); |
| |
| return Status; |
| |
| } |
| |
| |
| OMX_ERRORTYPE OpenmaxAvcAO::GetConfig( |
| OMX_IN OMX_HANDLETYPE hComponent, |
| OMX_IN OMX_INDEXTYPE nIndex, |
| OMX_INOUT OMX_PTR pComponentConfigStructure) |
| { |
| OSCL_UNUSED_ARG(hComponent); |
| OSCL_UNUSED_ARG(nIndex); |
| OSCL_UNUSED_ARG(pComponentConfigStructure); |
| return OMX_ErrorNotImplemented; |
| } |
| |
| /* This routine will reset the decoder library and some of the associated flags*/ |
| void OpenmaxAvcAO::ResetComponent() |
| { |
| // reset decoder |
| if (ipAvcDec) |
| { |
| ipAvcDec->ResetDecoder(); |
| } |
| |
| } |