| /* |
| * 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 "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; |
| } |