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