/* * Copyright (C) 2012 Intel Corporation. All rights reserved. * * 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 <inttypes.h> #include <OMX_Component.h> #include "isv_omxcomponent.h" #include <media/hardware/HardwareAPI.h> #include "isv_profile.h" #include <OMX_IndexExt.h> #include <hal_public.h> #include <nativebase/nativebase.h> #include "OMX_adaptor.h" //#define LOG_NDEBUG 0 #undef LOG_TAG #define LOG_TAG "isv-omxil" #define OUTPUT_STARTUP_DEC_BUF_NUM (38) #define FLUSH_WIDTH 352 #define FLUSH_HEIGHT 288 using namespace android; /********************************************************************************** * component methods & helpers */ #define GET_ISVOMX_COMPONENT(hComponent) \ ISVComponent *pComp = static_cast<ISVComponent*> \ ((static_cast<OMX_COMPONENTTYPE*>(hComponent))->pComponentPrivate); \ if (!pComp) \ return OMX_ErrorBadParameter; Vector<ISVComponent*> ISVComponent::g_isv_components; extern MRM_OMX_Adaptor* g_mrm_omx_adaptor; #ifndef TARGET_VPP_USE_GEN //global, static sp<ISVProcessor> ISVComponent::mProcThread = NULL; #endif //global, static pthread_mutex_t ISVComponent::ProcThreadInstanceLock = PTHREAD_MUTEX_INITIALIZER; ISVComponent::ISVComponent( OMX_PTR pAppData) : mComponent(NULL), mpCallBacks(NULL), mCore(NULL), mpISVCallBacks(NULL), mISVBufferManager(NULL), mThreadRunning(false), mProcThreadObserver(NULL), mNumISVBuffers(MIN_ISV_BUFFER_NUM), mNumDecoderBuffers(0), mNumDecoderBuffersBak(0), mOutputDecoderBufferNum(0), mWidth(0), mHeight(0), mUseAndroidNativeBufferIndex(0), mStoreMetaDataInBuffersIndex(0), mHackFormat(0), mUseAndroidNativeBuffer(false), mUseAndroidNativeBuffer2(false), mVPPEnabled(false), mVPPFlushing(false), mOutputCropChanged(false), mInitialized(false), #ifdef TARGET_VPP_USE_GEN mProcThread(NULL), #endif mOwnProcessor(false) { memset(&mBaseComponent, 0, sizeof(OMX_COMPONENTTYPE)); /* handle initialization */ SetTypeHeader(&mBaseComponent, sizeof(mBaseComponent)); mBaseComponent.pApplicationPrivate = pAppData; mBaseComponent.pComponentPrivate = static_cast<OMX_PTR>(this); /* connect handle's functions */ mBaseComponent.GetComponentVersion = NULL; mBaseComponent.SendCommand = SendCommand; mBaseComponent.GetParameter = GetParameter; mBaseComponent.SetParameter = SetParameter; mBaseComponent.GetConfig = GetConfig; mBaseComponent.SetConfig = SetConfig; mBaseComponent.GetExtensionIndex = GetExtensionIndex; mBaseComponent.GetState = GetState; mBaseComponent.ComponentTunnelRequest = NULL; mBaseComponent.UseBuffer = UseBuffer; mBaseComponent.AllocateBuffer = AllocateBuffer; mBaseComponent.FreeBuffer = FreeBuffer; mBaseComponent.EmptyThisBuffer = EmptyThisBuffer; mBaseComponent.FillThisBuffer = FillThisBuffer; mBaseComponent.SetCallbacks = SetCallbacks; mBaseComponent.ComponentDeInit = NULL; mBaseComponent.UseEGLImage = NULL; mBaseComponent.ComponentRoleEnum = ComponentRoleEnum; g_isv_components.push_back(static_cast<ISVComponent*>(this)); mVPPOn = ISVProfile::isFRCOn() || ISVProfile::isVPPOn(); ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: mVPPOn %d", __func__, mVPPOn); if (mISVBufferManager == NULL) { mISVBufferManager = new ISVBufferManager(); } } ISVComponent::~ISVComponent() { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s", __func__); if (mpISVCallBacks) { free(mpISVCallBacks); mpISVCallBacks = NULL; } for (OMX_U32 i = 0; i < g_isv_components.size(); i++) { if (g_isv_components.itemAt(i) == static_cast<ISVComponent*>(this)) { g_isv_components.removeAt(i); } } memset(&mBaseComponent, 0, sizeof(OMX_COMPONENTTYPE)); deinit(); mVPPOn = false; mISVBufferManager = NULL; } status_t ISVComponent::init(int32_t width, int32_t height) { if (mInitialized) return STATUS_OK; bool frcOn = false; if (mProcThreadObserver == NULL) mProcThreadObserver = new ISVProcThreadObserver(&mBaseComponent, mComponent, mpCallBacks, mISVBufferManager); pthread_mutex_lock(&ProcThreadInstanceLock); if (mProcThread == NULL) { mProcThread = new ISVProcessor(false, mISVBufferManager, mProcThreadObserver, width, height); mOwnProcessor = true; mProcThread->start(); } #ifndef TARGET_VPP_USE_GEN else { mVPPEnabled = false; mOwnProcessor = false; ALOGI("%s: failed to alloc isv processor", __func__); pthread_mutex_unlock(&ProcThreadInstanceLock); return STATUS_ERROR; } #endif pthread_mutex_unlock(&ProcThreadInstanceLock); mInitialized = true; return STATUS_OK; } void ISVComponent::deinit() { pthread_mutex_lock(&ProcThreadInstanceLock); if (mOwnProcessor) { if (mProcThread != NULL) { mProcThread->stop(); mProcThread = NULL; ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: delete ISV processor ", __func__); } } pthread_mutex_unlock(&ProcThreadInstanceLock); mProcThreadObserver = NULL; mInitialized = false; } OMX_CALLBACKTYPE* ISVComponent::getCallBacks(OMX_CALLBACKTYPE* pCallBacks) { //reset component callback functions mpCallBacks = pCallBacks; if (mpISVCallBacks) { free(mpISVCallBacks); mpISVCallBacks = NULL; } mpISVCallBacks = (OMX_CALLBACKTYPE *)calloc(1, sizeof(OMX_CALLBACKTYPE)); if (!mpISVCallBacks) { ALOGE("%s: failed to alloc isv callbacks", __func__); return NULL; } mpISVCallBacks->EventHandler = EventHandler; mpISVCallBacks->EmptyBufferDone = pCallBacks->EmptyBufferDone; mpISVCallBacks->FillBufferDone = FillBufferDone; return mpISVCallBacks; } OMX_ERRORTYPE ISVComponent::SendCommand( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_COMMANDTYPE Cmd, OMX_IN OMX_U32 nParam1, OMX_IN OMX_PTR pCmdData) { GET_ISVOMX_COMPONENT(hComponent); return pComp->ISV_SendCommand(Cmd, nParam1, pCmdData); } OMX_ERRORTYPE ISVComponent::ISV_SendCommand( OMX_IN OMX_COMMANDTYPE Cmd, OMX_IN OMX_U32 nParam1, OMX_IN OMX_PTR pCmdData) { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: Cmd index 0x%08x, nParam1 %d", __func__, Cmd, nParam1); if (mVPPEnabled && mVPPOn) { if ((Cmd == OMX_CommandFlush && (nParam1 == kPortIndexOutput || nParam1 == OMX_ALL)) || (Cmd == OMX_CommandStateSet && nParam1 == OMX_StateIdle) || (Cmd == OMX_CommandPortDisable && nParam1 == 1)) { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: receive flush command, notify vpp thread to flush(Seek begin)", __func__); mVPPFlushing = true; mProcThread->notifyFlush(); } } return OMX_SendCommand(mComponent, Cmd, nParam1, pCmdData); } OMX_ERRORTYPE ISVComponent::GetParameter( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_INDEXTYPE nParamIndex, OMX_INOUT OMX_PTR pComponentParameterStructure) { GET_ISVOMX_COMPONENT(hComponent); return pComp->ISV_GetParameter(nParamIndex, pComponentParameterStructure); } OMX_ERRORTYPE ISVComponent::ISV_GetParameter( OMX_IN OMX_INDEXTYPE nParamIndex, OMX_INOUT OMX_PTR pComponentParameterStructure) { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: nIndex 0x%08x", __func__, nParamIndex); OMX_ERRORTYPE err = OMX_GetParameter(mComponent, nParamIndex, pComponentParameterStructure); if (err == OMX_ErrorNone && mVPPEnabled && mVPPOn) { OMX_PARAM_PORTDEFINITIONTYPE *def = static_cast<OMX_PARAM_PORTDEFINITIONTYPE*>(pComponentParameterStructure); if (nParamIndex == OMX_IndexParamPortDefinition && def->nPortIndex == kPortIndexOutput) { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: orignal bufferCountActual %d, bufferCountMin %d", __func__, def->nBufferCountActual, def->nBufferCountMin); #ifndef TARGET_VPP_USE_GEN //FIXME: THIS IS A HACK!! Request NV12 buffer for YV12 format //because VSP only support NV12 output OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def->format.video; if ((video_def->eColorFormat == VA_FOURCC_YV12) || (video_def->eColorFormat == HAL_PIXEL_FORMAT_INTEL_YV12)) { //FIXME workaround Disable ISV for YV12 input mVPPEnabled = false; ALOGI("%s: Disable ISV for YV12 input. mVPPEnabled %d", __func__, mVPPEnabled); } else { //FIXME workaround avc low resolution playback def->nBufferCountActual += mNumISVBuffers + 9; def->nBufferCountMin += mNumISVBuffers + 9; } #endif } } return err; } OMX_ERRORTYPE ISVComponent::SetParameter( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_INDEXTYPE nIndex, OMX_IN OMX_PTR pComponentParameterStructure) { GET_ISVOMX_COMPONENT(hComponent); return pComp->ISV_SetParameter(nIndex, pComponentParameterStructure); } OMX_ERRORTYPE ISVComponent::ISV_SetParameter( OMX_IN OMX_INDEXTYPE nIndex, OMX_IN OMX_PTR pComponentParameterStructure) { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: nIndex 0x%08x", __func__, nIndex); if (nIndex == static_cast<OMX_INDEXTYPE>(OMX_IndexExtSetISVMode)) { ISV_MODE* def = static_cast<ISV_MODE*>(pComponentParameterStructure); if (*def == ISV_AUTO) { mVPPEnabled = true; ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: mVPPEnabled -->true", __func__); #ifndef TARGET_VPP_USE_GEN if (mVPPOn) { uint32_t number = MIN_INPUT_NUM + MIN_OUTPUT_NUM; OMX_INDEXTYPE index; status_t error = OMX_GetExtensionIndex( mComponent, (OMX_STRING)"OMX.Intel.index.vppBufferNum", &index); if (error == OK) { error = OMX_SetParameter(mComponent, index, (OMX_PTR)&number); } else { // ingore this error ALOGW("Get vpp number index failed"); } } #endif } else if (*def == ISV_DISABLE) mVPPEnabled = false; return OMX_ErrorNone; } // before setting param to real omx component, firstly set to media resource manager OMX_ERRORTYPE err = g_mrm_omx_adaptor->MRM_OMX_SetParameter(mComponent, nIndex, pComponentParameterStructure); if (err == OMX_ErrorInsufficientResources) { return OMX_ErrorInsufficientResources; } err = OMX_SetParameter(mComponent, nIndex, pComponentParameterStructure); if (err == OMX_ErrorNone && mVPPEnabled && mVPPOn) { if (nIndex == OMX_IndexParamPortDefinition) { OMX_PARAM_PORTDEFINITIONTYPE *def = static_cast<OMX_PARAM_PORTDEFINITIONTYPE*>(pComponentParameterStructure); if (def->nPortIndex == kPortIndexOutput) { //set the buffer count we should fill to decoder before feed buffer to VPP mNumDecoderBuffersBak = mNumDecoderBuffers = def->nBufferCountActual - MIN_OUTPUT_NUM - UNDEQUEUED_NUM; mOutputDecoderBufferNum = 0; OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def->format.video; //FIXME: init itself here if (mWidth != video_def->nFrameWidth || mHeight != video_def->nFrameHeight) { deinit(); if (STATUS_OK == init(video_def->nFrameWidth, video_def->nFrameHeight)) { mWidth = video_def->nFrameWidth; mHeight = video_def->nFrameHeight; } } ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: def->nBufferCountActual %d, mNumDecoderBuffersBak %d", __func__, def->nBufferCountActual, mNumDecoderBuffersBak); if (mISVBufferManager != NULL && OK != mISVBufferManager->setBufferCount(def->nBufferCountActual)) { ALOGE("%s: failed to set ISV buffer count, set VPPEnabled -->false", __func__); mVPPEnabled = false; } ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: video frame width %d, height %d", __func__, video_def->nFrameWidth, video_def->nFrameHeight); } if (def->nPortIndex == kPortIndexInput) { OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def->format.video; if (mProcThread != NULL) mProcThread->configFRC(video_def->xFramerate); } } if (mUseAndroidNativeBuffer && nIndex == static_cast<OMX_INDEXTYPE>(mUseAndroidNativeBufferIndex)) { UseAndroidNativeBufferParams *def = static_cast<UseAndroidNativeBufferParams*>(pComponentParameterStructure); if (mISVBufferManager != NULL && OK != mISVBufferManager->useBuffer(def->nativeBuffer)) { ALOGE("%s: failed to register graphic buffers to ISV, set mVPPEnabled -->false", __func__); mVPPEnabled = false; } } if (nIndex == static_cast<OMX_INDEXTYPE>(mStoreMetaDataInBuffersIndex)) { StoreMetaDataInBuffersParams *params = static_cast<StoreMetaDataInBuffersParams*>(pComponentParameterStructure); if (params->nPortIndex == kPortIndexOutput) { if (mISVBufferManager != NULL) { bool bMetaDataMode = params->bStoreMetaData == OMX_TRUE; mISVBufferManager->setMetaDataMode(bMetaDataMode); } else { ALOGE("%s: falied to set Meta Data Mode ", __func__); } } ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: receive ISVStoreMetaDataInBuffers mISVWorkMode %d", __func__, (params->bStoreMetaData == OMX_TRUE)); } } return err; } OMX_ERRORTYPE ISVComponent::GetConfig( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_INDEXTYPE nIndex, OMX_INOUT OMX_PTR pComponentConfigStructure) { GET_ISVOMX_COMPONENT(hComponent); return pComp->ISV_GetConfig(nIndex, pComponentConfigStructure); } OMX_ERRORTYPE ISVComponent::ISV_GetConfig( OMX_IN OMX_INDEXTYPE nIndex, OMX_INOUT OMX_PTR pComponentConfigStructure) { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: nIndex 0x%08x", __func__, nIndex); OMX_ERRORTYPE err = OMX_GetConfig(mComponent, nIndex, pComponentConfigStructure); if (err == OMX_ErrorNone && mVPPEnabled && mVPPOn) { if (nIndex == OMX_IndexConfigCommonOutputCrop) { OMX_CONFIG_RECTTYPE *rect = static_cast<OMX_CONFIG_RECTTYPE*>(pComponentConfigStructure); if (rect->nPortIndex == kPortIndexOutput && rect->nWidth < mWidth && rect->nHeight < mHeight) { mISVBufferManager->setBuffersFlag(ISVBuffer::ISV_BUFFER_NEED_CLEAR); ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: mark all buffers need clear", __func__); } } } return err; } OMX_ERRORTYPE ISVComponent::SetConfig( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_INDEXTYPE nIndex, OMX_IN OMX_PTR pComponentConfigStructure) { GET_ISVOMX_COMPONENT(hComponent); return pComp->ISV_SetConfig(nIndex, pComponentConfigStructure); } OMX_ERRORTYPE ISVComponent::ISV_SetConfig( OMX_IN OMX_INDEXTYPE nIndex, OMX_IN OMX_PTR pComponentConfigStructure) { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: nIndex 0x%08x", __func__, nIndex); if (nIndex == static_cast<OMX_INDEXTYPE>(OMX_IndexConfigAutoFramerateConversion)) { OMX_CONFIG_BOOLEANTYPE *config = static_cast<OMX_CONFIG_BOOLEANTYPE*>(pComponentConfigStructure); if (config->bEnabled) { mVPPEnabled = true; ALOGI("%s: mVPPEnabled=true", __func__); } else { mVPPEnabled = false; ALOGI("%s: mVPPEnabled=false", __func__); } return OMX_ErrorNone; } return OMX_SetConfig(mComponent, nIndex, pComponentConfigStructure); } OMX_ERRORTYPE ISVComponent::GetExtensionIndex( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_STRING cParameterName, OMX_OUT OMX_INDEXTYPE* pIndexType) { GET_ISVOMX_COMPONENT(hComponent); return pComp->ISV_GetExtensionIndex(cParameterName, pIndexType); } OMX_ERRORTYPE ISVComponent::ISV_GetExtensionIndex( OMX_IN OMX_STRING cParameterName, OMX_OUT OMX_INDEXTYPE* pIndexType) { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: cParameterName %s", __func__, cParameterName); if(!strncmp(cParameterName, "OMX.intel.index.SetISVMode", strlen(cParameterName))) { *pIndexType = static_cast<OMX_INDEXTYPE>(OMX_IndexExtSetISVMode); return OMX_ErrorNone; } OMX_ERRORTYPE err = OMX_GetExtensionIndex(mComponent, cParameterName, pIndexType); if(err == OMX_ErrorNone && !strncmp(cParameterName, "OMX.google.android.index.useAndroidNativeBuffer2", strlen(cParameterName))) mUseAndroidNativeBuffer2 = true; if(err == OMX_ErrorNone && !strncmp(cParameterName, "OMX.google.android.index.useAndroidNativeBuffer", strlen(cParameterName))) { mUseAndroidNativeBuffer = true; mUseAndroidNativeBufferIndex = static_cast<uint32_t>(*pIndexType); } if(err == OMX_ErrorNone && !strncmp(cParameterName, "OMX.google.android.index.storeMetaDataInBuffers", strlen(cParameterName))) { mStoreMetaDataInBuffersIndex = static_cast<uint32_t>(*pIndexType); ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: storeMetaDataInBuffersIndex 0x%08x return %d", __func__, mStoreMetaDataInBuffersIndex, err); } ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: cParameterName %s, nIndex 0x%08x", __func__, cParameterName, *pIndexType); return err; } OMX_ERRORTYPE ISVComponent::GetState( OMX_IN OMX_HANDLETYPE hComponent, OMX_OUT OMX_STATETYPE* pState) { GET_ISVOMX_COMPONENT(hComponent); return pComp->ISV_GetState(pState); } OMX_ERRORTYPE ISVComponent::ISV_GetState( OMX_OUT OMX_STATETYPE* pState) { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s", __func__); return OMX_GetState(mComponent, pState); } OMX_ERRORTYPE ISVComponent::UseBuffer( OMX_IN OMX_HANDLETYPE hComponent, OMX_INOUT OMX_BUFFERHEADERTYPE **ppBufferHdr, OMX_IN OMX_U32 nPortIndex, OMX_IN OMX_PTR pAppPrivate, OMX_IN OMX_U32 nSizeBytes, OMX_IN OMX_U8 *pBuffer) { GET_ISVOMX_COMPONENT(hComponent); return pComp->ISV_UseBuffer(ppBufferHdr, nPortIndex, pAppPrivate, nSizeBytes, pBuffer); } OMX_ERRORTYPE ISVComponent::ISV_UseBuffer( OMX_INOUT OMX_BUFFERHEADERTYPE **ppBufferHdr, OMX_IN OMX_U32 nPortIndex, OMX_IN OMX_PTR pAppPrivate, OMX_IN OMX_U32 nSizeBytes, OMX_IN OMX_U8 *pBuffer) { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s", __func__); OMX_ERRORTYPE err = OMX_UseBuffer(mComponent, ppBufferHdr, nPortIndex, pAppPrivate, nSizeBytes, pBuffer); #ifndef USE_IVP if(err == OMX_ErrorNone && mVPPEnabled && mVPPOn && nPortIndex == kPortIndexOutput /*&& mUseAndroidNativeBuffer2*/) { if (mISVBufferManager != NULL) { if (OK != mISVBufferManager->useBuffer(reinterpret_cast<unsigned long>(pBuffer))) { ALOGE("%s: failed to register graphic buffers to ISV, set mVPPEnabled -->false", __func__); mVPPEnabled = false; } else ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: mVPP useBuffer success. buffer handle %p", __func__, pBuffer); } } #endif return err; } OMX_ERRORTYPE ISVComponent::AllocateBuffer( OMX_IN OMX_HANDLETYPE hComponent, OMX_INOUT OMX_BUFFERHEADERTYPE **ppBuffer, OMX_IN OMX_U32 nPortIndex, OMX_IN OMX_PTR pAppPrivate, OMX_IN OMX_U32 nSizeBytes) { GET_ISVOMX_COMPONENT(hComponent); return pComp->ISV_AllocateBuffer(ppBuffer, nPortIndex, pAppPrivate, nSizeBytes); } OMX_ERRORTYPE ISVComponent::ISV_AllocateBuffer( OMX_INOUT OMX_BUFFERHEADERTYPE **ppBuffer, OMX_IN OMX_U32 nPortIndex, OMX_IN OMX_PTR pAppPrivate, OMX_IN OMX_U32 nSizeBytes) { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s", __func__); return OMX_AllocateBuffer(mComponent, ppBuffer, nPortIndex, pAppPrivate, nSizeBytes); } OMX_ERRORTYPE ISVComponent::FreeBuffer( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_U32 nPortIndex, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { GET_ISVOMX_COMPONENT(hComponent); return pComp->ISV_FreeBuffer(nPortIndex, pBuffer); } OMX_ERRORTYPE ISVComponent::ISV_FreeBuffer( OMX_IN OMX_U32 nPortIndex, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: pBuffer %p", __func__, pBuffer); if(mVPPEnabled && mVPPOn && nPortIndex == kPortIndexOutput) { if (mISVBufferManager != NULL && OK != mISVBufferManager->freeBuffer(reinterpret_cast<unsigned long>(pBuffer->pBuffer))) ALOGW("%s: pBuffer %p has not been registered into ISV", __func__, pBuffer); } return OMX_FreeBuffer(mComponent, nPortIndex, pBuffer); } OMX_ERRORTYPE ISVComponent::EmptyThisBuffer( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { GET_ISVOMX_COMPONENT(hComponent); return pComp->ISV_EmptyThisBuffer(pBuffer); } OMX_ERRORTYPE ISVComponent::ISV_EmptyThisBuffer( OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: pBuffer %p", __func__, pBuffer); return OMX_EmptyThisBuffer(mComponent, pBuffer); } OMX_ERRORTYPE ISVComponent::FillThisBuffer( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: API entry.", __func__); GET_ISVOMX_COMPONENT(hComponent); return pComp->ISV_FillThisBuffer(pBuffer); } OMX_ERRORTYPE ISVComponent::ISV_FillThisBuffer( OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) { if(!mVPPEnabled || !mVPPOn) return OMX_FillThisBuffer(mComponent, pBuffer); ISVBuffer* isvBuffer = NULL; if (mISVBufferManager != NULL) { isvBuffer = mISVBufferManager->mapBuffer(reinterpret_cast<unsigned long>(pBuffer->pBuffer)); if (isvBuffer == NULL) { ALOGE("%s: failed to map ISVBuffer, set mVPPEnabled -->false", __func__); mVPPEnabled = false; return OMX_FillThisBuffer(mComponent, pBuffer); } if (OK != isvBuffer->initBufferInfo(mHackFormat)) { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: isvBuffer %p failed to initBufferInfo", __func__, isvBuffer); mVPPEnabled = false; return OMX_FillThisBuffer(mComponent, pBuffer); } } if (mNumDecoderBuffers > 0) { Mutex::Autolock autoLock(mDecoderBufLock); mNumDecoderBuffers--; ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: fill pBuffer %p to the decoder, decoder still need extra %d buffers", __func__, pBuffer, mNumDecoderBuffers); if (isvBuffer != NULL) isvBuffer->clearIfNeed(); return OMX_FillThisBuffer(mComponent, pBuffer); } mProcThread->addOutput(pBuffer); return OMX_ErrorNone; } OMX_ERRORTYPE ISVComponent::FillBufferDone( OMX_OUT OMX_HANDLETYPE hComponent, OMX_OUT OMX_PTR pAppData, OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer) { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: API entry. ISV component num %d, component handle %p on index 0", __func__, g_isv_components.size(), g_isv_components.itemAt(0)); for (OMX_U32 i = 0; i < g_isv_components.size(); i++) { if (static_cast<OMX_HANDLETYPE>(g_isv_components.itemAt(i)->mComponent) == hComponent) return g_isv_components.itemAt(i)->ISV_FillBufferDone(hComponent, pAppData, pBuffer); } return OMX_ErrorUndefined; } OMX_ERRORTYPE ISVComponent::ISV_FillBufferDone( OMX_OUT OMX_HANDLETYPE __maybe_unused hComponent, OMX_OUT OMX_PTR pAppData, OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer) { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: %p <== buffer_handle_t %p. mVPPEnabled %d, mVPPOn %d", __func__, pBuffer, pBuffer->pBuffer, mVPPEnabled, mVPPOn); if (!mpCallBacks) { ALOGE("%s: no call back functions were registered.", __func__); return OMX_ErrorUndefined; } if(!mVPPEnabled || !mVPPOn || mVPPFlushing || (pBuffer->nFilledLen == 0 && !(pBuffer->nFlags & OMX_BUFFERFLAG_EOS))) { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: FillBufferDone pBuffer %p, timeStamp %.2f ms", __func__, pBuffer, pBuffer->nTimeStamp/1E3); return mpCallBacks->FillBufferDone(&mBaseComponent, pAppData, pBuffer); } if (mOutputCropChanged && mISVBufferManager != NULL) { ISVBuffer* isvBuffer = mISVBufferManager->mapBuffer(reinterpret_cast<unsigned long>(pBuffer->pBuffer)); if (isvBuffer != NULL) isvBuffer->setFlag(ISVBuffer::ISV_BUFFER_CROP_CHANGED); mOutputCropChanged = false; } if ((mWidth > FLUSH_WIDTH) && (mHeight > FLUSH_HEIGHT) && (pBuffer->nFilledLen != 0) && (mOutputDecoderBufferNum < OUTPUT_STARTUP_DEC_BUF_NUM)) { Mutex::Autolock autoLock(mDecoderBufLock); // take one buffer from decoder loop here. Fill one buffer to the loop by mNumDecoderBuffers++ mNumDecoderBuffers++; mOutputDecoderBufferNum++; ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: return %d decoder output Buffer, mNumDecoderBuffers get %d input buffer", __func__, mOutputDecoderBufferNum, mNumDecoderBuffers); return mpCallBacks->FillBufferDone(&mBaseComponent, pAppData, pBuffer); } mProcThread->addInput(pBuffer); return OMX_ErrorNone; } OMX_ERRORTYPE ISVComponent::EventHandler( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_PTR pAppData, OMX_IN OMX_EVENTTYPE eEvent, OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, OMX_IN OMX_PTR pEventData) { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: API entry. ISV component num %d, component handle %p on index 0", __func__, g_isv_components.size(), g_isv_components.itemAt(0)); for (OMX_U32 i = 0; i < g_isv_components.size(); i++) { if (static_cast<OMX_HANDLETYPE>(g_isv_components.itemAt(i)->mComponent) == hComponent) return g_isv_components.itemAt(i)->ISV_EventHandler(hComponent, pAppData, eEvent, nData1, nData2, pEventData); } return OMX_ErrorUndefined; } OMX_ERRORTYPE ISVComponent::ISV_EventHandler( OMX_IN OMX_HANDLETYPE __maybe_unused hComponent, OMX_IN OMX_PTR pAppData, OMX_IN OMX_EVENTTYPE eEvent, OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, OMX_IN OMX_PTR pEventData) { if (!mpCallBacks) { ALOGE("%s: no call back functions were registered.", __func__); return OMX_ErrorUndefined; } if(!mVPPEnabled || !mVPPOn) return mpCallBacks->EventHandler(&mBaseComponent, pAppData, eEvent, nData1, nData2, pEventData); switch (eEvent) { case OMX_EventCmdComplete: { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: OMX_EventCmdComplete Cmd type 0x%08x, data2 %d", __func__, nData1, nData2); if (((OMX_COMMANDTYPE)nData1 == OMX_CommandFlush && (nData2 == kPortIndexOutput || nData2 == OMX_ALL)) || ((OMX_COMMANDTYPE)nData1 == OMX_CommandStateSet && nData2 == OMX_StateIdle) || ((OMX_COMMANDTYPE)nData1 == OMX_CommandPortDisable && nData2 == 1)) { mProcThread->waitFlushFinished(); mVPPFlushing = false; mNumDecoderBuffers = mNumDecoderBuffersBak; mOutputDecoderBufferNum = 0; } break; } case OMX_EventError: { //do we need do anything here? ALOGE("%s: ERROR(0x%08x, %d)", __func__, nData1, nData2); //mProcThread->flush(); break; } case OMX_EventPortSettingsChanged: { if (nData1 == kPortIndexOutput && nData2 == OMX_IndexConfigCommonOutputCrop) { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: output crop changed", __func__); mOutputCropChanged = true; return OMX_ErrorNone; } else if (nData1 == kPortIndexOutput && nData2 == OMX_IndexParamPortDefinition) { ALOGI("%s: output format changed. ISV flush buffers", __func__); mProcThread->notifyFlush(); } break; } default: { ALOGD_IF( ISV_COMPONENT_DEBUG, "%s: EVENT(%d, %" PRId32 ", %" PRId32 ")", __func__, eEvent, nData1, nData2); break; } } return mpCallBacks->EventHandler(&mBaseComponent, pAppData, eEvent, nData1, nData2, pEventData); } OMX_ERRORTYPE ISVComponent::SetCallbacks( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_CALLBACKTYPE* pCallbacks, OMX_IN OMX_PTR pAppData) { GET_ISVOMX_COMPONENT(hComponent); return pComp->ISV_SetCallbacks(pCallbacks, pAppData); } OMX_ERRORTYPE ISVComponent::ISV_SetCallbacks( OMX_IN OMX_CALLBACKTYPE* pCallbacks, OMX_IN OMX_PTR pAppData) { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s", __func__); if (mVPPEnabled && mVPPOn) { if (mpISVCallBacks == NULL) { mpISVCallBacks = (OMX_CALLBACKTYPE *)calloc(1, sizeof(OMX_CALLBACKTYPE)); if (!mpISVCallBacks) { ALOGE("%s: failed to alloc isv callbacks", __func__); return OMX_ErrorUndefined; } } mpISVCallBacks->EventHandler = EventHandler; mpISVCallBacks->EmptyBufferDone = pCallbacks->EmptyBufferDone; mpISVCallBacks->FillBufferDone = FillBufferDone; mpCallBacks = pCallbacks; return mComponent->SetCallbacks(mComponent, mpISVCallBacks, pAppData); } return mComponent->SetCallbacks(mComponent, pCallbacks, pAppData); } OMX_ERRORTYPE ISVComponent::ComponentRoleEnum( OMX_IN OMX_HANDLETYPE hComponent, OMX_OUT OMX_U8 *cRole, OMX_IN OMX_U32 nIndex) { GET_ISVOMX_COMPONENT(hComponent); return pComp->ISV_ComponentRoleEnum(cRole, nIndex); } OMX_ERRORTYPE ISVComponent::ISV_ComponentRoleEnum( OMX_OUT OMX_U8 *cRole, OMX_IN OMX_U32 nIndex) { ALOGD_IF(ISV_COMPONENT_DEBUG, "%s", __func__); return mComponent->ComponentRoleEnum(mComponent, cRole, nIndex); } void ISVComponent::SetTypeHeader(OMX_PTR type, OMX_U32 size) { OMX_U32 *nsize; OMX_VERSIONTYPE *nversion; if (!type) return; nsize = (OMX_U32 *)type; nversion = (OMX_VERSIONTYPE *)((OMX_U8 *)type + sizeof(OMX_U32)); *nsize = size; nversion->nVersion = OMX_SPEC_VERSION; } ISVProcThreadObserver::ISVProcThreadObserver( OMX_COMPONENTTYPE *pBaseComponent, OMX_COMPONENTTYPE *pComponent, OMX_CALLBACKTYPE *pCallBacks, sp<ISVBufferManager> bufferManager) : mBaseComponent(pBaseComponent), mComponent(pComponent), mpCallBacks(pCallBacks), mISVBufferManager(bufferManager) { ALOGV("VPPProcThreadObserver!"); } ISVProcThreadObserver::~ISVProcThreadObserver() { ALOGV("~VPPProcThreadObserver!"); mBaseComponent = NULL; mComponent = NULL; mpCallBacks = NULL; } OMX_ERRORTYPE ISVProcThreadObserver::releaseBuffer(PORT_INDEX index, OMX_BUFFERHEADERTYPE* pBuffer, bool bFLush) { if (!mBaseComponent || !mComponent || !mpCallBacks) return OMX_ErrorUndefined; OMX_ERRORTYPE err = OMX_ErrorNone; if (bFLush) { if(index == kPortIndexOutput) { pBuffer->nFilledLen = 0; pBuffer->nOffset = 0; pBuffer->nTimeStamp = 0; pBuffer->nFlags = 0; } err = mpCallBacks->FillBufferDone(&mBaseComponent, mBaseComponent->pApplicationPrivate, pBuffer); ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: flush pBuffer %p", __func__, pBuffer); return err; } if (index == kPortIndexInput) { pBuffer->nFilledLen = 0; pBuffer->nOffset = 0; pBuffer->nFlags = 0; pBuffer->nTimeStamp = 0; if (mISVBufferManager != NULL) { ISVBuffer* isvBuffer = mISVBufferManager->mapBuffer(reinterpret_cast<unsigned long>(pBuffer->pBuffer)); if (isvBuffer != NULL) isvBuffer->clearIfNeed(); } err = OMX_FillThisBuffer(mComponent, pBuffer); ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: FillBuffer pBuffer %p", __func__, pBuffer); } else { err = mpCallBacks->FillBufferDone(&mBaseComponent, mBaseComponent->pApplicationPrivate, pBuffer); ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: FillBufferDone pBuffer %p, timeStamp %.2f ms", __func__, pBuffer, pBuffer->nTimeStamp/1E3); } return err; } OMX_ERRORTYPE ISVProcThreadObserver::reportOutputCrop() { if (!mBaseComponent || !mComponent || !mpCallBacks) return OMX_ErrorUndefined; OMX_ERRORTYPE err = OMX_ErrorNone; err = mpCallBacks->EventHandler(&mBaseComponent, mBaseComponent->pApplicationPrivate, OMX_EventPortSettingsChanged, kPortIndexOutput, OMX_IndexConfigCommonOutputCrop, NULL); return err; }