| /* ------------------------------------------------------------------ |
| * 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 "pv_omxdefs.h" |
| #include "omx_amr_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 |
| |
| #define OMX_HALFRANGE_THRESHOLD 0x7FFFFFFF |
| /**** The duration of one output AMR frame (in ms) is fixed and equal to 20ms - needed for timestamp updates ****/ |
| /**** Note that AMR sampling rate is always 8khz, so a frame of 20 ms always corresponds to 160 (16-bit) samples = 320 bytes */ |
| #define OMX_AMR_DEC_FRAME_INTERVAL 20 |
| |
| OSCL_DLL_ENTRY_POINT_DEFAULT() |
| |
| // This function is called by OMX_GetHandle and it creates an instance of the amr component AO |
| OSCL_EXPORT_REF OMX_ERRORTYPE AmrOmxComponentFactory(OMX_OUT OMX_HANDLETYPE* pHandle, OMX_IN OMX_PTR pAppData, 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); |
| |
| OpenmaxAmrAO* pOpenmaxAOType; |
| OMX_ERRORTYPE Status; |
| |
| // move InitAmrOmxComponentFields content to actual constructor |
| |
| pOpenmaxAOType = (OpenmaxAmrAO*) OSCL_NEW(OpenmaxAmrAO, ()); |
| |
| 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 AmrOmxComponentDestructor(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 |
| OpenmaxAmrAO* pOpenmaxAOType = (OpenmaxAmrAO*)((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_AMR_COMPONENT |
| class AmrOmxSharedLibraryInterface: public OsclSharedLibraryInterface, |
| public OmxSharedLibraryInterface |
| |
| { |
| public: |
| static AmrOmxSharedLibraryInterface *Instance() |
| { |
| static AmrOmxSharedLibraryInterface amromxinterface; |
| return &amromxinterface; |
| }; |
| |
| OsclAny *QueryOmxComponentInterface(const OsclUuid& aOmxTypeId, const OsclUuid& aInterfaceId) |
| { |
| if (PV_OMX_AMRDEC_UUID == aOmxTypeId) |
| { |
| if (PV_OMX_CREATE_INTERFACE == aInterfaceId) |
| { |
| return ((OsclAny*)(&AmrOmxComponentFactory)); |
| } |
| else if (PV_OMX_DESTROY_INTERFACE == aInterfaceId) |
| { |
| return ((OsclAny*)(&AmrOmxComponentDestructor)); |
| } |
| } |
| return NULL; |
| }; |
| OsclAny *SharedLibraryLookup(const OsclUuid& aInterfaceId) |
| { |
| if (aInterfaceId == PV_OMX_SHARED_INTERFACE) |
| { |
| return OSCL_STATIC_CAST(OmxSharedLibraryInterface*, this); |
| } |
| return NULL; |
| }; |
| private: |
| AmrOmxSharedLibraryInterface() {}; |
| }; |
| |
| // function to obtain the interface object from the shared library |
| extern "C" |
| { |
| OSCL_EXPORT_REF OsclAny* PVGetInterface() |
| { |
| return AmrOmxSharedLibraryInterface::Instance(); |
| } |
| } |
| |
| #endif |
| |
| ////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| OMX_ERRORTYPE OpenmaxAmrAO::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 = OpenmaxAmrAO::BaseComponentProxySendCommand; |
| iOmxComponent.GetParameter = OpenmaxAmrAO::BaseComponentProxyGetParameter; |
| iOmxComponent.SetParameter = OpenmaxAmrAO::BaseComponentProxySetParameter; |
| iOmxComponent.GetConfig = OpenmaxAmrAO::BaseComponentProxyGetConfig; |
| iOmxComponent.SetConfig = OpenmaxAmrAO::BaseComponentProxySetConfig; |
| iOmxComponent.GetExtensionIndex = OpenmaxAmrAO::BaseComponentProxyGetExtensionIndex; |
| iOmxComponent.GetState = OpenmaxAmrAO::BaseComponentProxyGetState; |
| iOmxComponent.UseBuffer = OpenmaxAmrAO::BaseComponentProxyUseBuffer; |
| iOmxComponent.AllocateBuffer = OpenmaxAmrAO::BaseComponentProxyAllocateBuffer; |
| iOmxComponent.FreeBuffer = OpenmaxAmrAO::BaseComponentProxyFreeBuffer; |
| iOmxComponent.EmptyThisBuffer = OpenmaxAmrAO::BaseComponentProxyEmptyThisBuffer; |
| iOmxComponent.FillThisBuffer = OpenmaxAmrAO::BaseComponentProxyFillThisBuffer; |
| |
| #else |
| iPVCapabilityFlags.iIsOMXComponentMultiThreaded = OMX_FALSE; |
| |
| iOmxComponent.SendCommand = OpenmaxAmrAO::BaseComponentSendCommand; |
| iOmxComponent.GetParameter = OpenmaxAmrAO::BaseComponentGetParameter; |
| iOmxComponent.SetParameter = OpenmaxAmrAO::BaseComponentSetParameter; |
| iOmxComponent.GetConfig = OpenmaxAmrAO::BaseComponentGetConfig; |
| iOmxComponent.SetConfig = OpenmaxAmrAO::BaseComponentSetConfig; |
| iOmxComponent.GetExtensionIndex = OpenmaxAmrAO::BaseComponentGetExtensionIndex; |
| iOmxComponent.GetState = OpenmaxAmrAO::BaseComponentGetState; |
| iOmxComponent.UseBuffer = OpenmaxAmrAO::BaseComponentUseBuffer; |
| iOmxComponent.AllocateBuffer = OpenmaxAmrAO::BaseComponentAllocateBuffer; |
| iOmxComponent.FreeBuffer = OpenmaxAmrAO::BaseComponentFreeBuffer; |
| iOmxComponent.EmptyThisBuffer = OpenmaxAmrAO::BaseComponentEmptyThisBuffer; |
| iOmxComponent.FillThisBuffer = OpenmaxAmrAO::BaseComponentFillThisBuffer; |
| #endif |
| |
| iOmxComponent.SetCallbacks = OpenmaxAmrAO::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.iOMXComponentUsesNALStartCodes = OMX_FALSE; |
| iPVCapabilityFlags.iOMXComponentCanHandleIncompleteFrames = OMX_TRUE; |
| iPVCapabilityFlags.iOMXComponentUsesFullAVCFrames = OMX_FALSE; |
| |
| 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.nPortIndex = OMX_PORT_INPUTPORT_INDEX; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.eDomain = OMX_PortDomainAudio; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.format.audio.cMIMEType = (OMX_STRING)"audio/mpeg"; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.format.audio.pNativeRender = 0; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.format.audio.bFlagErrorConcealment = OMX_FALSE; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.format.audio.eEncoding = OMX_AUDIO_CodingAMR; |
| 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_AMR; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.nBufferCountMin = 1; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.nBufferSize = INPUT_BUFFER_SIZE_AMR; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.bEnabled = OMX_TRUE; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.bPopulated = OMX_FALSE; |
| |
| |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.nPortIndex = OMX_PORT_OUTPUTPORT_INDEX; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.eDomain = OMX_PortDomainAudio; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.format.audio.cMIMEType = (OMX_STRING)"raw"; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.format.audio.pNativeRender = 0; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.format.audio.bFlagErrorConcealment = OMX_FALSE; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.format.audio.eEncoding = OMX_AUDIO_CodingPCM; |
| 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_AMR; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.nBufferCountMin = 1; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.nBufferSize = OUTPUT_BUFFER_SIZE_AMR * 6; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.bEnabled = OMX_TRUE; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->PortParam.bPopulated = OMX_FALSE; |
| |
| //Default values for AMR audio param port |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->AudioAmrParam.nPortIndex = OMX_PORT_INPUTPORT_INDEX; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->AudioAmrParam.nChannels = 1; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->AudioAmrParam.nBitRate = 0; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->AudioAmrParam.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->AudioAmrParam.eAMRDTXMode = OMX_AUDIO_AMRDTXModeOnVAD1; |
| ipPorts[OMX_PORT_INPUTPORT_INDEX]->AudioAmrParam.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatConformance; |
| |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->AudioPcmMode.nPortIndex = OMX_PORT_OUTPUTPORT_INDEX; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->AudioPcmMode.nChannels = 1; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->AudioPcmMode.eNumData = OMX_NumericalDataSigned; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->AudioPcmMode.bInterleaved = OMX_TRUE; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->AudioPcmMode.nBitPerSample = 16; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->AudioPcmMode.nSamplingRate = 8000; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->AudioPcmMode.ePCMMode = OMX_AUDIO_PCMModeLinear; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->AudioPcmMode.eChannelMapping[0] = OMX_AUDIO_ChannelLF; |
| ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->AudioPcmMode.eChannelMapping[1] = OMX_AUDIO_ChannelRF; |
| |
| iPortTypesParam.nPorts = 2; |
| iPortTypesParam.nStartPortNumber = 0; |
| |
| pInPort = (ComponentPortType*) ipPorts[OMX_PORT_INPUTPORT_INDEX]; |
| pOutPort = (ComponentPortType*) ipPorts[OMX_PORT_OUTPUTPORT_INDEX]; |
| |
| SetHeader(&pInPort->AudioParam, sizeof(OMX_AUDIO_PARAM_PORTFORMATTYPE)); |
| pInPort->AudioParam.nPortIndex = 0; |
| pInPort->AudioParam.nIndex = 0; |
| pInPort->AudioParam.eEncoding = OMX_AUDIO_CodingAMR; |
| |
| SetHeader(&pOutPort->AudioParam, sizeof(OMX_AUDIO_PARAM_PORTFORMATTYPE)); |
| pOutPort->AudioParam.nPortIndex = 1; |
| pOutPort->AudioParam.nIndex = 0; |
| pOutPort->AudioParam.eEncoding = OMX_AUDIO_CodingPCM; |
| |
| iInputBufferRemainingBytes = 0; |
| |
| if (ipAmrDec) |
| { |
| OSCL_DELETE(ipAmrDec); |
| ipAmrDec = NULL; |
| } |
| |
| ipAmrDec = OSCL_NEW(OmxAmrDecoder, ()); |
| if (NULL == ipAmrDec) |
| { |
| return OMX_ErrorInsufficientResources; |
| } |
| |
| //Commented memset here as some default values are set in the constructor |
| //oscl_memset(ipAmrDec, 0, sizeof (OmxAmrDecoder)); |
| |
| #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 OpenmaxAmrAO::DestroyComponent() |
| { |
| if (iIsInit != OMX_FALSE) |
| { |
| ComponentDeInit(); |
| } |
| |
| //Destroy the base class now |
| DestroyBaseComponent(); |
| |
| if (ipAmrDec) |
| { |
| OSCL_DELETE(ipAmrDec); |
| ipAmrDec = NULL; |
| } |
| |
| if (ipAppPriv) |
| { |
| ipAppPriv->CompHandle = NULL; |
| |
| oscl_free(ipAppPriv); |
| ipAppPriv = NULL; |
| } |
| |
| return OMX_ErrorNone; |
| } |
| |
| |
| /* This routine will extract the input timestamp, verify whether silence insertion |
| * is required or not and also handle the various tasks associated with repositioning */ |
| void OpenmaxAmrAO::SyncWithInputTimestamp() |
| { |
| //Do not check for silence insertion if the clip is repositioned |
| if (OMX_FALSE == iRepositionFlag) |
| { |
| CheckForSilenceInsertion(); |
| } |
| |
| |
| /* Set the current timestamp equal to input buffer timestamp in case of |
| * a) All input frames |
| * b) First frame after repositioning */ |
| if (OMX_FALSE == iSilenceInsertionInProgress || OMX_TRUE == iRepositionFlag) |
| { |
| iCurrentTimestamp = iFrameTimestamp; |
| |
| //Reset the flag back to false, once timestamp has been updated from input frame |
| if (OMX_TRUE == iRepositionFlag) |
| { |
| iRepositionFlag = OMX_FALSE; |
| } |
| } |
| } |
| |
| |
| /* Reset the decoder library in case of repositioning or flush command or |
| * state transition (Executing ->Idle) */ |
| void OpenmaxAmrAO::ResetComponent() |
| { |
| // reset decoder |
| if (ipAmrDec) |
| { |
| ipAmrDec->ResetDecoder(); |
| } |
| } |
| |
| /* A component specific routine called from BufferMgmtWithoutMarker */ |
| void OpenmaxAmrAO::ProcessInBufferFlag() |
| { |
| /* Used in timestamp calculation |
| * Since we copy one buffer in advance, so let the first buffer finish up |
| * before applying 2nd buffers timestamp into the output timestamp */ |
| if (iInputBufferRemainingBytes <= 0) |
| { |
| if (0 == iFrameCount) |
| { |
| iPreviousFrameLength = ipInputBuffer->nFilledLen; |
| iCurrentTimestamp = iFrameTimestamp; |
| } |
| |
| iInputBufferRemainingBytes += iPreviousFrameLength; |
| } |
| |
| iPreviousFrameLength = ipInputBuffer->nFilledLen; |
| } |
| |
| |
| /* 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 OpenmaxAmrAO::ComponentBufferMgmtWithoutMarker() |
| { |
| //This common routine has been written in the base class |
| TempInputBufferMgmtWithoutMarker(); |
| } |
| |
| |
| void OpenmaxAmrAO::ProcessData() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : ProcessData IN")); |
| if (!iEndOfFrameFlag) |
| { |
| DecodeWithoutMarker(); |
| } |
| else |
| { |
| DecodeWithMarker(); |
| } |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : ProcessData OUT")); |
| } |
| |
| |
| void OpenmaxAmrAO::DecodeWithoutMarker() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : 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 ResizeNeeded = OMX_FALSE; |
| OMX_BOOL DecodeReturn = OMX_FALSE; |
| |
| OMX_U32 TempInputBufferSize = (2 * sizeof(uint8) * (ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.nBufferSize)); |
| |
| |
| 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))) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : 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, "OpenmaxAmrAO : DecodeWithoutMarker Error, Output Buffer Dequeue returned NULL, OUT")); |
| return; |
| } |
| ipOutputBuffer->nFilledLen = 0; |
| iNewOutBufRequired = OMX_FALSE; |
| |
| //Set the current timestamp to the output buffer timestamp |
| ipOutputBuffer->nTimeStamp = iCurrentTimestamp; |
| |
| // Copy the output buffer that was stored locally before dynamic port reconfiguration |
| // in the new omx buffer received. |
| if (OMX_TRUE == iSendOutBufferAfterPortReconfigFlag) |
| { |
| if ((ipTempOutBufferForPortReconfig) |
| && (iSizeOutBufferForPortReconfig <= ipOutputBuffer->nAllocLen)) |
| { |
| oscl_memcpy(ipOutputBuffer->pBuffer, ipTempOutBufferForPortReconfig, iSizeOutBufferForPortReconfig); |
| ipOutputBuffer->nFilledLen = iSizeOutBufferForPortReconfig; |
| ipOutputBuffer->nTimeStamp = iTimestampOutBufferForPortReconfig; |
| } |
| |
| iSendOutBufferAfterPortReconfigFlag = OMX_FALSE; |
| |
| //Send the output buffer back only when it has become full |
| if ((ipOutputBuffer->nAllocLen - ipOutputBuffer->nFilledLen) < iOutputFrameLength) |
| { |
| ReturnOutputBuffer(ipOutputBuffer, pOutPort); |
| } |
| |
| //Free the temp output buffer |
| if (ipTempOutBufferForPortReconfig) |
| { |
| oscl_free(ipTempOutBufferForPortReconfig); |
| ipTempOutBufferForPortReconfig = NULL; |
| iSizeOutBufferForPortReconfig = 0; |
| } |
| |
| //Dequeue new output buffer if required to continue decoding the next frame |
| if (OMX_TRUE == iNewOutBufRequired) |
| { |
| if (0 == (GetQueueNumElem(pOutputQueue))) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : DecodeWithoutMarker OUT output buffer unavailable")); |
| return; |
| } |
| |
| ipOutputBuffer = (OMX_BUFFERHEADERTYPE*) DeQueue(pOutputQueue); |
| if (NULL == ipOutputBuffer) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : DecodeWithoutMarker Error, Output Buffer Dequeue returned NULL, OUT")); |
| return; |
| } |
| |
| ipOutputBuffer->nFilledLen = 0; |
| iNewOutBufRequired = OMX_FALSE; |
| |
| ipOutputBuffer->nTimeStamp = iCurrentTimestamp; |
| } |
| } |
| } |
| |
| /* Code for the marking buffer. Takes care of the OMX_CommandMarkBuffer |
| * command and hMarkTargetComponent as given by the specifications |
| */ |
| if (ipMark != NULL) |
| { |
| 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 |
| |
| if (iTempInputBufferLength > 0) |
| { |
| pOutBuffer = &ipOutputBuffer->pBuffer[ipOutputBuffer->nFilledLen]; |
| OutputLength = 0; |
| |
| pTempInBuffer = ipTempInputBuffer + iTempConsumedLength; |
| TempInLength = iTempInputBufferLength; |
| |
| //Output buffer is passed as a short pointer |
| DecodeReturn = ipAmrDec->AmrDecodeFrame((OMX_S16*) pOutBuffer, |
| (OMX_U32*) & OutputLength, |
| &(pTempInBuffer), |
| &TempInLength, |
| &iFrameCount, |
| &ResizeNeeded); |
| |
| |
| //If decoder returned error, report it to the client via a callback |
| if (OMX_FALSE == DecodeReturn && OMX_FALSE == iEndofStream) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : DecodeWithoutMarker ErrorStreamCorrupt callback send")); |
| |
| (*(ipCallbacks->EventHandler)) |
| (pHandle, |
| iCallbackData, |
| OMX_EventError, |
| OMX_ErrorStreamCorrupt, |
| 0, |
| NULL); |
| } |
| |
| if (ResizeNeeded == OMX_TRUE) |
| { |
| if (0 != OutputLength) |
| { |
| iOutputFrameLength = OutputLength; |
| } |
| |
| iResizePending = OMX_TRUE; |
| |
| /* Do not return the output buffer generated yet, store it locally |
| * and wait for the dynamic port reconfig to complete */ |
| if ((NULL == ipTempOutBufferForPortReconfig)) |
| { |
| ipTempOutBufferForPortReconfig = (OMX_U8*) oscl_malloc(sizeof(uint8) * OutputLength); |
| if (NULL == ipTempOutBufferForPortReconfig) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : DecodeWithoutMarker error, insufficient resources")); |
| return; |
| } |
| } |
| |
| //Copy the omx output buffer to the temporary internal buffer |
| oscl_memcpy(ipTempOutBufferForPortReconfig, pOutBuffer, OutputLength); |
| iSizeOutBufferForPortReconfig = OutputLength; |
| |
| iTimestampOutBufferForPortReconfig = iCurrentTimestamp; |
| |
| iCurrentTimestamp += OMX_AMR_DEC_FRAME_INTERVAL; |
| //Make this length 0 so that no output buffer is returned by the component |
| OutputLength = 0; |
| |
| // send port settings changed event |
| OMX_COMPONENTTYPE* pHandle = (OMX_COMPONENTTYPE*) ipAppPriv->CompHandle; |
| |
| (*(ipCallbacks->EventHandler)) |
| (pHandle, |
| iCallbackData, |
| OMX_EventPortSettingsChanged, //The command was completed |
| OMX_PORT_OUTPUTPORT_INDEX, |
| 0, |
| NULL); |
| |
| } |
| |
| ipOutputBuffer->nFilledLen += OutputLength; |
| |
| //offset not required in our case, set it to zero |
| ipOutputBuffer->nOffset = 0; |
| |
| if (OutputLength > 0) |
| { |
| iCurrentTimestamp += OMX_AMR_DEC_FRAME_INTERVAL; |
| } |
| |
| iTempConsumedLength += (iTempInputBufferLength - TempInLength); |
| iInputBufferRemainingBytes -= (iTempInputBufferLength - TempInLength); |
| |
| iTempInputBufferLength = TempInLength; |
| |
| if (iInputBufferRemainingBytes <= 0) |
| { |
| iCurrentTimestamp = iFrameTimestamp; |
| } |
| |
| //Do not decode if big buffer is less than half the size |
| if (TempInLength < (TempInputBufferSize >> 1)) |
| { |
| iIsInputBufferEnded = OMX_TRUE; |
| iNewInBufferRequired = 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 ((0 == iTempInputBufferLength) || (OMX_FALSE == DecodeReturn)) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : 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, "OpenmaxAmrAO : DecodeWithoutMarker OUT")); |
| |
| return; |
| } |
| } |
| |
| //Send the output buffer back after decode |
| if ((ipOutputBuffer->nAllocLen - ipOutputBuffer->nFilledLen) < (iOutputFrameLength)) |
| { |
| 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 ((iTempInputBufferLength != 0 || GetQueueNumElem(pInputQueue) > 0) |
| && (GetQueueNumElem(pOutputQueue) > 0) && (ResizeNeeded == OMX_FALSE)) |
| |
| { |
| RunIfNotReady(); |
| } |
| } |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : DecodeWithoutMarker OUT")); |
| return; |
| } |
| |
| |
| void OpenmaxAmrAO::DecodeWithMarker() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : DecodeWithMarker IN")); |
| |
| 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 DecodeReturn = OMX_FALSE; |
| OMX_COMPONENTTYPE* pHandle = &iOmxComponent; |
| OMX_BOOL ResizeNeeded = OMX_FALSE; |
| |
| if ((!iIsInputBufferEnded) || (iEndofStream)) |
| { |
| if (OMX_TRUE == iSilenceInsertionInProgress) |
| { |
| DoSilenceInsertion(); |
| //If the flag is still true, come back to this routine again |
| if (OMX_TRUE == iSilenceInsertionInProgress) |
| { |
| return; |
| } |
| } |
| |
| //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, "OpenmaxAmrAO : DecodeWithMarker OUT output buffer unavailable")); |
| return; |
| } |
| |
| ipOutputBuffer = (OMX_BUFFERHEADERTYPE*) DeQueue(pOutputQueue); |
| if (NULL == ipOutputBuffer) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : DecodeWithMarker Error, Output Buffer Dequeue returned NULL, OUT")); |
| return; |
| } |
| |
| ipOutputBuffer->nFilledLen = 0; |
| iNewOutBufRequired = OMX_FALSE; |
| |
| //Set the current timestamp to the output buffer timestamp |
| ipOutputBuffer->nTimeStamp = iCurrentTimestamp; |
| |
| // Copy the output buffer that was stored locally before dynamic port reconfiguration |
| // in the new omx buffer received. |
| if (OMX_TRUE == iSendOutBufferAfterPortReconfigFlag) |
| { |
| if ((ipTempOutBufferForPortReconfig) |
| && (iSizeOutBufferForPortReconfig <= ipOutputBuffer->nAllocLen)) |
| { |
| oscl_memcpy(ipOutputBuffer->pBuffer, ipTempOutBufferForPortReconfig, iSizeOutBufferForPortReconfig); |
| ipOutputBuffer->nFilledLen = iSizeOutBufferForPortReconfig; |
| ipOutputBuffer->nTimeStamp = iTimestampOutBufferForPortReconfig; |
| } |
| |
| iSendOutBufferAfterPortReconfigFlag = OMX_FALSE; |
| |
| //Send the output buffer back only when it has become full |
| if ((ipOutputBuffer->nAllocLen - ipOutputBuffer->nFilledLen) < iOutputFrameLength) |
| { |
| ReturnOutputBuffer(ipOutputBuffer, pOutPort); |
| } |
| |
| //Free the temp output buffer |
| if (ipTempOutBufferForPortReconfig) |
| { |
| oscl_free(ipTempOutBufferForPortReconfig); |
| ipTempOutBufferForPortReconfig = NULL; |
| iSizeOutBufferForPortReconfig = 0; |
| } |
| |
| //Dequeue new output buffer if required to continue decoding the next frame |
| if (OMX_TRUE == iNewOutBufRequired) |
| { |
| if (0 == (GetQueueNumElem(pOutputQueue))) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO :DecodeWithMarker OUT output buffer unavailable")); |
| return; |
| } |
| |
| ipOutputBuffer = (OMX_BUFFERHEADERTYPE*) DeQueue(pOutputQueue); |
| if (NULL == ipOutputBuffer) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : DecodeWithMarker Error, Output Buffer Dequeue returned NULL, OUT")); |
| return; |
| } |
| |
| ipOutputBuffer->nFilledLen = 0; |
| iNewOutBufRequired = OMX_FALSE; |
| |
| ipOutputBuffer->nTimeStamp = iCurrentTimestamp; |
| } |
| } |
| } |
| |
| /* Code for the marking buffer. Takes care of the OMX_CommandMarkBuffer |
| * command and hMarkTargetComponent as given by the specifications |
| */ |
| if (ipMark != NULL) |
| { |
| ipOutputBuffer->hMarkTargetComponent = ipMark->hMarkTargetComponent; |
| ipOutputBuffer->pMarkData = ipMark->pMarkData; |
| ipMark = NULL; |
| } |
| |
| if (ipTargetComponent != NULL) |
| { |
| ipOutputBuffer->hMarkTargetComponent = ipTargetComponent; |
| ipOutputBuffer->pMarkData = iTargetMarkData; |
| ipTargetComponent = NULL; |
| |
| } |
| //Mark buffer code ends here |
| |
| if (iInputCurrLength > 0) |
| { |
| pOutBuffer = &ipOutputBuffer->pBuffer[ipOutputBuffer->nFilledLen]; |
| OutputLength = 0; |
| |
| //Output buffer is passed as a short pointer |
| DecodeReturn = ipAmrDec->AmrDecodeFrame((OMX_S16*)pOutBuffer, |
| (OMX_U32*) & OutputLength, |
| &(ipFrameDecodeBuffer), |
| &(iInputCurrLength), |
| &iFrameCount, |
| &ResizeNeeded); |
| |
| //If decoder returned error, report it to the client via a callback |
| if ((OMX_FALSE == DecodeReturn) && (OMX_FALSE == iEndofStream)) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : DecodeWithMarker ErrorStreamCorrupt callback send")); |
| |
| (*(ipCallbacks->EventHandler)) |
| (pHandle, |
| iCallbackData, |
| OMX_EventError, |
| OMX_ErrorStreamCorrupt, |
| 0, |
| NULL); |
| } |
| |
| if (ResizeNeeded == OMX_TRUE) |
| { |
| if (0 != OutputLength) |
| { |
| iOutputFrameLength = OutputLength; |
| |
| } |
| |
| iResizePending = OMX_TRUE; |
| |
| /* Do not return the output buffer generated yet, store it locally |
| * and wait for the dynamic port reconfig to complete */ |
| if ((NULL == ipTempOutBufferForPortReconfig)) |
| { |
| ipTempOutBufferForPortReconfig = (OMX_U8*) oscl_malloc(sizeof(uint8) * OutputLength); |
| if (NULL == ipTempOutBufferForPortReconfig) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : DecodeWithMarker error, insufficient resources")); |
| return; |
| } |
| } |
| |
| //Copy the omx output buffer to the temporary internal buffer |
| oscl_memcpy(ipTempOutBufferForPortReconfig, pOutBuffer, OutputLength); |
| iSizeOutBufferForPortReconfig = OutputLength; |
| |
| iTimestampOutBufferForPortReconfig = iCurrentTimestamp; |
| |
| iCurrentTimestamp += OMX_AMR_DEC_FRAME_INTERVAL; |
| //Make this length 0 so that no output buffer is returned by the component |
| OutputLength = 0; |
| |
| |
| // send port settings changed event |
| OMX_COMPONENTTYPE* pHandle = (OMX_COMPONENTTYPE*) ipAppPriv->CompHandle; |
| |
| // set the flag to disable further processing until Client reacts to this |
| // by doing dynamic port reconfiguration |
| |
| (*(ipCallbacks->EventHandler)) |
| (pHandle, |
| iCallbackData, |
| OMX_EventPortSettingsChanged, //The command was completed |
| OMX_PORT_OUTPUTPORT_INDEX, |
| 0, |
| NULL); |
| |
| } |
| |
| ipOutputBuffer->nFilledLen += OutputLength; |
| if (OutputLength > 0) |
| { |
| iCurrentTimestamp += OMX_AMR_DEC_FRAME_INTERVAL; |
| } |
| //offset not required in our case, set it to zero |
| ipOutputBuffer->nOffset = 0; |
| |
| |
| /* Return the input buffer it has been consumed fully or decoder returned error*/ |
| if ((iInputCurrLength == 0) || (OMX_FALSE == DecodeReturn)) |
| { |
| ipInputBuffer->nFilledLen = 0; |
| ReturnInputBuffer(ipInputBuffer, pInPort); |
| iNewInBufferRequired = OMX_TRUE; |
| iIsInputBufferEnded = OMX_TRUE; |
| iInputCurrLength = 0; |
| ipInputBuffer = NULL; |
| } |
| else |
| { |
| iNewInBufferRequired = OMX_FALSE; |
| iIsInputBufferEnded = OMX_FALSE; |
| } |
| } |
| |
| |
| /* 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 == iInputCurrLength) || (OMX_FALSE == DecodeReturn)) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : DecodeWithMarker EOS callback send")); |
| |
| (*(ipCallbacks->EventHandler)) |
| (pHandle, |
| iCallbackData, |
| OMX_EventBufferFlag, |
| 1, |
| OMX_BUFFERFLAG_EOS, |
| NULL); |
| |
| iNewInBufferRequired = OMX_TRUE; |
| //Mark this flag false once the callback has been send back |
| iEndofStream = OMX_FALSE; |
| |
| ipOutputBuffer->nFlags |= OMX_BUFFERFLAG_EOS; |
| ReturnOutputBuffer(ipOutputBuffer, pOutPort); |
| ipOutputBuffer = NULL; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : DecodeWithMarker OUT")); |
| return; |
| } |
| |
| } |
| |
| //Send the output buffer back when it has become full |
| if ((ipOutputBuffer->nAllocLen - ipOutputBuffer->nFilledLen) < (iOutputFrameLength)) |
| { |
| 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 ((iInputCurrLength != 0 || GetQueueNumElem(pInputQueue) > 0) |
| && (GetQueueNumElem(pOutputQueue) > 0) && (ResizeNeeded == OMX_FALSE)) |
| { |
| RunIfNotReady(); |
| } |
| } |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : DecodeWithMarker OUT")); |
| return; |
| } |
| |
| |
| |
| //Not implemented & supported in case of base profile components |
| |
| void OpenmaxAmrAO::ComponentGetRolesOfComponent(OMX_STRING* aRoleString) |
| { |
| *aRoleString = (OMX_STRING)"audio_decoder.amr"; |
| } |
| |
| |
| //Component constructor |
| OpenmaxAmrAO::OpenmaxAmrAO() |
| { |
| ipAmrDec = NULL; |
| |
| if (!IsAdded()) |
| { |
| AddToScheduler(); |
| } |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : constructed")); |
| } |
| |
| |
| //Active object destructor |
| OpenmaxAmrAO::~OpenmaxAmrAO() |
| { |
| if (IsAdded()) |
| { |
| RemoveFromScheduler(); |
| } |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : destructed")); |
| } |
| |
| |
| /** The Initialization function |
| */ |
| OMX_ERRORTYPE OpenmaxAmrAO::ComponentInit() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : ComponentInit IN")); |
| |
| OMX_BOOL Status = OMX_TRUE; |
| |
| if (OMX_TRUE == iIsInit) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : ComponentInit error incorrect operation")); |
| return OMX_ErrorIncorrectStateOperation; |
| } |
| iIsInit = OMX_TRUE; |
| |
| |
| // Added an extra check based on whether client has set nb or wb as Role in |
| // SetParameter() for index OMX_IndexParamStandardComponentRole |
| OMX_AUDIO_AMRBANDMODETYPE AmrBandMode = ipPorts[OMX_PORT_INPUTPORT_INDEX]->AudioAmrParam.eAMRBandMode; |
| if ((OMX_TRUE == iComponentRoleFlag) && (0 == oscl_strcmp((OMX_STRING)iComponentRole, (OMX_STRING)"audio_decoder.amrnb"))) |
| { |
| if ((AmrBandMode < OMX_AUDIO_AMRBandModeNB0) || (AmrBandMode > OMX_AUDIO_AMRBandModeNB7)) |
| { |
| //Narrow band component does not support these band modes |
| return OMX_ErrorInvalidComponent; |
| } |
| } |
| else if ((OMX_TRUE == iComponentRoleFlag) && (0 == oscl_strcmp((OMX_STRING)iComponentRole, (OMX_STRING)"audio_decoder.amrwb"))) |
| { |
| if ((AmrBandMode < OMX_AUDIO_AMRBandModeWB0) || (AmrBandMode > OMX_AUDIO_AMRBandModeWB8)) |
| { |
| //Wide band component does not support these band modes |
| return OMX_ErrorInvalidComponent; |
| } |
| } |
| |
| //amr lib init |
| if (!iCodecReady) |
| { |
| Status = ipAmrDec->AmrDecInit(ipPorts[OMX_PORT_INPUTPORT_INDEX]->AudioAmrParam.eAMRFrameFormat, ipPorts[OMX_PORT_INPUTPORT_INDEX]->AudioAmrParam.eAMRBandMode); |
| iCodecReady = OMX_TRUE; |
| } |
| |
| //ipAmrDec->iAmrInitFlag = 0; |
| iInputCurrLength = 0; |
| //Used in dynamic port reconfiguration |
| iFrameCount = 0; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : ComponentInit OUT")); |
| |
| if (OMX_TRUE == Status) |
| { |
| return OMX_ErrorNone; |
| } |
| else |
| { |
| return OMX_ErrorInvalidComponent; |
| } |
| } |
| |
| |
| |
| /** This function is called upon a transition to the idle or invalid state. |
| * Also it is called by the ComponentDestructor() function |
| */ |
| OMX_ERRORTYPE OpenmaxAmrAO::ComponentDeInit() |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : ComponentDeInit IN")); |
| |
| iIsInit = OMX_FALSE; |
| |
| if (iCodecReady) |
| { |
| ipAmrDec->AmrDecDeinit(); |
| iCodecReady = OMX_FALSE; |
| } |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : ComponentDeInit OUT")); |
| |
| return OMX_ErrorNone; |
| |
| } |
| |
| |
| //Check whether silence insertion is required here or not |
| void OpenmaxAmrAO::CheckForSilenceInsertion() |
| { |
| OMX_TICKS TimestampGap; |
| //Set the flag to false by default |
| iSilenceInsertionInProgress = OMX_FALSE; |
| |
| TimestampGap = iFrameTimestamp - iCurrentTimestamp; |
| |
| if ((TimestampGap > OMX_HALFRANGE_THRESHOLD) || (TimestampGap < OMX_AMR_DEC_FRAME_INTERVAL && iFrameCount > 0)) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAacAO : CheckForSilenceInsertion OUT - No need to insert silence")); |
| return; |
| } |
| |
| //Silence insertion needed, mark the flag to true |
| if (iFrameCount > 0) |
| { |
| iSilenceInsertionInProgress = OMX_TRUE; |
| //Determine the number of silence frames to insert |
| iSilenceFramesNeeded = TimestampGap / OMX_AMR_DEC_FRAME_INTERVAL; |
| iZeroFramesNeeded = 0; |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : CheckForSilenceInsertion OUT - Silence Insertion required here")); |
| } |
| |
| return; |
| } |
| |
| //Perform the silence insertion |
| void OpenmaxAmrAO::DoSilenceInsertion() |
| { |
| QueueType* pOutputQueue = ipPorts[OMX_PORT_OUTPUTPORT_INDEX]->pBufferQueue; |
| ComponentPortType* pOutPort = ipPorts[OMX_PORT_OUTPUTPORT_INDEX]; |
| |
| OMX_U8* pOutBuffer = NULL; |
| OMX_U32 OutputLength; |
| //OMX_BOOL ResizeNeeded = OMX_FALSE; |
| OMX_BOOL DecodeReturn; |
| |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : DoSilenceInsertion IN")); |
| |
| while (iSilenceFramesNeeded > 0) |
| { |
| //Check whether prev output bufer has been consumed or not |
| if (OMX_TRUE == iNewOutBufRequired) |
| { |
| //Check whether a new output buffer is available or not |
| if (0 == (GetQueueNumElem(pOutputQueue))) |
| { |
| //Resume Silence insertion next time when component will be called |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : DoSilenceInsertion OUT output buffer unavailable")); |
| iSilenceInsertionInProgress = OMX_TRUE; |
| return; |
| } |
| |
| ipOutputBuffer = (OMX_BUFFERHEADERTYPE*) DeQueue(pOutputQueue); |
| if (NULL == ipOutputBuffer) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : DoSilenceInsertion Error, Output Buffer Dequeue returned NULL, OUT")); |
| iSilenceInsertionInProgress = OMX_TRUE; |
| return; |
| } |
| ipOutputBuffer->nFilledLen = 0; |
| iNewOutBufRequired = OMX_FALSE; |
| |
| //Set the current timestamp to the output buffer timestamp |
| ipOutputBuffer->nTimeStamp = iCurrentTimestamp; |
| } |
| |
| pOutBuffer = &ipOutputBuffer->pBuffer[ipOutputBuffer->nFilledLen]; |
| OutputLength = 0; |
| |
| //Decode the silence frame |
| DecodeReturn = ipAmrDec->AmrDecodeSilenceFrame((OMX_S16*) pOutBuffer, |
| (OMX_U32*) & OutputLength); |
| |
| |
| if (OMX_FALSE == DecodeReturn) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : DoSilenceInsertion - Decode error of silence generation, Insert zero frames instead")); |
| iZeroFramesNeeded = iSilenceFramesNeeded; |
| iSilenceFramesNeeded = 0; |
| break; |
| } |
| |
| //Output length for a buffer of OMX_U8* will be double as that of OMX_S16* |
| ipOutputBuffer->nFilledLen += OutputLength; |
| //offset not required in our case, set it to zero |
| ipOutputBuffer->nOffset = 0; |
| |
| if (OutputLength > 0) |
| { |
| iCurrentTimestamp += OMX_AMR_DEC_FRAME_INTERVAL; |
| } |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : DoSilenceInsertion - silence frame decoded")); |
| |
| //Send the output buffer back when it has become full |
| if ((ipOutputBuffer->nAllocLen - ipOutputBuffer->nFilledLen) < iOutputFrameLength) |
| { |
| ReturnOutputBuffer(ipOutputBuffer, pOutPort); |
| ipOutputBuffer = NULL; |
| } |
| |
| // Decrement the silence frame counter |
| --iSilenceFramesNeeded; |
| } |
| |
| // THE ZERO FRAME INSERTION IS PERFORMED ONLY IF SILENCE INSERTION FAILS |
| while (iZeroFramesNeeded > 0) |
| { |
| //Check whether prev output bufer has been consumed or not |
| if (OMX_TRUE == iNewOutBufRequired) |
| { |
| //Check whether a new output buffer is available or not |
| if (0 == (GetQueueNumElem(pOutputQueue))) |
| { |
| //Resume Silence insertion next time when component will be called |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : DoSilenceInsertion OUT output buffer unavailable")); |
| iSilenceInsertionInProgress = OMX_TRUE; |
| return; |
| } |
| |
| ipOutputBuffer = (OMX_BUFFERHEADERTYPE*) DeQueue(pOutputQueue); |
| if (NULL == ipOutputBuffer) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : DoSilenceInsertion Error, Output Buffer Dequeue returned NULL, OUT")); |
| iSilenceInsertionInProgress = OMX_TRUE; |
| return; |
| } |
| ipOutputBuffer->nFilledLen = 0; |
| iNewOutBufRequired = OMX_FALSE; |
| |
| //Set the current timestamp to the output buffer timestamp |
| ipOutputBuffer->nTimeStamp = iCurrentTimestamp; |
| } |
| |
| pOutBuffer = &ipOutputBuffer->pBuffer[ipOutputBuffer->nFilledLen]; |
| oscl_memset(pOutBuffer, 0, iOutputFrameLength); |
| |
| ipOutputBuffer->nFilledLen += iOutputFrameLength; |
| ipOutputBuffer->nOffset = 0; |
| iCurrentTimestamp += OMX_AMR_DEC_FRAME_INTERVAL; |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : DoSilenceInsertion - One frame of zeros inserted")); |
| |
| //Send the output buffer back when it has become full |
| if ((ipOutputBuffer->nAllocLen - ipOutputBuffer->nFilledLen) < iOutputFrameLength) |
| { |
| ReturnOutputBuffer(ipOutputBuffer, pOutPort); |
| ipOutputBuffer = NULL; |
| } |
| |
| // Decrement the silence frame counter |
| --iZeroFramesNeeded; |
| } |
| |
| /* Completed Silence insertion successfully, now consider the input buffer already dequeued |
| * for decoding & update the timestamps */ |
| |
| iSilenceInsertionInProgress = OMX_FALSE; |
| iCurrentTimestamp = iFrameTimestamp; |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_NOTICE, (0, "OpenmaxAmrAO : DoSilenceInsertion OUT - Done successfully")); |
| |
| return; |
| } |
| |
| OMX_ERRORTYPE OpenmaxAmrAO::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; |
| } |