diff options
-rw-r--r-- | Android.mk | 3 | ||||
-rw-r--r-- | videocodec/Android.mk | 49 | ||||
-rw-r--r-- | videocodec/OMXVideoDecoderVP9Hybrid.cpp | 360 | ||||
-rw-r--r-- | videocodec/OMXVideoDecoderVP9Hybrid.h | 88 |
4 files changed, 496 insertions, 4 deletions
@@ -8,5 +8,4 @@ INTEL_OMX_COMPONENT_ROOT := $(LOCAL_PATH) #intel video codecs include $(INTEL_OMX_COMPONENT_ROOT)/videocodec/Android.mk include $(INTEL_OMX_COMPONENT_ROOT)/videocodec/libvpx_internal/Android.mk - -endif +endif #BOARD_USES_MRST_OMX diff --git a/videocodec/Android.mk b/videocodec/Android.mk index 3eef8c9..d63b83b 100644 --- a/videocodec/Android.mk +++ b/videocodec/Android.mk @@ -189,10 +189,55 @@ LOCAL_CFLAGS += -DUSE_GEN_HW endif include $(BUILD_SHARED_LIBRARY) -################################################################################ - +# VP9 hybrid decoder and HW Render +ifeq ($(TARGET_BOARD_PLATFORM),moorefield) include $(CLEAR_VARS) +ifeq ($(TARGET_HAS_VPP),true) +LOCAL_CFLAGS += -DTARGET_HAS_VPP +endif +LOCAL_SHARED_LIBRARIES := \ + libui \ + libwrs_omxil_common \ + liblog \ + libva_videodecoder \ + libdl \ + +LOCAL_C_INCLUDES := \ + $(TARGET_OUT_HEADERS)/wrs_omxil_core \ + $(TARGET_OUT_HEADERS)/khronos/openmax \ + $(TARGET_OUT_HEADERS)/libmix_videodecoder \ + $(TARGET_OUT_HEADERS)/libva \ + $(call include-path-for, frameworks-native)/media/hardware \ + $(call include-path-for, frameworks-native)/media/openmax + +ifeq ($(TARGET_BOARD_PLATFORM),baytrail) + LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/ufo +endif +LOCAL_SRC_FILES := \ + OMXComponentCodecBase.cpp\ + OMXVideoDecoderBase.cpp\ + OMXVideoDecoderVP9Hybrid.cpp + +LOCAL_CFLAGS += -Werror +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE := libOMXVideoDecoderVP9Hybrid + +ifeq ($(TARGET_BOARD_PLATFORM),merrifield) +LOCAL_CFLAGS += -DVED_TILING +endif + +ifeq ($(TARGET_BOARD_PLATFORM),moorefield) +LOCAL_CFLAGS += -DVED_TILING +endif + +ifeq ($(TARGET_BOARD_PLATFORM),baytrail) +LOCAL_CFLAGS += -DUSE_GEN_HW +endif +include $(BUILD_SHARED_LIBRARY) +endif + +include $(CLEAR_VARS) ifeq ($(TARGET_HAS_VPP),true) LOCAL_CFLAGS += -DTARGET_HAS_VPP endif diff --git a/videocodec/OMXVideoDecoderVP9Hybrid.cpp b/videocodec/OMXVideoDecoderVP9Hybrid.cpp new file mode 100644 index 0000000..e1ff00d --- /dev/null +++ b/videocodec/OMXVideoDecoderVP9Hybrid.cpp @@ -0,0 +1,360 @@ +/* +* 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 <system/window.h> +#include <hardware/hardware.h> +#include <hardware/gralloc.h> +#include <system/graphics.h> + +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; +} + +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) { + unsigned int buff[MAX_GRAPHIC_BUFFER_NUM]; + unsigned int i; + int bufferSize = mGraphicBufferParam.graphicBufferStride * + mGraphicBufferParam.graphicBufferHeight * 1.5; + int bufferStride = mGraphicBufferParam.graphicBufferStride; + + for (i = 0; i < mOMXBufferHeaderTypePtrNum; i++ ) { + OMX_BUFFERHEADERTYPE *buf_hdr = mOMXBufferHeaderTypePtrArray[i]; + buff[i] = (unsigned int)(buf_hdr->pBuffer); + } + + 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"); + if (mOpenDecoder == NULL || mCloseDecoder == NULL + || mInitDecoder == NULL || mSingalRenderDone == NULL + || mDecoderDecode == NULL || mCheckBufferAvailable == NULL + || mGetOutput == NULL) { + return OMX_ErrorBadParameter; + } + + if (mOpenDecoder(&mCtx,&mHybridCtx) == false) { + LOGE("open hybrid Decoder fail\n"); + return OMX_ErrorBadParameter; + } + + mInitDecoder(mHybridCtx,bufferSize,bufferStride,mOMXBufferHeaderTypePtrNum, buff); + return OMX_ErrorNone; +} + +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) { + return OMX_ErrorNone; +} + +OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::ProcessorPreFillBuffer(OMX_BUFFERHEADERTYPE* buffer) { + unsigned int handle = (unsigned int)buffer->pBuffer; + unsigned int i = 0; + + if (buffer->nOutputPortIndex == OUTPORT_INDEX){ + mSingalRenderDone(handle); + } + 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]; + + 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 (inBuffer->nFlags & OMX_BUFFERFLAG_EOS) { + if (inBuffer->nFilledLen == 0) { + (*pBuffers[OUTPORT_INDEX])->nFilledLen = 0; + (*pBuffers[OUTPORT_INDEX])->nFlags = OMX_BUFFERFLAG_EOS; + return OMX_ErrorNone; + } + } + +#if LOG_TIME == 1 + struct timeval tv_start, tv_end; + int32_t time_ms; + gettimeofday(&tv_start,NULL); +#endif + if (mDecoderDecode(mCtx,mHybridCtx,inBuffer->pBuffer + inBuffer->nOffset,inBuffer->nFilledLen) == false) { + 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], + ((*pBuffers[INPORT_INDEX]))->nFlags); + + if (ret == OMX_ErrorNone) { + (*pBuffers[OUTPORT_INDEX])->nTimeStamp = inBuffer->nTimeStamp; + } + + 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; + // 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; +} + +static int ALIGN(int x, int y) { + // y must be a power of 2. + return (x + y - 1) & ~(y - 1); +} + +OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::FillRenderBuffer(OMX_BUFFERHEADERTYPE **pBuffer, + buffer_retain_t *retain, + OMX_U32 inportBufferFlags) +{ + OMX_BUFFERHEADERTYPE *buffer = *pBuffer; + OMX_BUFFERHEADERTYPE *buffer_orign = buffer; + + OMX_ERRORTYPE ret = OMX_ErrorNone; + + if (mWorkingMode != GRAPHICBUFFER_MODE) { + LOGE("Working Mode is not GRAPHICBUFFER_MODE"); + ret = OMX_ErrorBadParameter; + } + int fb_index = mGetOutput(mCtx); + if (fb_index == -1) { + LOGE("vpx_codec_get_frame return NULL."); + return OMX_ErrorNotReady; + } + + buffer = *pBuffer = mOMXBufferHeaderTypePtrArray[fb_index]; + + size_t dst_y_size = mGraphicBufferParam.graphicBufferStride * + mGraphicBufferParam.graphicBufferHeight; + size_t dst_c_stride = ALIGN(mGraphicBufferParam.graphicBufferStride / 2, 16); + size_t dst_c_size = dst_c_stride * mGraphicBufferParam.graphicBufferHeight / 2; + 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_COLOR_FORMATTYPE OMXVideoDecoderVP9Hybrid::GetOutputColorFormat(int) { + LOGV("Output color format is HAL_PIXEL_FORMAT_YV12."); + return (OMX_COLOR_FORMATTYPE)HAL_PIXEL_FORMAT_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_NEVER \ + | 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(); + + if (!param->enable) { + mWorkingMode = RAWDATA_MODE; + return OMX_ErrorNone; + } + mWorkingMode = GRAPHICBUFFER_MODE; + PortVideo *port = NULL; + port = static_cast<PortVideo *>(this->ports[OUTPORT_INDEX]); + + OMX_PARAM_PORTDEFINITIONTYPE port_def; + memcpy(&port_def,port->GetPortDefinition(),sizeof(port_def)); + port_def.nBufferCountMin = mNativeBufferCount; + port_def.nBufferCountActual = mNativeBufferCount; + port_def.format.video.cMIMEType = (OMX_STRING)VA_VED_RAW_MIME_TYPE; + port_def.format.video.eColorFormat = (OMX_COLOR_FORMATTYPE)OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar; + // add borders for libvpx decode need. + port_def.format.video.nFrameHeight += VPX_DECODE_BORDER * 2; + port_def.format.video.nFrameWidth += VPX_DECODE_BORDER * 2; + // make heigth 32bit align + port_def.format.video.nFrameHeight = (port_def.format.video.nFrameHeight + 0x1f) & ~0x1f; + 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(); +} + +DECLARE_OMX_COMPONENT("OMX.Intel.VideoDecoder.VP9.hybrid", "video_decoder.vp9", OMXVideoDecoderVP9Hybrid); diff --git a/videocodec/OMXVideoDecoderVP9Hybrid.h b/videocodec/OMXVideoDecoderVP9Hybrid.h new file mode 100644 index 0000000..68b06c1 --- /dev/null +++ b/videocodec/OMXVideoDecoderVP9Hybrid.h @@ -0,0 +1,88 @@ +/* +* 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. +*/ + + + +#ifndef OMX_VIDEO_DECODER_VP9_HYBRID_H_ +#define OMX_VIDEO_DECODER_VP9_HYBRID_H_ + +#include "OMXVideoDecoderBase.h" +#include <dlfcn.h> +#define VPX_DECODE_BORDER 0 + +class OMXVideoDecoderVP9Hybrid : public OMXVideoDecoderBase { +public: + OMXVideoDecoderVP9Hybrid(); + virtual ~OMXVideoDecoderVP9Hybrid(); + +protected: + virtual OMX_ERRORTYPE InitInputPortFormatSpecific(OMX_PARAM_PORTDEFINITIONTYPE *paramPortDefinitionInput); + virtual OMX_ERRORTYPE ProcessorInit(void); + virtual OMX_ERRORTYPE ProcessorDeinit(void); + virtual OMX_ERRORTYPE ProcessorStop(void); + virtual OMX_ERRORTYPE ProcessorFlush(OMX_U32 portIndex); + virtual OMX_ERRORTYPE ProcessorProcess( + OMX_BUFFERHEADERTYPE ***pBuffers, + buffer_retain_t *retains, + OMX_U32 numberBuffers); + + virtual OMX_ERRORTYPE ProcessorPreFillBuffer(OMX_BUFFERHEADERTYPE* buffer); + virtual bool IsAllBufferAvailable(void); + + virtual OMX_ERRORTYPE PrepareConfigBuffer(VideoConfigBuffer *p); + virtual OMX_ERRORTYPE PrepareDecodeBuffer(OMX_BUFFERHEADERTYPE *buffer, buffer_retain_t *retain, VideoDecodeBuffer *p); + + virtual OMX_ERRORTYPE BuildHandlerList(void); + + virtual OMX_ERRORTYPE FillRenderBuffer(OMX_BUFFERHEADERTYPE **pBuffer, buffer_retain_t *retain, OMX_U32 inportBufferFlags); + + virtual OMX_COLOR_FORMATTYPE GetOutputColorFormat(int width); + virtual OMX_ERRORTYPE GetDecoderOutputCropSpecific(OMX_PTR pStructure); + virtual OMX_ERRORTYPE GetNativeBufferUsageSpecific(OMX_PTR pStructure); + virtual OMX_ERRORTYPE SetNativeBufferModeSpecific(OMX_PTR pStructure); + + DECLARE_HANDLER(OMXVideoDecoderVP9Hybrid, ParamVideoVp9); + +private: + void *mCtx; + void *mHybridCtx; + void *mLibHandle; + typedef bool (*OpenFunc)(void ** , void **); + typedef bool (*InitFunc)(void *,unsigned int, unsigned int, int, unsigned int *); + typedef bool (*CloseFunc)(void *, void *); + typedef bool (*SingalRenderDoneFunc)(unsigned int); + typedef bool (*DecodeFunc)(void *, void *, unsigned char *, unsigned int); + typedef bool (*IsBufferAvailableFunc)(); + typedef int (*GetOutputFunc)(void *); + OpenFunc mOpenDecoder; + InitFunc mInitDecoder; + CloseFunc mCloseDecoder; + SingalRenderDoneFunc mSingalRenderDone; + DecodeFunc mDecoderDecode; + IsBufferAvailableFunc mCheckBufferAvailable; + GetOutputFunc mGetOutput; + enum { + // OMX_PARAM_PORTDEFINITIONTYPE + INPORT_MIN_BUFFER_COUNT = 1, + INPORT_ACTUAL_BUFFER_COUNT = 5, + INPORT_BUFFER_SIZE = 1382400, + OUTPORT_NATIVE_BUFFER_COUNT = 12, // 8 reference + 1 current + 3 for asynchronized mode + }; + +}; + +#endif + |