/*
* 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.
*/
#define LOG_TIME 0
//#define LOG_NDEBUG 0
#define LOG_TAG "OMXVideoDecoderVP9Hybrid"
#include <wrs_omxil_core/log.h>
#include "OMXVideoDecoderVP9Hybrid.h"
#include <hardware/hardware.h>
#include <hardware/gralloc.h>
#include <system/graphics.h>
#include <hal_public.h>
#define VP9_YV12_ALIGN (128-1)
static const char* VP9_MIME_TYPE = "video/x-vnd.on2.vp9";
OMXVideoDecoderVP9Hybrid::OMXVideoDecoderVP9Hybrid() {
LOGV("OMXVideoDecoderVP9Hybrid is constructed.");
mNativeBufferCount = OUTPORT_NATIVE_BUFFER_COUNT;
BuildHandlerList();
mLibHandle = NULL;
mOpenDecoder = NULL;
mInitDecoder = NULL;
mCloseDecoder = NULL;
mSingalRenderDone = NULL;
mDecoderDecode = NULL;
mCheckBufferAvailable = NULL;
mGetOutput = NULL;
mGetRawDataOutput = NULL;
mGetFrameResolution = NULL;
mDeinitDecoder = NULL;
mLastTimeStamp = 0;
mWorkingMode = RAWDATA_MODE;
mDecodedImageWidth = 0;
mDecodedImageHeight = 0;
mDecodedImageNewWidth = 0;
mDecodedImageNewHeight = 0;
}
OMXVideoDecoderVP9Hybrid::~OMXVideoDecoderVP9Hybrid() {
LOGV("OMXVideoDecoderVP9Hybrid is destructed.");
}
OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::InitInputPortFormatSpecific(
OMX_PARAM_PORTDEFINITIONTYPE *paramPortDefinitionInput) {
// OMX_PARAM_PORTDEFINITIONTYPE
paramPortDefinitionInput->nBufferCountActual = INPORT_ACTUAL_BUFFER_COUNT;
paramPortDefinitionInput->nBufferCountMin = INPORT_MIN_BUFFER_COUNT;
paramPortDefinitionInput->nBufferSize = INPORT_BUFFER_SIZE;
paramPortDefinitionInput->format.video.cMIMEType = (OMX_STRING)VP9_MIME_TYPE;
paramPortDefinitionInput->format.video.eCompressionFormat = OMX_VIDEO_CodingVP9;
return OMX_ErrorNone;
}
OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::ProcessorInit(void) {
uint32_t buff[MAX_GRAPHIC_BUFFER_NUM];
uint32_t i, bufferCount;
bool gralloc_mode = (mWorkingMode == GRAPHICBUFFER_MODE);
uint32_t bufferSize, bufferHStride, bufferHeight, bufferVStride, bufferWidth;
if (!gralloc_mode) {
bufferHStride = 1920;
bufferVStride = 1088;
bufferWidth = 1920;
bufferHeight = 1080;
bufferCount = 12;
} else {
if (mAPMode == METADATA_MODE) {
const OMX_PARAM_PORTDEFINITIONTYPE *def_output = this->ports[OUTPORT_INDEX]->GetPortDefinition();
if (def_output == NULL) {
return OMX_ErrorBadParameter;
}
bufferCount = mMetaDataBuffersNum = def_output->nBufferCountActual;
mOMXBufferHeaderTypePtrNum = 0;
mGraphicBufferParam.graphicBufferColorFormat = def_output->format.video.eColorFormat;
mGraphicBufferParam.graphicBufferHStride = (def_output->format.video.nFrameWidth + VP9_YV12_ALIGN) & ~VP9_YV12_ALIGN;
mGraphicBufferParam.graphicBufferVStride = (def_output->format.video.nFrameHeight + 0x1f) & ~0x1f;
mGraphicBufferParam.graphicBufferWidth = def_output->format.video.nFrameWidth;
mGraphicBufferParam.graphicBufferHeight = def_output->format.video.nFrameHeight;
mDecodedImageWidth = def_output->format.video.nFrameWidth;
mDecodedImageHeight = def_output->format.video.nFrameHeight;
} else{
bufferCount = mOMXBufferHeaderTypePtrNum;
for (i = 0; i < bufferCount; i++ ) {
OMX_BUFFERHEADERTYPE *buf_hdr = mOMXBufferHeaderTypePtrArray[i];
buff[i] = (uint32_t)(buf_hdr->pBuffer);
}
}
bufferHStride = mGraphicBufferParam.graphicBufferHStride;
bufferVStride = mGraphicBufferParam.graphicBufferVStride;
bufferWidth = mGraphicBufferParam.graphicBufferWidth;
bufferHeight = mGraphicBufferParam.graphicBufferHeight;
}
bufferSize = bufferHStride * bufferVStride * 1.5;
mLibHandle = dlopen("libDecoderVP9Hybrid.so", RTLD_NOW);
if (mLibHandle == NULL) {
LOGE("dlopen libDecoderVP9Hybrid.so fail\n");
return OMX_ErrorBadParameter;
} else {
LOGI("dlopen libDecoderVP9Hybrid.so successfully\n");
}
mOpenDecoder = (OpenFunc)dlsym(mLibHandle, "Decoder_Open");
mCloseDecoder = (CloseFunc)dlsym(mLibHandle, "Decoder_Close");
mInitDecoder = (InitFunc)dlsym(mLibHandle, "Decoder_Init");
mSingalRenderDone = (SingalRenderDoneFunc)dlsym(mLibHandle, "Decoder_SingalRenderDone");
mDecoderDecode = (DecodeFunc)dlsym(mLibHandle, "Decoder_Decode");
mCheckBufferAvailable = (IsBufferAvailableFunc)dlsym(mLibHandle, "Decoder_IsBufferAvailable");
mGetOutput = (GetOutputFunc)dlsym(mLibHandle, "Decoder_GetOutput");
mGetRawDataOutput = (GetRawDataOutputFunc)dlsym(mLibHandle, "Decoder_GetRawDataOutput");
mGetFrameResolution = (GetFrameResolutionFunc)dlsym(mLibHandle, "Decoder_GetFrameResolution");
mDeinitDecoder = (DeinitFunc)dlsym(mLibHandle, "Decoder_Deinit");
if (mOpenDecoder == NULL || mCloseDecoder == NULL
|| mInitDecoder == NULL || mSingalRenderDone == NULL
|| mDecoderDecode == NULL || mCheckBufferAvailable == NULL
|| mGetOutput == NULL || mGetRawDataOutput == NULL
|| mGetFrameResolution == NULL || mDeinitDecoder == NULL) {
return OMX_ErrorBadParameter;
}
if (mOpenDecoder(&mCtx,&mHybridCtx) == false) {
LOGE("open hybrid Decoder fail\n");
return OMX_ErrorBadParameter;
}
// FIXME: The proprietary part of the vp9hybrid decoder should be updated
// to take VStride as well as Height. For now it's convenient to
// use VStride as that was effectively what was done before..
mInitDecoder(mHybridCtx, bufferSize, bufferHStride, bufferWidth,
bufferHeight, bufferCount, gralloc_mode, buff, (uint32_t)mAPMode);
return OMX_ErrorNone;
}
OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::ProcessorReset(void)
{
uint32_t buff[MAX_GRAPHIC_BUFFER_NUM];
uint32_t i, bufferCount;
bool gralloc_mode = (mWorkingMode == GRAPHICBUFFER_MODE);
uint32_t bufferSize, bufferHStride, bufferHeight, bufferVStride, bufferWidth;
if (!gralloc_mode) {
bufferHStride = mDecodedImageWidth;
bufferVStride = mDecodedImageHeight;
bufferWidth = mDecodedImageWidth;
bufferHeight = mDecodedImageHeight;
bufferSize = bufferHStride * bufferVStride * 1.5;
bufferCount = 12;
} else {
if (mAPMode == METADATA_MODE) {
const OMX_PARAM_PORTDEFINITIONTYPE *def_output = this->ports[OUTPORT_INDEX]->GetPortDefinition();
if (def_output == NULL) {
return OMX_ErrorBadParameter;
}
bufferCount = mMetaDataBuffersNum = def_output->nBufferCountActual;
mOMXBufferHeaderTypePtrNum = 0;
mGraphicBufferParam.graphicBufferColorFormat = def_output->format.video.eColorFormat;
mGraphicBufferParam.graphicBufferHStride = (def_output->format.video.nFrameWidth + VP9_YV12_ALIGN) & ~VP9_YV12_ALIGN;
mGraphicBufferParam.graphicBufferVStride = (def_output->format.video.nFrameHeight + 0x1f) & ~0x1f;
mGraphicBufferParam.graphicBufferWidth = def_output->format.video.nFrameWidth;
mGraphicBufferParam.graphicBufferHeight = def_output->format.video.nFrameHeight;
} else{
bufferCount = mOMXBufferHeaderTypePtrNum;
for (i = 0; i < bufferCount; i++ ) {
OMX_BUFFERHEADERTYPE *buf_hdr = mOMXBufferHeaderTypePtrArray[i];
buff[i] = (uint32_t)(buf_hdr->pBuffer);
}
}
bufferHStride = mGraphicBufferParam.graphicBufferHStride;
bufferVStride = mGraphicBufferParam.graphicBufferVStride;
bufferWidth = mGraphicBufferParam.graphicBufferWidth;
bufferHeight = mGraphicBufferParam.graphicBufferHeight;
}
bufferSize = bufferHStride * bufferVStride * 1.5;
// FIXME: The proprietary part of the vp9hybrid decoder should be updated
// to take VStride as well as Height. For now it's convenient to
// use VStride as that was effectively what was done before..
mInitDecoder(mHybridCtx, bufferSize, bufferHStride, bufferWidth,
bufferHeight, bufferCount, gralloc_mode, buff, (uint32_t)mAPMode);
mFormatChanged = false;
return OMX_ErrorNone;
}
bool OMXVideoDecoderVP9Hybrid::isReallocateNeeded(const uint8_t * data,uint32_t data_sz)
{
bool gralloc_mode = (mWorkingMode == GRAPHICBUFFER_MODE);
uint32_t width, height;
bool ret = true;
if (gralloc_mode) {
ret = mGetFrameResolution(data,data_sz, &width, &height);
if (width == 0 || height == 0)
return false;
if (ret) {
if (mAPMode == METADATA_MODE) {
ret = (width != mDecodedImageWidth)
|| (height != mDecodedImageHeight);
} else {
ret = width > mGraphicBufferParam.graphicBufferWidth
|| height > mGraphicBufferParam.graphicBufferHeight;
}
if (ret) {
mDecodedImageNewWidth = width;
mDecodedImageNewHeight = height;
return true;
}
}
}
return ret;
}
OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::ProcessorDeinit(void) {
mCloseDecoder(mCtx,mHybridCtx);
mOMXBufferHeaderTypePtrNum = 0;
if (mLibHandle != NULL) {
dlclose(mLibHandle);
mLibHandle = NULL;
}
return OMX_ErrorNone;
}
OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::ProcessorStop(void) {
return OMXComponentCodecBase::ProcessorStop();
}
OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::ProcessorFlush(OMX_U32 portIndex) {
if (portIndex == INPORT_INDEX || portIndex == OMX_ALL) {
// end the last frame
unsigned int width, height;
mDecoderDecode(mCtx,mHybridCtx,NULL,0,true);
mGetOutput(mCtx,mHybridCtx, &width, &height);
}
return OMX_ErrorNone;
}
OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::ProcessorPreFillBuffer(OMX_BUFFERHEADERTYPE* buffer) {
if (buffer->nOutputPortIndex == OUTPORT_INDEX){
unsigned int handle;
if (mAPMode == METADATA_MODE) {
bool found = false;
if (mOMXBufferHeaderTypePtrNum < mMetaDataBuffersNum) {
for (uint32_t i = 0; i < mOMXBufferHeaderTypePtrNum; i++) {
if (mOMXBufferHeaderTypePtrArray[i] == buffer) {
found = true;
break;
}
}
if (!found) {
mOMXBufferHeaderTypePtrArray[mOMXBufferHeaderTypePtrNum] = buffer;
mOMXBufferHeaderTypePtrNum++;
}
} else {
found = true;
}
android::VideoGrallocMetadata *metadata = (android::VideoGrallocMetadata *)(buffer->pBuffer);
handle = (unsigned int)metadata->pHandle;
mSingalRenderDone(mHybridCtx, handle, !found);
} else {
handle = (unsigned int)buffer->pBuffer;
mSingalRenderDone(mHybridCtx, handle, false);
}
}
return OMX_ErrorNone;
}
OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::ProcessorProcess(
OMX_BUFFERHEADERTYPE ***pBuffers,
buffer_retain_t *retains,
OMX_U32)
{
OMX_ERRORTYPE ret;
OMX_BUFFERHEADERTYPE *inBuffer = *pBuffers[INPORT_INDEX];
OMX_BUFFERHEADERTYPE *outBuffer = *pBuffers[OUTPORT_INDEX];
OMX_BOOL isResolutionChange = OMX_FALSE;
bool eos = (inBuffer->nFlags & OMX_BUFFERFLAG_EOS)? true : false;
eos = eos && (inBuffer->nFilledLen == 0);
static unsigned char *firstFrame = NULL;
static uint32_t firstFrameSize = 0;
if (inBuffer->pBuffer == NULL) {
LOGE("Buffer to decode is empty.");
return OMX_ErrorBadParameter;
}
if (inBuffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
LOGI("Buffer has OMX_BUFFERFLAG_CODECCONFIG flag.");
}
if (inBuffer->nFlags & OMX_BUFFERFLAG_DECODEONLY) {
LOGW("Buffer has OMX_BUFFERFLAG_DECODEONLY flag.");
}
if (firstFrameSize == 0 && inBuffer->nFilledLen != 0 && inBuffer->nTimeStamp != 0) {
if (firstFrame != NULL) {
free(firstFrame);
firstFrame = NULL;
}
firstFrame = (unsigned char *)malloc(inBuffer->nFilledLen);
memcpy(firstFrame, inBuffer->pBuffer + inBuffer->nOffset, inBuffer->nFilledLen);
firstFrameSize = inBuffer->nFilledLen;
}
if ((mWorkingMode == GRAPHICBUFFER_MODE) && (mAPMode == METADATA_MODE) && (!mFormatChanged)) {
bool mRet = mGetFrameResolution(inBuffer->pBuffer + inBuffer->nOffset, inBuffer->nFilledLen,
&mDecodedImageNewWidth,&mDecodedImageNewHeight);
if (mRet && ((mDecodedImageNewWidth != 0) && (mDecodedImageNewHeight != 0)) &&
((mDecodedImageWidth != 0) && (mDecodedImageHeight != 0)) &&
((mDecodedImageNewWidth != mDecodedImageWidth || mDecodedImageNewHeight != mDecodedImageHeight))) {
if (mLastTimeStamp == 0) {
retains[INPORT_INDEX] = BUFFER_RETAIN_GETAGAIN;
HandleFormatChange();
return OMX_ErrorNone;
} else {
// Detected format change in time.
// drain the last frame, keep the current input buffer
mDecoderDecode(mCtx, mHybridCtx, firstFrame, firstFrameSize, false);
retains[INPORT_INDEX] = BUFFER_RETAIN_GETAGAIN;
mFormatChanged = true;
ret = FillRenderBuffer(pBuffers[OUTPORT_INDEX], &retains[OUTPORT_INDEX],
eos ? OMX_BUFFERFLAG_EOS : 0, &isResolutionChange);
if (ret == OMX_ErrorNone)
(*pBuffers[OUTPORT_INDEX])->nTimeStamp = mLastTimeStamp;
mLastTimeStamp = inBuffer->nTimeStamp;
free(firstFrame);
firstFrame = NULL;
firstFrameSize = 0;
return ret;
}
} else if (!mRet && (mDecodedImageNewWidth == 0 || mDecodedImageNewHeight == 0)) {
retains[INPORT_INDEX] = BUFFER_RETAIN_NOT_RETAIN;
return OMX_ErrorBadParameter;
}
}
#if LOG_TIME == 1
struct timeval tv_start, tv_end;
int32_t time_ms;
gettimeofday(&tv_start,NULL);
#endif
int res = mDecoderDecode(mCtx,mHybridCtx,inBuffer->pBuffer + inBuffer->nOffset,inBuffer->nFilledLen, eos);
if (res != 0) {
if (res == -2) {
if (isReallocateNeeded(inBuffer->pBuffer + inBuffer->nOffset,inBuffer->nFilledLen)) {
if (mAPMode == METADATA_MODE) {
mFormatChanged = true;
} else {
retains[INPORT_INDEX] = BUFFER_RETAIN_GETAGAIN;
HandleFormatChange();
return OMX_ErrorNone;
}
}
// drain the last frame, keep the current input buffer
res = mDecoderDecode(mCtx,mHybridCtx,NULL,0,true);
retains[INPORT_INDEX] = BUFFER_RETAIN_GETAGAIN;
} else if (res == -3) {
LOGW("on2 decoder skipped to decode the frame.");
(*pBuffers[OUTPORT_INDEX])->nOffset = 0;
(*pBuffers[OUTPORT_INDEX])->nFilledLen = 0;
return OMX_ErrorNone;
} else {
LOGE("on2 decoder failed to decode frame.");
return OMX_ErrorBadParameter;
}
}
#if LOG_TIME == 1
gettimeofday(&tv_end,NULL);
time_ms = (int32_t)(tv_end.tv_sec - tv_start.tv_sec) * 1000 + (int32_t)(tv_end.tv_usec - tv_start.tv_usec)/1000;
LOGI("vpx_codec_decode: %d ms", time_ms);
#endif
ret = FillRenderBuffer(pBuffers[OUTPORT_INDEX],
&retains[OUTPORT_INDEX],
eos? OMX_BUFFERFLAG_EOS:0,
&isResolutionChange);
if (ret == OMX_ErrorNone) {
(*pBuffers[OUTPORT_INDEX])->nTimeStamp = mLastTimeStamp;
}
mLastTimeStamp = inBuffer->nTimeStamp;
if (isResolutionChange == OMX_TRUE) {
HandleFormatChange();
}
bool inputEoS = ((*pBuffers[INPORT_INDEX])->nFlags & OMX_BUFFERFLAG_EOS);
bool outputEoS = ((*pBuffers[OUTPORT_INDEX])->nFlags & OMX_BUFFERFLAG_EOS);
// if output port is not eos, retain the input buffer
// until all the output buffers are drained.
if (inputEoS && !outputEoS && retains[INPORT_INDEX] != BUFFER_RETAIN_GETAGAIN) {
retains[INPORT_INDEX] = BUFFER_RETAIN_GETAGAIN;
// the input buffer is retained for draining purpose.
// Set nFilledLen to 0 so buffer will not be decoded again.
(*pBuffers[INPORT_INDEX])->nFilledLen = 0;
}
if (ret == OMX_ErrorNotReady) {
retains[OUTPORT_INDEX] = BUFFER_RETAIN_GETAGAIN;
ret = OMX_ErrorNone;
}
return ret;
}
OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::FillRenderBuffer(OMX_BUFFERHEADERTYPE **pBuffer,
buffer_retain_t *retain,
OMX_U32 inportBufferFlags,
OMX_BOOL *isResolutionChange)
{
OMX_BUFFERHEADERTYPE *buffer = *pBuffer;
OMX_BUFFERHEADERTYPE *buffer_orign = buffer;
OMX_ERRORTYPE ret = OMX_ErrorNone;
int fb_index;
if (mWorkingMode == RAWDATA_MODE) {
const OMX_PARAM_PORTDEFINITIONTYPE *paramPortDefinitionOutput
= this->ports[OUTPORT_INDEX]->GetPortDefinition();
int32_t stride = paramPortDefinitionOutput->format.video.nStride;
int32_t height = paramPortDefinitionOutput->format.video.nFrameHeight;
int32_t width = paramPortDefinitionOutput->format.video.nFrameWidth;
unsigned char *dst = buffer->pBuffer;
fb_index = mGetRawDataOutput(mCtx,mHybridCtx,dst,height,stride);
if (fb_index == -1) {
if (inportBufferFlags & OMX_BUFFERFLAG_EOS) {
// eos frame is non-shown frame
buffer->nFlags = OMX_BUFFERFLAG_EOS;
buffer->nOffset = 0;
buffer->nFilledLen = 0;
return OMX_ErrorNone;
}
LOGV("vpx_codec_get_frame return NULL.");
return OMX_ErrorNotReady;
}
buffer->nOffset = 0;
buffer->nFilledLen = stride*height*3/2;
if (inportBufferFlags & OMX_BUFFERFLAG_EOS) {
buffer->nFlags = OMX_BUFFERFLAG_EOS;
}
return OMX_ErrorNone;
}
if (mFormatChanged && mAPMode == METADATA_MODE) {
fb_index = mGetOutput(mCtx,mHybridCtx, &mDecodedImageWidth, &mDecodedImageHeight);
} else {
fb_index = mGetOutput(mCtx,mHybridCtx, &mDecodedImageNewWidth, &mDecodedImageNewHeight);
}
if (fb_index == -1) {
if (mFormatChanged && mAPMode == METADATA_MODE) {
*isResolutionChange = OMX_TRUE;
return OMX_ErrorNone;
}
if (inportBufferFlags & OMX_BUFFERFLAG_EOS) {
// eos frame is no-shown frame
buffer->nFlags = OMX_BUFFERFLAG_EOS;
buffer->nOffset = 0;
buffer->nFilledLen = 0;
return OMX_ErrorNone;
}
LOGV("vpx_codec_get_frame return NULL.");
return OMX_ErrorNotReady;
}
if (mDecodedImageHeight == 0 && mDecodedImageWidth == 0) {
mDecodedImageWidth = mDecodedImageNewWidth;
mDecodedImageHeight = mDecodedImageNewHeight;
if (mAPMode == LEGACY_MODE)
*isResolutionChange = OMX_TRUE;
}
if (mAPMode == LEGACY_MODE) {
if ((mDecodedImageNewWidth != mDecodedImageWidth)
|| (mDecodedImageNewHeight!= mDecodedImageHeight))
*isResolutionChange = OMX_TRUE;
} else {
if (mFormatChanged && ((mDecodedImageNewWidth != mDecodedImageWidth)
|| (mDecodedImageNewHeight!= mDecodedImageHeight)))
*isResolutionChange = OMX_TRUE;
}
buffer = *pBuffer = mOMXBufferHeaderTypePtrArray[fb_index];
buffer->nOffset = 0;
buffer->nFilledLen = sizeof(OMX_U8*);
if (inportBufferFlags & OMX_BUFFERFLAG_EOS) {
buffer->nFlags = OMX_BUFFERFLAG_EOS;
}
if (buffer_orign != buffer) {
*retain = BUFFER_RETAIN_OVERRIDDEN;
}
ret = OMX_ErrorNone;
return ret;
}
OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::PrepareConfigBuffer(VideoConfigBuffer *) {
return OMX_ErrorNone;
}
OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::PrepareDecodeBuffer(OMX_BUFFERHEADERTYPE *,
buffer_retain_t *,
VideoDecodeBuffer *) {
return OMX_ErrorNone;
}
OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::BuildHandlerList(void) {
OMXVideoDecoderBase::BuildHandlerList();
return OMX_ErrorNone;
}
OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::GetParamVideoVp9(OMX_PTR) {
return OMX_ErrorNone;
}
OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::SetParamVideoVp9(OMX_PTR) {
return OMX_ErrorNone;
}
OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::HandleFormatChange(void)
{
ALOGE("handle format change from %dx%d to %dx%d",
mDecodedImageWidth,mDecodedImageHeight,mDecodedImageNewWidth,mDecodedImageNewHeight);
mDecodedImageWidth = mDecodedImageNewWidth;
mDecodedImageHeight = mDecodedImageNewHeight;
// Sync port definition as it may change.
OMX_PARAM_PORTDEFINITIONTYPE paramPortDefinitionInput, paramPortDefinitionOutput;
memcpy(¶mPortDefinitionInput,
this->ports[INPORT_INDEX]->GetPortDefinition(),
sizeof(paramPortDefinitionInput));
memcpy(¶mPortDefinitionOutput,
this->ports[OUTPORT_INDEX]->GetPortDefinition(),
sizeof(paramPortDefinitionOutput));
unsigned int width = mDecodedImageWidth;
unsigned int height = mDecodedImageHeight;
unsigned int stride = mDecodedImageWidth;
unsigned int sliceHeight = mDecodedImageHeight;
unsigned int widthCropped = mDecodedImageWidth;
unsigned int heightCropped = mDecodedImageHeight;
unsigned int strideCropped = widthCropped;
unsigned int sliceHeightCropped = heightCropped;
if (widthCropped == paramPortDefinitionOutput.format.video.nFrameWidth &&
heightCropped == paramPortDefinitionOutput.format.video.nFrameHeight) {
if (mWorkingMode == RAWDATA_MODE) {
LOGW("Change of portsetting is not reported as size is not changed.");
return OMX_ErrorNone;
}
}
if (mAPMode == METADATA_MODE) {
paramPortDefinitionOutput.nBufferCountActual = mNativeBufferCount;
paramPortDefinitionOutput.nBufferCountMin = mNativeBufferCount - 4;
}
paramPortDefinitionInput.format.video.nFrameWidth = width;
paramPortDefinitionInput.format.video.nFrameHeight = height;
paramPortDefinitionInput.format.video.nStride = stride;
paramPortDefinitionInput.format.video.nSliceHeight = sliceHeight;
if (mWorkingMode == RAWDATA_MODE) {
paramPortDefinitionOutput.format.video.nFrameWidth = widthCropped;
paramPortDefinitionOutput.format.video.nFrameHeight = heightCropped;
paramPortDefinitionOutput.format.video.nStride = strideCropped;
paramPortDefinitionOutput.format.video.nSliceHeight = sliceHeightCropped;
} else if (mWorkingMode == GRAPHICBUFFER_MODE) {
// when the width and height ES parse are not larger than allocated graphic buffer in outport,
// there is no need to reallocate graphic buffer,just report the crop info to omx client
if (mAPMode == LEGACY_MODE &&
width <= mGraphicBufferParam.graphicBufferWidth &&
height <= mGraphicBufferParam.graphicBufferHeight) {
this->ports[INPORT_INDEX]->SetPortDefinition(¶mPortDefinitionInput, true);
this->ports[OUTPORT_INDEX]->ReportOutputCrop();
return OMX_ErrorNone;
}
if (mAPMode == METADATA_MODE ||
width > mGraphicBufferParam.graphicBufferWidth ||
height > mGraphicBufferParam.graphicBufferHeight) {
// update the real decoded resolution to outport instead of display resolution
// for graphic buffer reallocation
// when the width and height parsed from ES are larger than allocated graphic buffer in outport,
paramPortDefinitionOutput.format.video.nFrameWidth = width;
paramPortDefinitionOutput.format.video.nFrameHeight = height;
paramPortDefinitionOutput.format.video.eColorFormat = GetOutputColorFormat(
paramPortDefinitionOutput.format.video.nFrameWidth);
paramPortDefinitionOutput.format.video.nStride = stride;
paramPortDefinitionOutput.format.video.nSliceHeight = sliceHeight;
}
}
paramPortDefinitionOutput.bEnabled = (OMX_BOOL)false;
mOMXBufferHeaderTypePtrNum = 0;
mMetaDataBuffersNum = 0;
memset(&mGraphicBufferParam, 0, sizeof(mGraphicBufferParam));
mDeinitDecoder(mHybridCtx);
this->ports[INPORT_INDEX]->SetPortDefinition(¶mPortDefinitionInput, true);
this->ports[OUTPORT_INDEX]->SetPortDefinition(¶mPortDefinitionOutput, true);
this->ports[OUTPORT_INDEX]->ReportPortSettingsChanged();
return OMX_ErrorNone;
}
OMX_COLOR_FORMATTYPE OMXVideoDecoderVP9Hybrid::GetOutputColorFormat(int) {
LOGV("Output color format is HAL_PIXEL_FORMAT_INTEL_YV12.");
return (OMX_COLOR_FORMATTYPE)HAL_PIXEL_FORMAT_INTEL_YV12;
}
OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::GetDecoderOutputCropSpecific(OMX_PTR pStructure) {
OMX_ERRORTYPE ret = OMX_ErrorNone;
OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)pStructure;
CHECK_TYPE_HEADER(rectParams);
if (rectParams->nPortIndex != OUTPORT_INDEX) {
return OMX_ErrorUndefined;
}
const OMX_PARAM_PORTDEFINITIONTYPE *paramPortDefinitionInput
= this->ports[INPORT_INDEX]->GetPortDefinition();
rectParams->nLeft = VPX_DECODE_BORDER;
rectParams->nTop = VPX_DECODE_BORDER;
rectParams->nWidth = paramPortDefinitionInput->format.video.nFrameWidth;
rectParams->nHeight = paramPortDefinitionInput->format.video.nFrameHeight;
return ret;
}
OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::GetNativeBufferUsageSpecific(OMX_PTR pStructure) {
OMX_ERRORTYPE ret;
android::GetAndroidNativeBufferUsageParams *param =
(android::GetAndroidNativeBufferUsageParams*)pStructure;
CHECK_TYPE_HEADER(param);
param->nUsage |= (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_OFTEN
| GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_EXTERNAL_DISP);
return OMX_ErrorNone;
}
OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::SetNativeBufferModeSpecific(OMX_PTR pStructure) {
OMX_ERRORTYPE ret;
android::EnableAndroidNativeBuffersParams *param =
(android::EnableAndroidNativeBuffersParams*)pStructure;
CHECK_TYPE_HEADER(param);
CHECK_PORT_INDEX_RANGE(param);
CHECK_SET_PARAM_STATE();
PortVideo *port = NULL;
port = static_cast<PortVideo *>(this->ports[OUTPORT_INDEX]);
OMX_PARAM_PORTDEFINITIONTYPE port_def;
memcpy(&port_def,port->GetPortDefinition(),sizeof(port_def));
if (!param->enable) {
mWorkingMode = RAWDATA_MODE;
LOGI("Raw data mode is used");
// If it is fallback from native mode the color format has been
// already set to INTEL format.
// We need to set back the default color format and Native stuff.
port_def.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
port_def.format.video.pNativeRender = NULL;
port_def.format.video.pNativeWindow = NULL;
port->SetPortDefinition(&port_def,true);
return OMX_ErrorNone;
}
mWorkingMode = GRAPHICBUFFER_MODE;
port_def.nBufferCountMin = mNativeBufferCount - 4;
port_def.nBufferCountActual = mNativeBufferCount;
port_def.format.video.cMIMEType = (OMX_STRING)VA_VED_RAW_MIME_TYPE;
// add borders for libvpx decode need.
port_def.format.video.nFrameWidth += VPX_DECODE_BORDER * 2;
port_def.format.video.nFrameHeight += VPX_DECODE_BORDER * 2;
mDecodedImageWidth = port_def.format.video.nFrameWidth;
mDecodedImageHeight = port_def.format.video.nFrameHeight;
port_def.format.video.eColorFormat = GetOutputColorFormat(port_def.format.video.nFrameWidth);
port->SetPortDefinition(&port_def,true);
return OMX_ErrorNone;
}
bool OMXVideoDecoderVP9Hybrid::IsAllBufferAvailable(void) {
bool b = ComponentBase::IsAllBufferAvailable();
if (b == false) {
return false;
}
PortVideo *port = NULL;
port = static_cast<PortVideo *>(this->ports[OUTPORT_INDEX]);
const OMX_PARAM_PORTDEFINITIONTYPE* port_def = port->GetPortDefinition();
// if output port is disabled, retain the input buffer
if (!port_def->bEnabled) {
return false;
}
return mCheckBufferAvailable(mHybridCtx);
}
DECLARE_OMX_COMPONENT("OMX.Intel.VideoDecoder.VP9.hybrid", "video_decoder.vp9", OMXVideoDecoderVP9Hybrid);