Add ISV support to fugu
Intel Smart Video (ISV) component is a video post processing component.
It implements frame rate conversion and sharpen.
Bug: 17383204
BZ: 227971
Change-Id: Ia020258dff0d8cb96d8625d2cfa8a4a6c4045527
Signed-off-by: Xigui Wang <xigui.wang@intel.com>
Depends-On: I9b22da03ea3f2a7d9dd85042fff442d2414cbc26
diff --git a/ISV/Android.mk b/ISV/Android.mk
new file mode 100644
index 0000000..12965a9
--- /dev/null
+++ b/ISV/Android.mk
@@ -0,0 +1,49 @@
+ifeq ($(TARGET_HAS_ISV),true)
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ omx/isv_omxcore.cpp \
+ omx/isv_omxcomponent.cpp \
+ base/isv_bufmanager.cpp \
+ base/isv_processor.cpp \
+ base/isv_worker.cpp \
+ profile/isv_profile.cpp
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := libisv_omx_core
+LOCAL_32_BIT_ONLY := true
+
+LOCAL_SHARED_LIBRARIES := \
+ libutils \
+ libcutils \
+ libdl \
+ libhardware \
+ libexpat \
+ libva \
+ libva-android
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/include \
+ $(call include-path-for, frameworks-openmax) \
+ $(TARGET_OUT_HEADERS)/libmedia_utils_vpp \
+ $(TARGET_OUT_HEADERS)/display \
+ $(TARGET_OUT_HEADERS)/khronos/openmax \
+ $(TARGET_OUT_HEADERS)/libva \
+ $(TARGET_OUT_HEADERS)/pvr/hal \
+ $(call include-path-for, frameworks-native)/media/openmax
+
+ifeq ($(USE_MEDIASDK),true)
+ LOCAL_CFLAGS += -DUSE_MEDIASDK
+endif
+
+ifeq ($(TARGET_VPP_USE_GEN),true)
+ LOCAL_CFLAGS += -DTARGET_VPP_USE_GEN
+endif
+
+LOCAL_CFLAGS += -Werror
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/ISV/base/isv_bufmanager.cpp b/ISV/base/isv_bufmanager.cpp
new file mode 100644
index 0000000..f0fdc42
--- /dev/null
+++ b/ISV/base/isv_bufmanager.cpp
@@ -0,0 +1,198 @@
+/*
+ * 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 <media/hardware/HardwareAPI.h>
+#include <system/graphics.h>
+#include "isv_bufmanager.h"
+#include "hal_public.h"
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "isv-omxil"
+
+using namespace android;
+
+ISVBuffer::~ISVBuffer() {
+ if (mWorker != NULL) {
+ ALOGV("%s: mSurface %d", __func__, mSurface);
+ mWorker->freeSurface(&mSurface);
+ }
+}
+
+status_t ISVBuffer::initBufferInfo()
+{
+ if (mType == ISV_BUFFER_METADATA) {
+ VideoDecoderOutputMetaData *metaData =
+ reinterpret_cast<VideoDecoderOutputMetaData*>(mBuffer);
+
+ if (metaData->eType != kMetadataBufferTypeGrallocSource) {
+ ALOGE("%s: unsupported meta data format eType = %d", __func__, metaData->eType);
+ return UNKNOWN_ERROR;
+ }
+
+ if (mGrallocHandle != 0) {
+ if ((uint32_t)metaData->pHandle != mGrallocHandle) {
+ if (STATUS_OK != mWorker->freeSurface(&mSurface)) {
+ ALOGE("%s: free surface %d failed.", __func__, mSurface);
+ return UNKNOWN_ERROR;
+ }
+ } else
+ return OK;
+ }
+ mGrallocHandle = (uint32_t)metaData->pHandle;
+ } else {
+ if (mSurface != -1)
+ return OK;
+ mGrallocHandle = mBuffer;
+ }
+
+#ifdef TARGET_VPP_USE_GEN
+ gralloc_module_t* pGralloc = NULL;
+ ufo_buffer_details_t info;
+
+ memset(&info, 0, sizeof(ufo_buffer_details_t));
+ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, (hw_module_t const**)&pGralloc);
+ if (!pGralloc) err = -1;
+ if (0 == err)
+ err = pGralloc->perform(pGralloc, INTEL_UFO_GRALLOC_MODULE_PERFORM_GET_BO_INFO, handle, &info);
+
+ if (0 != err)
+ {
+ ALOGE("%s: can't get graphic buffer info", __func__);
+ }
+ mWidth = info.width;
+ mHeight = info.height;
+ mStride = info.pitch;
+ mColorFormat = info.format;
+#else
+ IMG_native_handle_t* grallocHandle = (IMG_native_handle_t*)mGrallocHandle;
+ mStride = grallocHandle->iWidth;
+ mColorFormat = grallocHandle->iFormat;
+#endif
+
+ //FIXME: currently, VSP doesn't support YV12 format very well, so diable ISV temporarily
+ if (mColorFormat == HAL_PIXEL_FORMAT_YV12) {
+ ALOGI("%s: VSP doesn't support YV12 very well, so disable ISV", __func__);
+ return BAD_TYPE;
+ }
+
+ if (mWorker == NULL) {
+ ALOGE("%s: mWorker == NULL!!", __func__);
+ return UNKNOWN_ERROR;
+ }
+
+ if (STATUS_OK != mWorker->allocSurface(&mWidth, &mHeight, mStride, mColorFormat, mGrallocHandle, &mSurface)) {
+ ALOGE("%s: alloc surface failed, mGrallocHandle %p", __func__, mGrallocHandle);
+ return UNKNOWN_ERROR;
+ }
+
+ ALOGD_IF(ISV_BUFFER_MANAGER_DEBUG, "%s: mWidth %d, mHeight %d, mStride %d, mColorFormat %d, mGrallocHandle %p, mSurface %d",
+ __func__, mWidth, mHeight, mStride, mColorFormat, mGrallocHandle, mSurface);
+ return OK;
+}
+
+status_t ISVBufferManager::setBufferCount(int32_t size)
+{
+ Mutex::Autolock autoLock(mBufferLock);
+#if 0
+ if (!mBuffers.isEmpty()) {
+ ALOGE("%s: the buffer queue should be empty before we set its size", __func__);
+ return STATUS_ERROR;
+ }
+#endif
+ mBuffers.setCapacity(size);
+
+ return OK;
+}
+
+status_t ISVBufferManager::freeBuffer(uint32_t handle)
+{
+ Mutex::Autolock autoLock(mBufferLock);
+ for (uint32_t i = 0; i < mBuffers.size(); i++) {
+ ISVBuffer* isvBuffer = mBuffers.itemAt(i);
+ if (isvBuffer->getHandle() == (uint32_t)handle) {
+ delete isvBuffer;
+ mBuffers.removeAt(i);
+ ALOGD_IF(ISV_BUFFER_MANAGER_DEBUG, "%s: remove handle 0x%08x, and then mBuffers.size() %d", __func__,
+ handle, mBuffers.size());
+ return OK;
+ }
+ }
+
+ ALOGW("%s: can't find buffer %u", __func__, handle);
+ return UNKNOWN_ERROR;
+}
+
+status_t ISVBufferManager::useBuffer(uint32_t handle)
+{
+ Mutex::Autolock autoLock(mBufferLock);
+ if (handle == 0 || mBuffers.size() >= mBuffers.capacity())
+ return BAD_VALUE;
+
+ for (uint32_t i = 0; i < mBuffers.size(); i++) {
+ ISVBuffer* isvBuffer = mBuffers.itemAt(i);
+ if (isvBuffer->getHandle() == (uint32_t)handle) {
+ ALOGE("%s: this buffer 0x%08x has already been registered", __func__, handle);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ ISVBuffer* isvBuffer = new ISVBuffer(mWorker, handle, mMetaDataMode ? ISVBuffer::ISV_BUFFER_METADATA : ISVBuffer::ISV_BUFFER_GRALLOC);
+
+ ALOGD_IF(ISV_BUFFER_MANAGER_DEBUG, "%s: add handle 0x%08x, and then mBuffers.size() %d", __func__,
+ handle, mBuffers.size());
+ mBuffers.push_back(isvBuffer);
+ return OK;
+
+}
+
+status_t ISVBufferManager::useBuffer(const sp<ANativeWindowBuffer> nativeBuffer)
+{
+ Mutex::Autolock autoLock(mBufferLock);
+ if (nativeBuffer == NULL || mBuffers.size() >= mBuffers.capacity())
+ return BAD_VALUE;
+
+ for (uint32_t i = 0; i < mBuffers.size(); i++) {
+ ISVBuffer* isvBuffer = mBuffers.itemAt(i);
+ if (isvBuffer->getHandle() == (uint32_t)nativeBuffer->handle) {
+ ALOGE("%s: this buffer 0x%08x has already been registered", __func__, nativeBuffer->handle);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ ISVBuffer* isvBuffer = new ISVBuffer(mWorker,
+ (uint32_t)nativeBuffer->handle, (uint32_t)nativeBuffer->handle,
+ nativeBuffer->width, nativeBuffer->height,
+ nativeBuffer->stride, nativeBuffer->format,
+ mMetaDataMode ? ISVBuffer::ISV_BUFFER_METADATA : ISVBuffer::ISV_BUFFER_GRALLOC);
+
+ ALOGD_IF(ISV_BUFFER_MANAGER_DEBUG, "%s: add handle 0x%08x, and then mBuffers.size() %d", __func__,
+ nativeBuffer->handle, mBuffers.size());
+ mBuffers.push_back(isvBuffer);
+ return OK;
+}
+
+ISVBuffer* ISVBufferManager::mapBuffer(uint32_t handle)
+{
+ Mutex::Autolock autoLock(mBufferLock);
+ for (uint32_t i = 0; i < mBuffers.size(); i++) {
+ ISVBuffer* isvBuffer = mBuffers.itemAt(i);
+ if (isvBuffer->getHandle() == (uint32_t)handle)
+ return isvBuffer;
+ }
+ return NULL;
+}
diff --git a/ISV/base/isv_processor.cpp b/ISV/base/isv_processor.cpp
new file mode 100644
index 0000000..1bff29d
--- /dev/null
+++ b/ISV/base/isv_processor.cpp
@@ -0,0 +1,578 @@
+/*
+ * 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 <math.h>
+#include <utils/Errors.h>
+#include "isv_processor.h"
+#include "isv_profile.h"
+#include "isv_omxcomponent.h"
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "isv-omxil"
+
+using namespace android;
+
+#define MAX_RETRY_NUM 8
+
+ISVProcessor::ISVProcessor(bool canCallJava,
+ sp<ISVBufferManager> bufferManager,
+ sp<ISVProcessorObserver> owner,
+ uint32_t width, uint32_t height)
+ :Thread(canCallJava),
+ mpOwner(owner),
+ mThreadId(NULL),
+ mThreadRunning(false),
+ mISVWorker(NULL),
+ mBufferManager(bufferManager),
+ mOutputProcIdx(0),
+ mInputProcIdx(0),
+ mNumTaskInProcesing(0),
+ mNumRetry(0),
+ mLastTimeStamp(0),
+ mError(false),
+ mbFlush(false),
+ mbBypass(false),
+ mFlagEnd(false),
+ mFilters(0)
+{
+ //FIXME: for 1920 x 1088, we also consider it as 1080p
+ mISVProfile = new ISVProfile(width, (height == 1088) ? 1080 : height);
+
+ // get platform ISV cap first
+ mFilters = mISVProfile->getFilterStatus();
+
+ // turn off filters if dynamic vpp/frc setting is off
+ if (!ISVProfile::isVPPOn())
+ mFilters &= FilterFrameRateConversion;
+
+ if (!ISVProfile::isFRCOn())
+ mFilters &= ~FilterFrameRateConversion;
+
+ //FIXME: move this into profile.
+ if (width > 2048)
+ mFilters &= ~FilterSharpening;
+
+ memset(&mFilterParam, 0, sizeof(mFilterParam));
+ //FIXME: we don't support scaling yet, so set src region equal to dst region
+ mFilterParam.srcWidth = mFilterParam.dstWidth = width;
+ mFilterParam.srcHeight = mFilterParam.dstHeight = height;
+ mOutputBuffers.clear();
+ mInputBuffers.clear();
+}
+
+ISVProcessor::~ISVProcessor() {
+ ALOGV("ISVProcessor is deleted");
+ flush();
+ mOutputBuffers.clear();
+ mInputBuffers.clear();
+
+ mISVProfile = NULL;
+ mFilters = 0;
+ memset(&mFilterParam, 0, sizeof(mFilterParam));
+}
+
+status_t ISVProcessor::readyToRun()
+{
+ mThreadId = androidGetThreadId();
+ //do init ops here
+ return Thread::readyToRun();
+}
+
+void ISVProcessor::start()
+{
+ ALOGD_IF(ISV_THREAD_DEBUG, "ISVProcessor::start");
+
+ if (mISVWorker == NULL) {
+ mISVWorker = new ISVWorker();
+ if (STATUS_OK != mISVWorker->init(mFilterParam.srcWidth, mFilterParam.srcHeight))
+ ALOGE("%s: mISVWorker init failed", __func__);
+ }
+
+ mBufferManager->setWorker(mISVWorker);
+
+ this->run("ISVProcessor", ANDROID_PRIORITY_NORMAL);
+ mThreadRunning = true;
+ return;
+}
+
+void ISVProcessor::stop()
+{
+ ALOGD_IF(ISV_THREAD_DEBUG, "ISVProcessor::stop");
+
+ if(mThreadRunning) {
+ this->requestExit();
+ {
+ Mutex::Autolock autoLock(mLock);
+ mRunCond.signal();
+ }
+ this->requestExitAndWait();
+ mThreadRunning = false;
+ }
+
+ if (STATUS_OK != mISVWorker->deinit())
+ ALOGE("%s: mISVWorker deinit failed", __func__);
+
+ mISVWorker = NULL;
+ return;
+}
+
+bool ISVProcessor::getBufForFirmwareOutput(Vector<ISVBuffer*> *fillBufList,uint32_t *fillBufNum){
+ uint32_t i = 0;
+ // output buffer number for filling
+ *fillBufNum = 0;
+ uint32_t needFillNum = 0;
+ OMX_BUFFERHEADERTYPE *outputBuffer;
+
+ //output data available
+ needFillNum = mISVWorker->getFillBufCount();
+ if (mOutputProcIdx < needFillNum ||
+ mInputProcIdx < 1) {
+ ALOGE("%s: no enough input or output buffer which need to be sync", __func__);
+ return false;
+ }
+
+ if ((needFillNum == 0) || (needFillNum > 4))
+ return false;
+
+ Mutex::Autolock autoLock(mOutputLock);
+ for (i = 0; i < needFillNum; i++) {
+ //fetch the render buffer from the top of output buffer queue
+ outputBuffer = mOutputBuffers.itemAt(i);
+ uint32_t fillHandle = reinterpret_cast<uint32_t>(outputBuffer->pBuffer);
+ ISVBuffer* fillBuf = mBufferManager->mapBuffer(fillHandle);
+ fillBufList->push_back(fillBuf);
+ }
+
+ *fillBufNum = i;
+ return true;
+}
+
+
+status_t ISVProcessor::updateFirmwareOutputBufStatus(uint32_t fillBufNum) {
+ int64_t timeUs;
+ OMX_BUFFERHEADERTYPE *outputBuffer;
+ OMX_BUFFERHEADERTYPE *inputBuffer;
+ OMX_ERRORTYPE err;
+
+ if (mInputBuffers.empty()) {
+ ALOGE("%s: input buffer queue is empty. no buffer need to be sync", __func__);
+ return UNKNOWN_ERROR;
+ }
+
+ if (mOutputBuffers.size() < fillBufNum) {
+ ALOGE("%s: no enough output buffer which need to be sync", __func__);
+ return UNKNOWN_ERROR;
+ }
+ // remove one buffer from intput buffer queue
+ {
+ Mutex::Autolock autoLock(mInputLock);
+ inputBuffer = mInputBuffers.itemAt(0);
+ err = mpOwner->releaseBuffer(kPortIndexInput, inputBuffer, false);
+ if (err != OMX_ErrorNone) {
+ ALOGE("%s: failed to fillInputBuffer", __func__);
+ return UNKNOWN_ERROR;
+ }
+
+ mInputBuffers.removeAt(0);
+ ALOGD_IF(ISV_THREAD_DEBUG, "%s: fetch buffer %u from input buffer queue for fill to decoder, and then queue size is %d", __func__,
+ inputBuffer, mInputBuffers.size());
+ mInputProcIdx--;
+ }
+
+ //set the time stamp for interpreted frames
+ {
+ Mutex::Autolock autoLock(mOutputLock);
+ timeUs = mOutputBuffers[0]->nTimeStamp;
+
+ for(uint32_t i = 0; i < fillBufNum; i++) {
+ outputBuffer = mOutputBuffers.itemAt(i);
+ if (fillBufNum > 1) {
+ if(mFilterParam.frameRate == 15)
+ outputBuffer->nTimeStamp = timeUs - 1000000ll * (fillBufNum - i - 1) / 30;
+ else
+ outputBuffer->nTimeStamp = timeUs - 1000000ll * (fillBufNum - i - 1) / 60;
+ }
+
+ //return filled buffers for rendering
+ err = mpOwner->releaseBuffer(kPortIndexOutput, outputBuffer, false);
+ if (err != OMX_ErrorNone) {
+ ALOGE("%s: failed to releaseOutputBuffer", __func__);
+ return UNKNOWN_ERROR;
+ }
+
+ ALOGD_IF(ISV_THREAD_DEBUG, "%s: fetch buffer %u(timestamp %.2f ms) from output buffer queue for render, and then queue size is %d", __func__,
+ outputBuffer, outputBuffer->nTimeStamp/1E3, mOutputBuffers.size());
+ }
+ // remove filled buffers from output buffer queue
+ mOutputBuffers.removeItemsAt(0, fillBufNum);
+ mOutputProcIdx -= fillBufNum;
+ }
+ return OK;
+}
+
+
+bool ISVProcessor::getBufForFirmwareInput(Vector<ISVBuffer*> *procBufList,
+ ISVBuffer **inputBuf,
+ uint32_t *procBufNum)
+{
+ OMX_BUFFERHEADERTYPE *outputBuffer;
+ OMX_BUFFERHEADERTYPE *inputBuffer;
+
+ int32_t procBufCount = mISVWorker->getProcBufCount();
+ if ((procBufCount == 0) || (procBufCount > 4)) {
+ return false;
+ }
+
+ //fetch a input buffer for processing
+ {
+ ALOGD_IF(ISV_COMPONENT_LOCK_DEBUG, "%s: acqiring mInputLock", __func__);
+ Mutex::Autolock autoLock(mInputLock);
+ ALOGD_IF(ISV_COMPONENT_LOCK_DEBUG, "%s: acqired mInputLock", __func__);
+ if (mbFlush) {
+ procBufCount = 1;
+ *inputBuf = NULL;
+ } else {
+ inputBuffer = mInputBuffers.itemAt(mInputProcIdx);
+ uint32_t inputHandle = reinterpret_cast<uint32_t>(inputBuffer->pBuffer);
+ *inputBuf = mBufferManager->mapBuffer(inputHandle);
+ }
+ ALOGD_IF(ISV_COMPONENT_LOCK_DEBUG, "%s: releasing mInputLock", __func__);
+ }
+
+ //fetch output buffers for processing
+ {
+ ALOGD_IF(ISV_COMPONENT_LOCK_DEBUG, "%s: acqiring mOutputLock", __func__);
+ Mutex::Autolock autoLock(mOutputLock);
+ ALOGD_IF(ISV_COMPONENT_LOCK_DEBUG, "%s: acqired mOutputLock", __func__);
+ if (mbFlush) {
+ outputBuffer = mOutputBuffers.itemAt(0);
+ uint32_t outputHandle = reinterpret_cast<uint32_t>(outputBuffer->pBuffer);
+ procBufList->push_back(mBufferManager->mapBuffer(outputHandle));
+ } else {
+ for (int32_t i = 0; i < procBufCount; i++) {
+ outputBuffer = mOutputBuffers.itemAt(mOutputProcIdx + i);
+ uint32_t outputHandle = reinterpret_cast<uint32_t>(outputBuffer->pBuffer);
+ procBufList->push_back(mBufferManager->mapBuffer(outputHandle));
+ }
+ }
+ *procBufNum = procBufCount;
+ ALOGD_IF(ISV_COMPONENT_LOCK_DEBUG, "%s: releasing mOutputLock", __func__);
+ }
+
+ return true;
+}
+
+
+status_t ISVProcessor::updateFirmwareInputBufStatus(uint32_t procBufNum)
+{
+ OMX_BUFFERHEADERTYPE *outputBuffer;
+ OMX_BUFFERHEADERTYPE *inputBuffer;
+
+ inputBuffer = mInputBuffers.itemAt(mInputProcIdx);
+ mInputProcIdx++;
+
+ Mutex::Autolock autoLock(mOutputLock);
+ for(uint32_t i = 0; i < procBufNum; i++) {
+ outputBuffer = mOutputBuffers.editItemAt(mOutputProcIdx + i);
+ // set output buffer timestamp as the same as input
+ outputBuffer->nTimeStamp = inputBuffer->nTimeStamp;
+ outputBuffer->nFilledLen = inputBuffer->nFilledLen;
+ outputBuffer->nOffset = inputBuffer->nOffset;
+ outputBuffer->nFlags = inputBuffer->nFlags;
+ //outputBuffer->nTickCount = inputBuffer->nTickCount;
+ //outputBuffer->pMarkData = intputBuffer->pMarkData;
+ }
+ mOutputProcIdx += procBufNum;
+ return OK;
+}
+
+
+bool ISVProcessor::isReadytoRun()
+{
+ ALOGD_IF(ISV_THREAD_DEBUG, "%s: mISVWorker->getProcBufCount() return %d", __func__,
+ mISVWorker->getProcBufCount());
+ if (mInputProcIdx < mInputBuffers.size()
+ && (mOutputBuffers.size() - mOutputProcIdx) >= mISVWorker->getProcBufCount())
+ return true;
+ else
+ return false;
+}
+
+
+bool ISVProcessor::threadLoop() {
+ uint32_t procBufNum = 0, fillBufNum = 0;
+ ISVBuffer* inputBuf;
+ Vector<ISVBuffer*> procBufList;
+ Vector<ISVBuffer*> fillBufList;
+ uint32_t flags = 0;
+ bool bGetBufSuccess = true;
+
+ Mutex::Autolock autoLock(mLock);
+
+ if (!isReadytoRun() && !mbFlush) {
+ mRunCond.wait(mLock);
+ }
+
+ if (isReadytoRun() || mbFlush) {
+ procBufList.clear();
+ bool bGetInBuf = getBufForFirmwareInput(&procBufList, &inputBuf, &procBufNum);
+ if (bGetInBuf) {
+ if (!mbFlush)
+ flags = mInputBuffers[mInputProcIdx]->nFlags;
+ status_t ret = mISVWorker->process(inputBuf, procBufList, procBufNum, mbFlush, flags);
+ // for seek and EOS
+ if (mbFlush) {
+ mISVWorker->reset();
+ flush();
+
+ mNumTaskInProcesing = 0;
+ mInputProcIdx = 0;
+ mOutputProcIdx = 0;
+
+ mbFlush = false;
+
+ Mutex::Autolock endLock(mEndLock);
+ mEndCond.signal();
+ return true;
+ }
+ if (ret == STATUS_OK) {
+ mNumTaskInProcesing++;
+ updateFirmwareInputBufStatus(procBufNum);
+ } else {
+ mbBypass = true;
+ flush();
+ ALOGE("VSP process error %d .... ISV changes to bypass mode", __LINE__);
+ }
+ }
+ }
+
+ ALOGV("mNumTaskInProcesing %d", mNumTaskInProcesing);
+ while ((mNumTaskInProcesing > 0) && mNumTaskInProcesing >= mISVWorker->mNumForwardReferences && bGetBufSuccess ) {
+ fillBufList.clear();
+ bGetBufSuccess = getBufForFirmwareOutput(&fillBufList, &fillBufNum);
+ ALOGD_IF(ISV_THREAD_DEBUG, "%s: bGetOutput %d, buf num %d", __func__,
+ bGetBufSuccess, fillBufNum);
+ if (bGetBufSuccess) {
+ status_t ret = mISVWorker->fill(fillBufList, fillBufNum);
+ if (ret == STATUS_OK) {
+ mNumTaskInProcesing--;
+ ALOGV("mNumTaskInProcesing: %d ...", mNumTaskInProcesing);
+ updateFirmwareOutputBufStatus(fillBufNum);
+ } else {
+ mError = true;
+ ALOGE("ISV read firmware data error! Thread EXIT...");
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool ISVProcessor::isCurrentThread() const {
+ return mThreadId == androidGetThreadId();
+}
+
+inline bool ISVProcessor::isFrameRateValid(uint32_t fps)
+{
+ return (fps == 15 || fps == 24 || fps == 25 || fps == 30 || fps == 50 || fps == 60) ? true : false;
+}
+
+status_t ISVProcessor::configFilters(OMX_BUFFERHEADERTYPE* buffer)
+{
+ if ((mFilters & FilterFrameRateConversion) != 0) {
+ if (!isFrameRateValid(mFilterParam.frameRate)) {
+ if (mNumRetry++ < MAX_RETRY_NUM) {
+ int64_t deltaTime = buffer->nTimeStamp - mLastTimeStamp;
+ mLastTimeStamp = buffer->nTimeStamp;
+ if (deltaTime != 0)
+ mFilterParam.frameRate = ceil(1.0 / deltaTime * 1E6);
+ if (!isFrameRateValid(mFilterParam.frameRate)) {
+ return NOT_ENOUGH_DATA;
+ } else {
+ if (mFilterParam.frameRate == 50 || mFilterParam.frameRate == 60) {
+ ALOGD_IF(ISV_THREAD_DEBUG, "%s: %d fps don't need do FRC, so disable FRC", __func__,
+ mFilterParam.frameRate);
+ mFilters &= ~FilterFrameRateConversion;
+ mFilterParam.frcRate = FRC_RATE_1X;
+ } else {
+ mFilterParam.frcRate = mISVProfile->getFRCRate(mFilterParam.frameRate);
+ ALOGD_IF(ISV_THREAD_DEBUG, "%s: calculate fps is %d, frc rate is %d", __func__,
+ mFilterParam.frameRate, mFilterParam.frcRate);
+ }
+ }
+ } else {
+ ALOGD_IF(ISV_THREAD_DEBUG, "%s: exceed max retry to get a valid frame rate(%d), disable FRC", __func__,
+ mFilterParam.frameRate);
+ mFilters &= ~FilterFrameRateConversion;
+ mFilterParam.frcRate = FRC_RATE_1X;
+ }
+ }
+ }
+
+ if ((buffer->nFlags & OMX_BUFFERFLAG_TFF) != 0 ||
+ (buffer->nFlags & OMX_BUFFERFLAG_BFF) != 0)
+ mFilters |= FilterDeinterlacing;
+ else
+ mFilters &= ~FilterDeinterlacing;
+
+ if (mFilters == 0) {
+ ALOGI("%s: no filter need to be config, bypass ISV", __func__);
+ return UNKNOWN_ERROR;
+ }
+
+ //config filters to mISVWorker
+ return (mISVWorker->configFilters(mFilters, &mFilterParam) == STATUS_OK) ? OK : UNKNOWN_ERROR;
+}
+
+void ISVProcessor::addInput(OMX_BUFFERHEADERTYPE* input)
+{
+ if (mbFlush) {
+ mpOwner->releaseBuffer(kPortIndexInput, input, true);
+ return;
+ }
+
+ if (mbBypass) {
+ // return this buffer to framework
+ mpOwner->releaseBuffer(kPortIndexOutput, input, false);
+ return;
+ }
+
+ if (input->nFlags & OMX_BUFFERFLAG_EOS) {
+ mpOwner->releaseBuffer(kPortIndexInput, input, true);
+ notifyFlush();
+ return;
+ }
+
+ status_t ret = configFilters(input);
+ if (ret == NOT_ENOUGH_DATA) {
+ // release this buffer if frc is not ready.
+ mpOwner->releaseBuffer(kPortIndexInput, input, false);
+ ALOGD_IF(ISV_THREAD_DEBUG, "%s: frc rate is not ready, release this buffer %u, fps %d", __func__,
+ input, mFilterParam.frameRate);
+ return;
+ } else if (ret == UNKNOWN_ERROR) {
+ ALOGD_IF(ISV_THREAD_DEBUG, "%s: configFilters failed, bypass ISV", __func__);
+ mbBypass = true;
+ mpOwner->releaseBuffer(kPortIndexOutput, input, false);
+ return;
+ }
+
+ {
+ //put the decoded buffer into fill buffer queue
+ ALOGD_IF(ISV_COMPONENT_LOCK_DEBUG, "%s: acqiring mInputLock", __func__);
+ Mutex::Autolock autoLock(mInputLock);
+ ALOGD_IF(ISV_COMPONENT_LOCK_DEBUG, "%s: acqired mInputLock", __func__);
+
+ mInputBuffers.push_back(input);
+ ALOGD_IF(ISV_THREAD_DEBUG, "%s: hold pBuffer %u in input buffer queue. Intput queue size is %d, mInputProIdx %d.\
+ Output queue size is %d, mOutputProcIdx %d", __func__,
+ input, mInputBuffers.size(), mInputProcIdx,
+ mOutputBuffers.size(), mOutputProcIdx);
+ ALOGD_IF(ISV_COMPONENT_LOCK_DEBUG, "%s: releasing mInputLock", __func__);
+ }
+
+ {
+ Mutex::Autolock autoLock(mLock);
+ mRunCond.signal();
+ }
+ return;
+}
+
+void ISVProcessor::addOutput(OMX_BUFFERHEADERTYPE* output)
+{
+ if (mbFlush) {
+ mpOwner->releaseBuffer(kPortIndexOutput, output, true);
+ return;
+ }
+
+ if (mbBypass || mOutputBuffers.size() >= MIN_OUTPUT_NUM) {
+ // return this buffer to decoder
+ mpOwner->releaseBuffer(kPortIndexInput, output, false);
+ return;
+ }
+
+ {
+ //push the buffer into the output queue if it is not full
+ ALOGD_IF(ISV_COMPONENT_LOCK_DEBUG, "%s: acqiring mOutputLock", __func__);
+ Mutex::Autolock autoLock(mOutputLock);
+ ALOGD_IF(ISV_COMPONENT_LOCK_DEBUG, "%s: acqired mOutputLock", __func__);
+
+ mOutputBuffers.push_back(output);
+ ALOGD_IF(ISV_THREAD_DEBUG, "%s: hold pBuffer %u in output buffer queue. Input queue size is %d, mInputProIdx %d.\
+ Output queue size is %d, mOutputProcIdx %d", __func__,
+ output, mInputBuffers.size(), mInputProcIdx,
+ mOutputBuffers.size(), mOutputProcIdx);
+ ALOGD_IF(ISV_COMPONENT_LOCK_DEBUG, "%s: releasing mOutputLock", __func__);
+ }
+
+ {
+ Mutex::Autolock autoLock(mLock);
+ mRunCond.signal();
+ }
+ return;
+}
+
+void ISVProcessor::notifyFlush()
+{
+ if (mInputBuffers.empty() && mOutputBuffers.empty()) {
+ ALOGD_IF(ISV_THREAD_DEBUG, "%s: input and ouput buffer queue is empty, nothing need to do", __func__);
+ return;
+ }
+
+ Mutex::Autolock autoLock(mLock);
+ mbFlush = true;
+ mRunCond.signal();
+ ALOGD_IF(ISV_THREAD_DEBUG, "wake up proc thread");
+ return;
+}
+
+void ISVProcessor::waitFlushFinished()
+{
+ Mutex::Autolock endLock(mEndLock);
+ ALOGD_IF(ISV_THREAD_DEBUG, "waiting mEnd lock(seek finish) ");
+ while(mbFlush) {
+ mEndCond.wait(mEndLock);
+ }
+ return;
+}
+
+void ISVProcessor::flush()
+{
+ OMX_BUFFERHEADERTYPE* pBuffer = NULL;
+ {
+ Mutex::Autolock autoLock(mInputLock);
+ while (!mInputBuffers.empty()) {
+ pBuffer = mInputBuffers.itemAt(0);
+ mpOwner->releaseBuffer(kPortIndexInput, pBuffer, true);
+ ALOGD_IF(ISV_THREAD_DEBUG, "%s: Flush the pBuffer %u in input buffer queue.", __func__, pBuffer);
+ mInputBuffers.removeAt(0);
+ }
+ }
+ {
+ Mutex::Autolock autoLock(mOutputLock);
+ while (!mOutputBuffers.empty()) {
+ pBuffer = mOutputBuffers.itemAt(0);
+ mpOwner->releaseBuffer(kPortIndexOutput, pBuffer, true);
+ ALOGD_IF(ISV_THREAD_DEBUG, "%s: Flush the pBuffer %u in output buffer queue.", __func__, pBuffer);
+ mOutputBuffers.removeAt(0);
+ }
+ }
+ //flush finished.
+ return;
+}
diff --git a/ISV/base/isv_worker.cpp b/ISV/base/isv_worker.cpp
new file mode 100644
index 0000000..bee3536
--- /dev/null
+++ b/ISV/base/isv_worker.cpp
@@ -0,0 +1,1005 @@
+/*
+ * 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 <cutils/properties.h>
+#include <system/graphics.h>
+#include "isv_worker.h"
+#ifndef TARGET_VPP_USE_GEN
+#include <hal_public.h>
+#else
+#include <ufo/graphics.h>
+#endif
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "isv-omxil"
+
+#define CHECK_VASTATUS(str) \
+ do { \
+ if (vaStatus != VA_STATUS_SUCCESS) { \
+ ALOGE("%s failed\n", str); \
+ return STATUS_ERROR;} \
+ }while(0);
+
+enum STRENGTH {
+ STRENGTH_LOW = 0,
+ STRENGTH_MEDIUM,
+ STRENGTH_HIGH
+};
+
+#define DENOISE_DEBLOCK_STRENGTH STRENGTH_MEDIUM
+#define COLOR_STRENGTH STRENGTH_MEDIUM
+#ifdef TARGET_VPP_USE_GEN
+#define COLOR_NUM 4
+#else
+#define COLOR_NUM 2
+#endif
+
+#define MAX_FRC_OUTPUT 4 /*for frcx4*/
+
+using namespace android;
+
+ISVWorker::ISVWorker()
+ :mNumForwardReferences(0),
+ mVAContext(VA_INVALID_ID),
+ mWidth(0), mHeight(0),
+ mDisplay(NULL), mVADisplay(NULL),
+ mVAConfig(VA_INVALID_ID),
+ mForwardReferences(NULL),
+ mPrevInput(0), mPrevOutput(0),
+ mNumFilterBuffers(0),
+ mFilterFrc(VA_INVALID_ID), mFilters(0),
+ mInputIndex(0), mOutputIndex(0),
+ mOutputCount(0) {
+ memset(&mFilterBuffers, VA_INVALID_ID, VAProcFilterCount * sizeof(VABufferID));
+ memset(&mFilterParam, 0, sizeof(mFilterParam));
+}
+
+bool ISVWorker::isSupport() const {
+ bool support = false;
+
+ int num_entrypoints = vaMaxNumEntrypoints(mVADisplay);
+ VAEntrypoint * entrypoints = (VAEntrypoint *)malloc(num_entrypoints * sizeof(VAEntrypoint));
+ if (entrypoints == NULL) {
+ ALOGE("failed to malloc entrypoints array\n");
+ return false;
+ }
+
+ // check if it contains VPP entry point VAEntrypointVideoProc
+ VAStatus vaStatus = vaQueryConfigEntrypoints(mVADisplay, VAProfileNone, entrypoints, &num_entrypoints);
+ if (vaStatus != VA_STATUS_SUCCESS) {
+ ALOGE("vaQueryConfigEntrypoints failed");
+ return false;
+ }
+ for (int i = 0; !support && i < num_entrypoints; i++) {
+ support = entrypoints[i] == VAEntrypointVideoProc;
+ }
+ free(entrypoints);
+ entrypoints = NULL;
+
+ return support;
+}
+
+uint32_t ISVWorker::getProcBufCount() {
+ return getOutputBufCount(mInputIndex);
+}
+
+uint32_t ISVWorker::getFillBufCount() {
+ return getOutputBufCount(mOutputIndex);
+}
+
+uint32_t ISVWorker::getOutputBufCount(uint32_t index) {
+ uint32_t bufCount = 1;
+ if (((mFilters & FilterFrameRateConversion) != 0)
+ && index > 0)
+ bufCount = mFilterParam.frcRate - (((mFilterParam.frcRate == FRC_RATE_2_5X) ? (index & 1): 0));
+ return bufCount;
+}
+
+
+status_t ISVWorker::init(uint32_t width, uint32_t height) {
+ ALOGV("init");
+
+ if (mDisplay != NULL) {
+ ALOGE("VA is particially started");
+ return STATUS_ERROR;
+ }
+ mDisplay = new Display;
+ *mDisplay = ANDROID_DISPLAY_HANDLE;
+
+ mVADisplay = vaGetDisplay(mDisplay);
+ if (mVADisplay == NULL) {
+ ALOGE("vaGetDisplay failed");
+ return STATUS_ERROR;
+ }
+
+ int majorVersion, minorVersion;
+ VAStatus vaStatus = vaInitialize(mVADisplay, &majorVersion, &minorVersion);
+ CHECK_VASTATUS("vaInitialize");
+
+ // Check if VPP entry point is supported
+ if (!isSupport()) {
+ ALOGE("VPP is not supported on current platform");
+ return STATUS_NOT_SUPPORT;
+ }
+
+ // Find out the format for the target
+ VAConfigAttrib attrib;
+ attrib.type = VAConfigAttribRTFormat;
+ vaStatus = vaGetConfigAttributes(mVADisplay, VAProfileNone, VAEntrypointVideoProc, &attrib, 1);
+ CHECK_VASTATUS("vaGetConfigAttributes");
+
+ if ((attrib.value & VA_RT_FORMAT_YUV420) == 0) {
+ ALOGE("attribute is %x vs wanted %x", attrib.value, VA_RT_FORMAT_YUV420);
+ return STATUS_NOT_SUPPORT;
+ }
+
+ ALOGV("ready to create config");
+ // Create the configuration
+ vaStatus = vaCreateConfig(mVADisplay, VAProfileNone, VAEntrypointVideoProc, &attrib, 1, &mVAConfig);
+ CHECK_VASTATUS("vaCreateConfig");
+
+
+ // Create Context
+ ALOGV("ready to create context");
+ mWidth = width;
+ mHeight = height;
+ vaStatus = vaCreateContext(mVADisplay, mVAConfig, mWidth, mHeight, 0, NULL, 0, &mVAContext);
+ CHECK_VASTATUS("vaCreateContext");
+
+ ALOGV("VA has been successfully started");
+ return STATUS_OK;
+}
+
+status_t ISVWorker::deinit() {
+ {
+ Mutex::Autolock autoLock(mPipelineBufferLock);
+ while (!mPipelineBuffers.isEmpty()) {
+ VABufferID pipelineBuffer = mPipelineBuffers.itemAt(0);
+ if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, pipelineBuffer))
+ ALOGW("%s: failed to destroy va buffer id %d", __func__, pipelineBuffer);
+ mPipelineBuffers.removeAt(0);
+ }
+ }
+
+ if (mNumFilterBuffers != 0) {
+ for (uint32_t i = 0; i < mNumFilterBuffers; i++) {
+ if(VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, mFilterBuffers[i]))
+ ALOGW("%s: failed to destroy va buffer id %d", __func__, mFilterBuffers[i]);
+ }
+ mNumFilterBuffers = 0;
+ memset(&mFilterBuffers, VA_INVALID_ID, VAProcFilterCount * sizeof(VABufferID));
+ mFilterFrc = VA_INVALID_ID;
+ }
+
+ if (mForwardReferences != NULL) {
+ free(mForwardReferences);
+ mForwardReferences = NULL;
+ mNumForwardReferences = 0;
+ }
+
+ if (mVAContext != VA_INVALID_ID) {
+ vaDestroyContext(mVADisplay, mVAContext);
+ mVAContext = VA_INVALID_ID;
+ }
+
+ if (mVAConfig != VA_INVALID_ID) {
+ vaDestroyConfig(mVADisplay, mVAConfig);
+ mVAConfig = VA_INVALID_ID;
+ }
+
+ if (mVADisplay) {
+ vaTerminate(mVADisplay);
+ mVADisplay = NULL;
+ }
+
+ if (mDisplay) {
+ delete mDisplay;
+ mDisplay = NULL;
+ }
+
+ return STATUS_OK;
+}
+
+status_t ISVWorker::allocSurface(uint32_t* width, uint32_t* height,
+ uint32_t stride, uint32_t format, uint32_t handle, int32_t* surfaceId)
+{
+ if (mWidth == 0 || mHeight == 0) {
+ ALOGE("%s: isv worker has not been initialized.", __func__);
+ return STATUS_ERROR;
+ }
+
+#ifndef TARGET_VPP_USE_GEN
+ *width = mWidth;
+ *height = mHeight;
+#endif
+ // Create VASurfaces
+ VASurfaceAttrib attribs[3];
+ VASurfaceAttribExternalBuffers vaExtBuf;
+
+ memset(&vaExtBuf, 0, sizeof(VASurfaceAttribExternalBuffers));
+ switch(format) {
+ case HAL_PIXEL_FORMAT_YV12:
+ vaExtBuf.pixel_format = VA_FOURCC_YV12;
+ vaExtBuf.num_planes = 3;
+ vaExtBuf.pitches[0] = stride;
+ vaExtBuf.pitches[1] = stride / 2;
+ vaExtBuf.pitches[2] = stride / 2;
+ vaExtBuf.pitches[3] = 0;
+ vaExtBuf.offsets[0] = 0;
+ vaExtBuf.offsets[1] = stride * *height;
+ vaExtBuf.offsets[2] = vaExtBuf.offsets[1] + (stride / 2) * (*height / 2);
+ vaExtBuf.offsets[3] = 0;
+ break;
+#ifdef TARGET_VPP_USE_GEN
+ case HAL_PIXEL_FORMAT_NV12_Y_TILED_INTEL:
+ case HAL_PIXEL_FORMAT_NV12_X_TILED_INTEL:
+ //it will be removed in future, it indicate the same format with HAL_PIXEL_FORMAT_NV12_Y_TILED_INTEL
+ case HAL_PIXEL_FORMAT_YUV420PackedSemiPlanar_Tiled_INTEL:
+#else
+ case HAL_PIXEL_FORMAT_NV12_VED:
+ case HAL_PIXEL_FORMAT_NV12_VEDT:
+#endif
+ vaExtBuf.pixel_format = VA_FOURCC_NV12;
+ vaExtBuf.num_planes = 2;
+ vaExtBuf.pitches[0] = stride;
+ vaExtBuf.pitches[1] = stride;
+ vaExtBuf.pitches[2] = 0;
+ vaExtBuf.pitches[3] = 0;
+ vaExtBuf.offsets[0] = 0;
+ vaExtBuf.offsets[1] = stride * *height;
+ vaExtBuf.offsets[2] = 0;
+ vaExtBuf.offsets[3] = 0;
+ break;
+ default:
+ ALOGE("%s: can't support this format 0x%08x", __func__, format);
+ return STATUS_ERROR;
+ }
+ vaExtBuf.width = *width;
+ vaExtBuf.height = *height;
+ vaExtBuf.data_size = stride * *height * 1.5;
+ vaExtBuf.num_buffers = 1;
+#ifndef TARGET_VPP_USE_GEN
+ if (format == HAL_PIXEL_FORMAT_NV12_VEDT) {
+ ALOGV("set TILING flag");
+ vaExtBuf.flags |= VA_SURFACE_EXTBUF_DESC_ENABLE_TILING;
+ }
+#endif
+ vaExtBuf.flags |= VA_SURFACE_ATTRIB_MEM_TYPE_ANDROID_GRALLOC;
+ vaExtBuf.buffers = (long unsigned int*)&handle;
+
+ attribs[0].type = (VASurfaceAttribType)VASurfaceAttribMemoryType;
+ attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
+ attribs[0].value.type = VAGenericValueTypeInteger;
+ attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_ANDROID_GRALLOC;
+
+ attribs[1].type = (VASurfaceAttribType)VASurfaceAttribExternalBufferDescriptor;
+ attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
+ attribs[1].value.type = VAGenericValueTypePointer;
+ attribs[1].value.value.p = &vaExtBuf;
+
+ attribs[2].type = (VASurfaceAttribType)VASurfaceAttribUsageHint;
+ attribs[2].flags = VA_SURFACE_ATTRIB_SETTABLE;
+ attribs[2].value.type = VAGenericValueTypeInteger;
+ attribs[2].value.value.i = VA_SURFACE_ATTRIB_USAGE_HINT_VPP_READ;
+
+ ALOGV("%s: Ext buffer: width %d, height %d, data_size %d, pitch %d", __func__,
+ vaExtBuf.width, vaExtBuf.height, vaExtBuf.data_size, vaExtBuf.pitches[0]);
+ VAStatus vaStatus = vaCreateSurfaces(mVADisplay, VA_RT_FORMAT_YUV420, vaExtBuf.width,
+ vaExtBuf.height, (VASurfaceID*)surfaceId, 1, attribs, 3);
+ CHECK_VASTATUS("vaCreateSurfaces");
+
+ return (vaStatus == VA_STATUS_SUCCESS) ? STATUS_OK : STATUS_ERROR;
+}
+
+status_t ISVWorker::freeSurface(int32_t* surfaceId)
+{
+ VAStatus vaStatus = VA_STATUS_SUCCESS;
+ vaDestroySurfaces(mVADisplay, (VASurfaceID*)surfaceId, 1);
+ CHECK_VASTATUS("vaDestroySurfaces");
+
+ return (vaStatus == VA_STATUS_SUCCESS) ? STATUS_OK : STATUS_ERROR;
+}
+
+status_t ISVWorker::configFilters(uint32_t filters,
+ const FilterParam* filterParam)
+{
+ status_t ret = STATUS_OK;
+
+ if (!filterParam) {
+ ALOGE("%s: invalid filterParam", __func__);
+ return STATUS_ERROR;
+ }
+
+ if (filters != 0) {
+ mFilterParam.srcWidth = filterParam->srcWidth;
+ mFilterParam.srcHeight = filterParam->srcHeight;
+ mFilterParam.dstWidth = filterParam->dstWidth;
+ mFilterParam.dstHeight = filterParam->dstHeight;
+ mFilterParam.frameRate = filterParam->frameRate;
+ mFilterParam.frcRate = filterParam->frcRate;
+ }
+
+ if (mFilters != filters) {
+ mFilters = filters;
+ ALOGI("%s: mFilters 0x%x, fps %d, frc rate %d", __func__, mFilters, mFilterParam.frameRate, mFilterParam.frcRate);
+ ret = setupFilters();
+ }
+
+ return ret;
+}
+
+bool ISVWorker::isFpsSupport(int32_t fps, int32_t *fpsSet, int32_t fpsSetCnt) {
+ bool ret = false;
+ for (int32_t i = 0; i < fpsSetCnt; i++) {
+ if (fps == fpsSet[i]) {
+ ret = true;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+status_t ISVWorker::setupFilters() {
+ ALOGV("setupFilters");
+ VAProcFilterParameterBuffer deblock, denoise, sharpen;
+ VAProcFilterParameterBufferDeinterlacing deint;
+ VAProcFilterParameterBufferColorBalance color[COLOR_NUM];
+ VAProcFilterParameterBufferFrameRateConversion frc;
+ VABufferID deblockId, denoiseId, deintId, sharpenId, colorId, frcId;
+ uint32_t numCaps;
+ VAProcFilterCap deblockCaps, denoiseCaps, sharpenCaps, frcCaps;
+ VAProcFilterCapDeinterlacing deinterlacingCaps[VAProcDeinterlacingCount];
+ VAProcFilterCapColorBalance colorCaps[COLOR_NUM];
+ VAStatus vaStatus;
+ uint32_t numSupportedFilters = VAProcFilterCount;
+ VAProcFilterType supportedFilters[VAProcFilterCount];
+
+ if (mNumFilterBuffers != 0) {
+ for (uint32_t i = 0; i < mNumFilterBuffers; i++) {
+ if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, mFilterBuffers[i]))
+ ALOGW("%s: failed to destroy va buffer %d", __func__, mFilterBuffers[i]);
+ //return STATUS_ERROR;
+ }
+ memset(&mFilterBuffers, VA_INVALID_ID, VAProcFilterCount * sizeof(VABufferID));
+ mFilterFrc = VA_INVALID_ID;
+ mNumFilterBuffers = 0;
+ }
+
+ // query supported filters
+ vaStatus = vaQueryVideoProcFilters(mVADisplay, mVAContext, supportedFilters, &numSupportedFilters);
+ CHECK_VASTATUS("vaQueryVideoProcFilters");
+
+ // create filter buffer for each filter
+ for (uint32_t i = 0; i < numSupportedFilters; i++) {
+ switch (supportedFilters[i]) {
+ case VAProcFilterDeblocking:
+ if ((mFilters & FilterDeblocking) != 0) {
+ // check filter caps
+ numCaps = 1;
+ vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext,
+ VAProcFilterDeblocking,
+ &deblockCaps,
+ &numCaps);
+ CHECK_VASTATUS("vaQueryVideoProcFilterCaps for deblocking");
+ // create parameter buffer
+ deblock.type = VAProcFilterDeblocking;
+ deblock.value = deblockCaps.range.min_value + DENOISE_DEBLOCK_STRENGTH * deblockCaps.range.step;
+ vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
+ VAProcFilterParameterBufferType, sizeof(deblock), 1,
+ &deblock, &deblockId);
+ CHECK_VASTATUS("vaCreateBuffer for deblocking");
+ mFilterBuffers[mNumFilterBuffers] = deblockId;
+ mNumFilterBuffers++;
+ }
+ break;
+ case VAProcFilterNoiseReduction:
+ if((mFilters & FilterNoiseReduction) != 0) {
+ // check filter caps
+ numCaps = 1;
+ vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext,
+ VAProcFilterNoiseReduction,
+ &denoiseCaps,
+ &numCaps);
+ CHECK_VASTATUS("vaQueryVideoProcFilterCaps for denoising");
+ // create parameter buffer
+ denoise.type = VAProcFilterNoiseReduction;
+#ifdef TARGET_VPP_USE_GEN
+ char propValueString[PROPERTY_VALUE_MAX];
+
+ // placeholder for vpg driver: can't support denoise factor auto adjust, so leave config to user.
+ property_get("vpp.filter.denoise.factor", propValueString, "64.0");
+ denoise.value = atof(propValueString);
+ denoise.value = (denoise.value < 0.0f) ? 0.0f : denoise.value;
+ denoise.value = (denoise.value > 64.0f) ? 64.0f : denoise.value;
+#else
+ denoise.value = denoiseCaps.range.min_value + DENOISE_DEBLOCK_STRENGTH * denoiseCaps.range.step;
+#endif
+ vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
+ VAProcFilterParameterBufferType, sizeof(denoise), 1,
+ &denoise, &denoiseId);
+ CHECK_VASTATUS("vaCreateBuffer for denoising");
+ mFilterBuffers[mNumFilterBuffers] = denoiseId;
+ mNumFilterBuffers++;
+ }
+ break;
+ case VAProcFilterDeinterlacing:
+ if ((mFilters & FilterDeinterlacing) != 0) {
+ numCaps = VAProcDeinterlacingCount;
+ vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext,
+ VAProcFilterDeinterlacing,
+ &deinterlacingCaps[0],
+ &numCaps);
+ CHECK_VASTATUS("vaQueryVideoProcFilterCaps for deinterlacing");
+ for (uint32_t i = 0; i < numCaps; i++)
+ {
+ VAProcFilterCapDeinterlacing * const cap = &deinterlacingCaps[i];
+ if (cap->type != VAProcDeinterlacingBob) // desired Deinterlacing Type
+ continue;
+
+ deint.type = VAProcFilterDeinterlacing;
+ deint.algorithm = VAProcDeinterlacingBob;
+ vaStatus = vaCreateBuffer(mVADisplay,
+ mVAContext,
+ VAProcFilterParameterBufferType,
+ sizeof(deint), 1,
+ &deint, &deintId);
+ CHECK_VASTATUS("vaCreateBuffer for deinterlacing");
+ mFilterBuffers[mNumFilterBuffers] = deintId;
+ mNumFilterBuffers++;
+ }
+ }
+ break;
+ case VAProcFilterSharpening:
+ if((mFilters & FilterSharpening) != 0) {
+ // check filter caps
+ numCaps = 1;
+ vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext,
+ VAProcFilterSharpening,
+ &sharpenCaps,
+ &numCaps);
+ CHECK_VASTATUS("vaQueryVideoProcFilterCaps for sharpening");
+ // create parameter buffer
+ sharpen.type = VAProcFilterSharpening;
+#ifdef TARGET_VPP_USE_GEN
+ char propValueString[PROPERTY_VALUE_MAX];
+
+ // placeholder for vpg driver: can't support sharpness factor auto adjust, so leave config to user.
+ property_get("vpp.filter.sharpen.factor", propValueString, "10.0");
+ sharpen.value = atof(propValueString);
+ sharpen.value = (sharpen.value < 0.0f) ? 0.0f : sharpen.value;
+ sharpen.value = (sharpen.value > 64.0f) ? 64.0f : sharpen.value;
+#else
+ sharpen.value = sharpenCaps.range.default_value;
+#endif
+ vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
+ VAProcFilterParameterBufferType, sizeof(sharpen), 1,
+ &sharpen, &sharpenId);
+ CHECK_VASTATUS("vaCreateBuffer for sharpening");
+ mFilterBuffers[mNumFilterBuffers] = sharpenId;
+ mNumFilterBuffers++;
+ }
+ break;
+ case VAProcFilterColorBalance:
+ if((mFilters & FilterColorBalance) != 0) {
+ uint32_t featureCount = 0;
+ // check filter caps
+ // FIXME: it's not used at all!
+ numCaps = COLOR_NUM;
+ vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext,
+ VAProcFilterColorBalance,
+ colorCaps,
+ &numCaps);
+ CHECK_VASTATUS("vaQueryVideoProcFilterCaps for color balance");
+ // create parameter buffer
+ for (uint32_t i = 0; i < numCaps; i++) {
+ if (colorCaps[i].type == VAProcColorBalanceAutoSaturation) {
+ color[i].type = VAProcFilterColorBalance;
+ color[i].attrib = VAProcColorBalanceAutoSaturation;
+ color[i].value = colorCaps[i].range.min_value + COLOR_STRENGTH * colorCaps[i].range.step;
+ featureCount++;
+ }
+ else if (colorCaps[i].type == VAProcColorBalanceAutoBrightness) {
+ color[i].type = VAProcFilterColorBalance;
+ color[i].attrib = VAProcColorBalanceAutoBrightness;
+ color[i].value = colorCaps[i].range.min_value + COLOR_STRENGTH * colorCaps[i].range.step;
+ featureCount++;
+ }
+ }
+#ifdef TARGET_VPP_USE_GEN
+ //TODO: VPG need to support check input value by colorCaps.
+ enum {kHue = 0, kSaturation, kBrightness, kContrast};
+ char propValueString[PROPERTY_VALUE_MAX];
+ color[kHue].type = VAProcFilterColorBalance;
+ color[kHue].attrib = VAProcColorBalanceHue;
+
+ // placeholder for vpg driver: can't support auto color balance, so leave config to user.
+ property_get("vpp.filter.procamp.hue", propValueString, "179.0");
+ color[kHue].value = atof(propValueString);
+ color[kHue].value = (color[kHue].value < -180.0f) ? -180.0f : color[kHue].value;
+ color[kHue].value = (color[kHue].value > 180.0f) ? 180.0f : color[kHue].value;
+ featureCount++;
+
+ color[kSaturation].type = VAProcFilterColorBalance;
+ color[kSaturation].attrib = VAProcColorBalanceSaturation;
+ property_get("vpp.filter.procamp.saturation", propValueString, "1.0");
+ color[kSaturation].value = atof(propValueString);
+ color[kSaturation].value = (color[kSaturation].value < 0.0f) ? 0.0f : color[kSaturation].value;
+ color[kSaturation].value = (color[kSaturation].value > 10.0f) ? 10.0f : color[kSaturation].value;
+ featureCount++;
+
+ color[kBrightness].type = VAProcFilterColorBalance;
+ color[kBrightness].attrib = VAProcColorBalanceBrightness;
+ property_get("vpp.filter.procamp.brightness", propValueString, "0.0");
+ color[kBrightness].value = atof(propValueString);
+ color[kBrightness].value = (color[kBrightness].value < -100.0f) ? -100.0f : color[kBrightness].value;
+ color[kBrightness].value = (color[kBrightness].value > 100.0f) ? 100.0f : color[kBrightness].value;
+ featureCount++;
+
+ color[kContrast].type = VAProcFilterColorBalance;
+ color[kContrast].attrib = VAProcColorBalanceContrast;
+ property_get("vpp.filter.procamp.contrast", propValueString, "1.0");
+ color[kContrast].value = atof(propValueString);
+ color[kContrast].value = (color[kContrast].value < 0.0f) ? 0.0f : color[kContrast].value;
+ color[kContrast].value = (color[kContrast].value > 10.0f) ? 10.0f : color[kContrast].value;
+ featureCount++;
+#endif
+ vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
+ VAProcFilterParameterBufferType, sizeof(*color), featureCount,
+ color, &colorId);
+ CHECK_VASTATUS("vaCreateBuffer for color balance");
+ mFilterBuffers[mNumFilterBuffers] = colorId;
+ mNumFilterBuffers++;
+ }
+ break;
+ case VAProcFilterFrameRateConversion:
+ if((mFilters & FilterFrameRateConversion) != 0) {
+ frc.type = VAProcFilterFrameRateConversion;
+ frc.input_fps = mFilterParam.frameRate;
+ switch (mFilterParam.frcRate){
+ case FRC_RATE_1X:
+ frc.output_fps = frc.input_fps;
+ break;
+ case FRC_RATE_2X:
+ frc.output_fps = frc.input_fps * 2;
+ break;
+ case FRC_RATE_2_5X:
+ frc.output_fps = frc.input_fps * 5/2;
+ break;
+ case FRC_RATE_4X:
+ frc.output_fps = frc.input_fps * 4;
+ break;
+ }
+ vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
+ VAProcFilterParameterBufferType, sizeof(frc), 1,
+ &frc, &frcId);
+ CHECK_VASTATUS("vaCreateBuffer for frc");
+ mFilterBuffers[mNumFilterBuffers] = frcId;
+ mNumFilterBuffers++;
+ mFilterFrc = frcId;
+ }
+ break;
+ default:
+ ALOGE("Not supported filter\n");
+ break;
+ }
+ }
+
+ return setupPipelineCaps();
+}
+
+status_t ISVWorker::setupPipelineCaps() {
+ ALOGV("setupPipelineCaps");
+ //TODO color standards
+ VAProcPipelineCaps pipelineCaps;
+ VAStatus vaStatus;
+ pipelineCaps.input_color_standards = in_color_standards;
+ pipelineCaps.num_input_color_standards = VAProcColorStandardCount;
+ pipelineCaps.output_color_standards = out_color_standards;
+ pipelineCaps.num_output_color_standards = VAProcColorStandardCount;
+
+ vaStatus = vaQueryVideoProcPipelineCaps(mVADisplay, mVAContext,
+ mFilterBuffers, mNumFilterBuffers,
+ &pipelineCaps);
+ CHECK_VASTATUS("vaQueryVideoProcPipelineCaps");
+
+ if (mForwardReferences != NULL) {
+ free(mForwardReferences);
+ mForwardReferences = NULL;
+ mNumForwardReferences = 0;
+ }
+
+ mNumForwardReferences = pipelineCaps.num_forward_references;
+ if (mNumForwardReferences > 0) {
+ mForwardReferences = (VASurfaceID*)malloc(mNumForwardReferences * sizeof(VASurfaceID));
+ if (mForwardReferences == NULL)
+ return STATUS_ALLOCATION_ERROR;
+ memset(mForwardReferences, 0, mNumForwardReferences * sizeof(VASurfaceID));
+ }
+ return STATUS_OK;
+}
+
+status_t ISVWorker::process(ISVBuffer* inputBuffer, Vector<ISVBuffer*> outputBuffer,
+ uint32_t outputCount, bool isEOS, uint32_t flags) {
+ ALOGV("process: outputCount=%d, mInputIndex=%d", outputCount, mInputIndex);
+ VASurfaceID input;
+ VASurfaceID output[MAX_FRC_OUTPUT];
+ VABufferID pipelineId;
+ VAProcPipelineParameterBuffer *pipeline;
+ VAProcFilterParameterBufferFrameRateConversion *frc;
+ VAStatus vaStatus;
+ uint32_t i;
+
+ if (mFilters == 0) {
+ ALOGE("%s: filters have not been initialized.", __func__);
+ return STATUS_ERROR;
+ }
+
+ if (outputCount < 1) {
+ ALOGE("invalid outputCount");
+ return STATUS_ERROR;
+ }
+
+ if (inputBuffer == NULL)
+ input = VA_INVALID_SURFACE;
+ else
+ input = inputBuffer->getSurface();
+
+ if (input == VA_INVALID_SURFACE && !isEOS) {
+ ALOGE("invalid input buffer");
+ return STATUS_ERROR;
+ }
+ for (i = 0; i < outputCount; i++) {
+ output[i] = outputBuffer[i]->getSurface();
+ if (output[i] == VA_INVALID_SURFACE) {
+ ALOGE("invalid output buffer");
+ return STATUS_ERROR;
+ }
+ }
+
+ // reference frames setting
+ if (mNumForwardReferences > 0) {
+ /* add previous frame into reference array*/
+ for (i = 1; i < mNumForwardReferences; i++) {
+ mForwardReferences[i - 1] = mForwardReferences[i];
+ }
+
+ //make last reference to input
+ mForwardReferences[mNumForwardReferences - 1] = mPrevInput;
+ }
+
+ mPrevInput = input;
+
+ // create pipeline parameter buffer
+ vaStatus = vaCreateBuffer(mVADisplay,
+ mVAContext,
+ VAProcPipelineParameterBufferType,
+ sizeof(VAProcPipelineParameterBuffer),
+ 1,
+ NULL,
+ &pipelineId);
+ CHECK_VASTATUS("vaCreateBuffer for VAProcPipelineParameterBufferType");
+
+ ALOGV("before vaBeginPicture");
+ vaStatus = vaBeginPicture(mVADisplay, mVAContext, output[0]);
+ CHECK_VASTATUS("vaBeginPicture");
+
+ // map pipeline paramter buffer
+ vaStatus = vaMapBuffer(mVADisplay, pipelineId, (void**)&pipeline);
+ CHECK_VASTATUS("vaMapBuffer for pipeline parameter buffer");
+
+ // frc pamameter setting
+ if ((mFilters & FilterFrameRateConversion) != 0) {
+ vaStatus = vaMapBuffer(mVADisplay, mFilterFrc, (void **)&frc);
+ CHECK_VASTATUS("vaMapBuffer for frc parameter buffer");
+ if (isEOS)
+ frc->num_output_frames = 0;
+ else
+ frc->num_output_frames = outputCount - 1;
+ frc->output_frames = output + 1;
+ }
+
+ // pipeline parameter setting
+ VARectangle dst_region;
+ dst_region.x = 0;
+ dst_region.y = 0;
+ dst_region.width = mFilterParam.dstWidth;
+ dst_region.height = mFilterParam.dstHeight;
+
+ VARectangle src_region;
+ src_region.x = 0;
+ src_region.y = 0;
+ src_region.width = mFilterParam.srcWidth;
+ src_region.height = mFilterParam.srcHeight;
+
+ if (isEOS) {
+ pipeline->surface = 0;
+ pipeline->pipeline_flags = VA_PIPELINE_FLAG_END;
+ }
+ else {
+ pipeline->surface = input;
+ pipeline->pipeline_flags = 0;
+ }
+#ifdef TARGET_VPP_USE_GEN
+ pipeline->surface_region = &src_region;
+ pipeline->output_region = &dst_region;
+ pipeline->surface_color_standard = VAProcColorStandardBT601;
+ pipeline->output_color_standard = VAProcColorStandardBT601;
+#else
+ pipeline->surface_region = NULL;
+ pipeline->output_region = NULL;//&output_region;
+ pipeline->surface_color_standard = VAProcColorStandardNone;
+ pipeline->output_color_standard = VAProcColorStandardNone;
+ /* real rotate state will be decided in psb video */
+ pipeline->rotation_state = 0;
+#endif
+ /* FIXME: set more meaningful background color */
+ pipeline->output_background_color = 0;
+ pipeline->filters = mFilterBuffers;
+ pipeline->num_filters = mNumFilterBuffers;
+ pipeline->forward_references = mForwardReferences;
+ pipeline->num_forward_references = mNumForwardReferences;
+ pipeline->backward_references = NULL;
+ pipeline->num_backward_references = 0;
+
+ //currently, we only transfer TOP field to frame, no frame rate change.
+ if (flags & (OMX_BUFFERFLAG_TFF | OMX_BUFFERFLAG_BFF)) {
+ pipeline->filter_flags = VA_TOP_FIELD;
+ } else {
+ pipeline->filter_flags = VA_FRAME_PICTURE;
+ }
+
+ if ((mFilters & FilterFrameRateConversion) != 0) {
+ vaStatus = vaUnmapBuffer(mVADisplay, mFilterFrc);
+ CHECK_VASTATUS("vaUnmapBuffer for frc parameter buffer");
+ }
+
+ vaStatus = vaUnmapBuffer(mVADisplay, pipelineId);
+ CHECK_VASTATUS("vaUnmapBuffer for pipeline parameter buffer");
+
+ ALOGV("before vaRenderPicture");
+ // Send parameter to driver
+ vaStatus = vaRenderPicture(mVADisplay, mVAContext, &pipelineId, 1);
+ CHECK_VASTATUS("vaRenderPicture");
+
+ ALOGV("before vaEndPicture");
+ vaStatus = vaEndPicture(mVADisplay, mVAContext);
+ CHECK_VASTATUS("vaEndPicture");
+
+ if (isEOS) {
+ vaStatus = vaSyncSurface(mVADisplay, mPrevOutput);
+ CHECK_VASTATUS("vaSyncSurface");
+ if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, pipelineId)) {
+ ALOGE("%s: failed to destroy va buffer %d", __func__, pipelineId);
+ return STATUS_ERROR;
+ }
+ return STATUS_OK;
+ }
+
+ mPrevOutput = output[0];
+ mInputIndex++;
+
+ Mutex::Autolock autoLock(mPipelineBufferLock);
+ mPipelineBuffers.push_back(pipelineId);
+
+ ALOGV("process, exit");
+ return STATUS_OK;
+}
+
+status_t ISVWorker::fill(Vector<ISVBuffer*> outputBuffer, uint32_t outputCount) {
+ ALOGV("fill, outputCount=%d, mOutputIndex=%d",outputCount, mOutputIndex);
+ // get output surface
+ VASurfaceID output[MAX_FRC_OUTPUT];
+ VAStatus vaStatus;
+ VASurfaceStatus surStatus;
+
+ if (outputCount < 1)
+ return STATUS_ERROR;
+ // map GraphicBuffer to VASurface
+ for (uint32_t i = 0; i < outputCount; i++) {
+
+ output[i] = outputBuffer[i]->getSurface();
+ if (output[i] == VA_INVALID_SURFACE) {
+ ALOGE("invalid output buffer");
+ return STATUS_ERROR;
+ }
+ //FIXME: only enable sync mode
+#if 0
+ vaStatus = vaQuerySurfaceStatus(mVADisplay, output[i],&surStatus);
+ CHECK_VASTATUS("vaQuerySurfaceStatus");
+ if (surStatus == VASurfaceRendering) {
+ ALOGV("Rendering %d", i);
+ /* The behavior of driver is: all output of one process task are return in one interruption.
+ The whole outputs of one FRC task are all ready or none of them is ready.
+ If the behavior changed, it hurts the performance.
+ */
+ if (0 != i) {
+ ALOGW("*****Driver behavior changed. The performance is hurt.");
+ ALOGW("Please check driver behavior: all output of one task return in one interruption.");
+ }
+ vaStatus = STATUS_DATA_RENDERING;
+ break;
+ }
+
+ if ((surStatus != VASurfaceRendering) && (surStatus != VASurfaceReady)) {
+ ALOGE("surface statu Error %d", surStatus);
+ vaStatus = STATUS_ERROR;
+ }
+#endif
+ vaStatus = vaSyncSurface(mVADisplay, output[i]);
+ CHECK_VASTATUS("vaSyncSurface");
+ vaStatus = STATUS_OK;
+ mOutputCount++;
+ //dumpYUVFrameData(output[i]);
+ }
+
+ {
+ Mutex::Autolock autoLock(mPipelineBufferLock);
+ if (vaStatus == STATUS_OK) {
+ VABufferID pipelineBuffer = mPipelineBuffers.itemAt(0);
+ if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, pipelineBuffer)) {
+ ALOGE("%s: failed to destroy va buffer %d", __func__, pipelineBuffer);
+ return STATUS_ERROR;
+ }
+ mPipelineBuffers.removeAt(0);
+ mOutputIndex++;
+ }
+ }
+
+ ALOGV("fill, exit");
+ return vaStatus;
+}
+
+// Debug only
+#define FRAME_OUTPUT_FILE_NV12 "/storage/sdcard0/vpp_output.nv12"
+status_t ISVWorker::dumpYUVFrameData(VASurfaceID surfaceID) {
+ status_t ret;
+ if (surfaceID == VA_INVALID_SURFACE)
+ return STATUS_ERROR;
+
+ VAStatus vaStatus;
+ VAImage image;
+ unsigned char *data_ptr;
+
+ vaStatus = vaDeriveImage(mVADisplay,
+ surfaceID,
+ &image);
+ CHECK_VASTATUS("vaDeriveImage");
+
+ vaStatus = vaMapBuffer(mVADisplay, image.buf, (void **)&data_ptr);
+ CHECK_VASTATUS("vaMapBuffer");
+
+ ret = writeNV12(mFilterParam.srcWidth, mFilterParam.srcHeight, data_ptr, image.pitches[0], image.pitches[1]);
+ if (ret != STATUS_OK) {
+ ALOGV("writeNV12 error");
+ return STATUS_ERROR;
+ }
+
+ vaStatus = vaUnmapBuffer(mVADisplay, image.buf);
+ CHECK_VASTATUS("vaUnMapBuffer");
+
+ vaStatus = vaDestroyImage(mVADisplay,image.image_id);
+ CHECK_VASTATUS("vaDestroyImage");
+
+ return STATUS_OK;
+}
+
+status_t ISVWorker::reset() {
+ status_t ret;
+ ALOGI("reset");
+ ALOGI("======mVPPInputCount=%d, mVPPRenderCount=%d======",
+ mInputIndex, mOutputCount);
+ mInputIndex = 0;
+ mOutputIndex = 0;
+ mOutputCount = 0;
+
+ {
+ Mutex::Autolock autoLock(mPipelineBufferLock);
+ while (!mPipelineBuffers.isEmpty()) {
+ VABufferID pipelineBuffer = mPipelineBuffers.itemAt(0);
+ if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, pipelineBuffer)) {
+ ALOGE("%s: failed to destroy va buffer %d", __func__, pipelineBuffer);
+ return STATUS_ERROR;
+ }
+ mPipelineBuffers.removeAt(0);
+ }
+ }
+
+ if (mNumFilterBuffers != 0) {
+ for (uint32_t i = 0; i < mNumFilterBuffers; i++) {
+ if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, mFilterBuffers[i]))
+ ALOGW("%s: failed to destroy va buffer %d", __func__, mFilterBuffers[i]);
+ //return STATUS_ERROR;
+ }
+ mNumFilterBuffers = 0;
+ memset(&mFilterBuffers, VA_INVALID_ID, VAProcFilterCount * sizeof(VABufferID));
+ mFilterFrc = VA_INVALID_ID;
+ }
+
+ // we need to clear the cache for reference surfaces
+ if (mForwardReferences != NULL) {
+ free(mForwardReferences);
+ mForwardReferences = NULL;
+ mNumForwardReferences = 0;
+ }
+
+ if (mVAContext != VA_INVALID_ID) {
+ vaDestroyContext(mVADisplay, mVAContext);
+ mVAContext = VA_INVALID_ID;
+ }
+ VAStatus vaStatus = vaCreateContext(mVADisplay, mVAConfig, mWidth, mHeight, 0, NULL, 0, &mVAContext);
+ CHECK_VASTATUS("vaCreateContext");
+
+ return setupFilters();
+}
+
+uint32_t ISVWorker::getVppOutputFps() {
+ uint32_t outputFps;
+ //mFilterParam.frcRate is 1 if FRC is disabled or input FPS is not changed by VPP.
+ if (FRC_RATE_2_5X == mFilterParam.frcRate) {
+ outputFps = mFilterParam.frameRate * 5 / 2;
+ } else {
+ outputFps = mFilterParam.frameRate * mFilterParam.frcRate;
+ }
+
+ ALOGV("vpp is on in settings %d %d %d", outputFps, mFilterParam.frameRate, mFilterParam.frcRate);
+ return outputFps;
+}
+
+
+status_t ISVWorker::writeNV12(int width, int height, unsigned char *out_buf, int y_pitch, int uv_pitch) {
+ size_t result;
+ int frame_size;
+ unsigned char *y_start, *uv_start;
+ int h;
+
+ FILE *ofile = fopen(FRAME_OUTPUT_FILE_NV12, "ab");
+ if(ofile == NULL) {
+ ALOGE("Open %s failed!", FRAME_OUTPUT_FILE_NV12);
+ return STATUS_ERROR;
+ }
+
+ if (out_buf == NULL)
+ {
+ fclose(ofile);
+ return STATUS_ERROR;
+ }
+ if ((width % 2) || (height % 2))
+ {
+ fclose(ofile);
+ return STATUS_ERROR;
+ }
+ // Set frame size
+ frame_size = height * width * 3/2;
+
+ /* write y */
+ y_start = out_buf;
+ for (h = 0; h < height; ++h) {
+ result = fwrite(y_start, sizeof(unsigned char), width, ofile);
+ y_start += y_pitch;
+ }
+
+ /* write uv */
+ uv_start = out_buf + uv_pitch * height;
+ for (h = 0; h < height / 2; ++h) {
+ result = fwrite(uv_start, sizeof(unsigned char), width, ofile);
+ uv_start += uv_pitch;
+ }
+ // Close file
+ fclose(ofile);
+ return STATUS_OK;
+}
diff --git a/ISV/include/isv_bufmanager.h b/ISV/include/isv_bufmanager.h
new file mode 100644
index 0000000..3a0df06
--- /dev/null
+++ b/ISV/include/isv_bufmanager.h
@@ -0,0 +1,150 @@
+/*
+ * 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 __ISV_BUFMANAGER_H
+#define __ISV_BUFMANAGER_H
+
+#include <utils/RefBase.h>
+#include <utils/Mutex.h>
+#include <utils/Errors.h>
+#include <utils/Vector.h>
+#include "isv_worker.h"
+
+using namespace android;
+
+#define ISV_BUFFER_MANAGER_DEBUG 0
+
+class ISVWorker;
+
+class ISVBuffer
+{
+public:
+ typedef enum {
+ ISV_BUFFER_GRALLOC,
+ ISV_BUFFER_METADATA,
+ } ISV_BUFFERTYPE;
+private:
+ //FIX ME: copy from ufo gralloc.h
+ typedef struct _ufo_buffer_details_t
+ {
+ int width; // \see alloc_device_t::alloc
+ int height; // \see alloc_device_t::alloc
+ int format; // \see alloc_device_t::alloc
+ int usage; // \see alloc_device_t::alloc
+ int name; // flink
+ uint32_t fb; // framebuffer id
+ int drmformat; // drm format
+ int pitch; // buffer pitch (in bytes)
+ int size; // buffer size (in bytes)
+ int allocWidth; // allocated buffer width in pixels.
+ int allocHeight; // allocated buffer height in lines.
+ int allocOffsetX;// horizontal pixel offset to content origin within allocated buffer.
+ int allocOffsetY;// vertical line offset to content origin within allocated buffer.
+ } ufo_buffer_details_t;
+
+ enum
+ {
+ INTEL_UFO_GRALLOC_MODULE_PERFORM_GET_BO_INFO = 6 // (buffer_handle_t, buffer_info_t*)
+ };
+
+public:
+ ISVBuffer(sp<ISVWorker> worker,
+ uint32_t buffer, uint32_t grallocHandle,
+ uint32_t width, uint32_t height,
+ uint32_t stride, uint32_t colorFormat,
+ ISV_BUFFERTYPE type)
+ :mWorker(worker),
+ mBuffer(buffer),
+ mGrallocHandle(grallocHandle),
+ mWidth(width),
+ mHeight(height),
+ mStride(stride),
+ mColorFormat(colorFormat),
+ mType(type),
+ mSurface(-1) {}
+
+ ISVBuffer(sp<ISVWorker> worker,
+ uint32_t buffer,
+ ISV_BUFFERTYPE type)
+ :mWorker(worker),
+ mBuffer(buffer),
+ mGrallocHandle(0),
+ mWidth(0),
+ mHeight(0),
+ mStride(0),
+ mColorFormat(0),
+ mType(type),
+ mSurface(-1) {}
+
+ ~ISVBuffer();
+
+ // init buffer info
+ status_t initBufferInfo();
+
+ // get va surface
+ uint32_t getSurface() { return mSurface; }
+ // get buffer handle
+ uint32_t getHandle() { return mBuffer; }
+
+private:
+ sp<ISVWorker> mWorker;
+ uint32_t mBuffer;
+ uint32_t mGrallocHandle;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ uint32_t mStride;
+ uint32_t mColorFormat;
+ ISV_BUFFERTYPE mType;
+ int32_t mSurface;
+};
+
+class ISVBufferManager: public RefBase
+{
+public:
+ ISVBufferManager()
+ :mWorker(NULL),
+ mMetaDataMode(false) {}
+
+ ~ISVBufferManager() {}
+ // set mBuffers size
+ status_t setBufferCount(int32_t size);
+
+ // register/unregister ISVBuffers to mBuffers
+ status_t useBuffer(const sp<ANativeWindowBuffer> nativeBuffer);
+ status_t useBuffer(uint32_t handle);
+ status_t freeBuffer(uint32_t handle);
+
+ // Map to ISVBuffer
+ ISVBuffer* mapBuffer(uint32_t handle);
+ // set isv worker
+ void setWorker(sp<ISVWorker> worker) { mWorker = worker; }
+ void setMetaDataMode(bool metaDataMode) { mMetaDataMode = metaDataMode; }
+private:
+ typedef enum {
+ GRALLOC_BUFFER_MODE = 0,
+ META_DATA_MODE = 1,
+ } ISV_WORK_MODE;
+
+ sp<ISVWorker> mWorker;
+ bool mMetaDataMode;
+ // VPP buffer queue
+ Vector<ISVBuffer*> mBuffers;
+ Mutex mBufferLock; // to protect access to mBuffers
+};
+
+
+#endif //#define __ISV_BUFMANAGER_H
diff --git a/ISV/include/isv_omxcomponent.h b/ISV/include/isv_omxcomponent.h
new file mode 100644
index 0000000..f3e2146
--- /dev/null
+++ b/ISV/include/isv_omxcomponent.h
@@ -0,0 +1,295 @@
+/*
+ * 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 ISV_OMXCOMPONENT_H_
+
+#define ISV_OMXCOMPONENT_H_
+
+#include <utils/Mutex.h>
+#include <utils/Vector.h>
+#include <utils/RefBase.h>
+#include "isv_omxcore.h"
+#include "isv_processor.h"
+#include "isv_profile.h"
+#include "isv_worker.h"
+#include "isv_bufmanager.h"
+
+#define ISV_COMPONENT_DEBUG 0
+
+#define MIN_INPUT_NUM (6) // forward reference frame number is 3 for merrifield/moorefield
+#define MIN_OUTPUT_NUM (10) // 2.5FRC need hold 2 + 3 + 2 + 3= 10 buffers, without FRC we set to 6
+#define DECODE_EXTRA_NUM (9) //?? i don't know
+#define MIN_ISV_BUFFER_NUM ((MIN_OUTPUT_NUM) + (MIN_INPUT_NUM) + (DECODE_EXTRA_NUM))
+#define UNDEQUEUED_NUM (4) // display system hold 4 buffers
+
+#define SKIP_FRAME_NUM (30)
+
+using namespace android;
+class ISVComponent;
+
+class ISVProcThreadObserver: public ISVProcessorObserver
+{
+public:
+ ISVProcThreadObserver(OMX_COMPONENTTYPE *pBaseComponent, OMX_COMPONENTTYPE *pComponent, OMX_CALLBACKTYPE *pCallBacks);
+ ~ISVProcThreadObserver();
+
+ virtual OMX_ERRORTYPE releaseBuffer(PORT_INDEX index, OMX_BUFFERHEADERTYPE* pBuffer, bool flush);
+private:
+ OMX_COMPONENTTYPE *mBaseComponent;
+ OMX_COMPONENTTYPE *mComponent;
+ OMX_CALLBACKTYPE *mpCallBacks;
+};
+
+class ISVComponent //: public RefBase
+{
+public:
+ /*
+ * construct & destruct
+ */
+ ISVComponent(OMX_PTR);
+ ~ISVComponent();
+
+ // replace component callbacks
+ OMX_CALLBACKTYPE *getCallBacks(OMX_CALLBACKTYPE*);
+ // pass down the real component&core
+ void setComponent(OMX_COMPONENTTYPE *pComp, ISVOMXCore *pCore){mComponent = pComp; mCore = pCore;return;}
+ // free the real component
+ OMX_ERRORTYPE freeComponent(){return (*(mCore->mFreeHandle))(static_cast<OMX_HANDLETYPE>(mComponent));}
+ // return ISV component handle
+ OMX_COMPONENTTYPE *getBaseComponent(){return &mBaseComponent;}
+
+ static Vector<ISVComponent*> g_isv_components;
+private:
+ /*
+ * component methods & helpers
+ */
+
+ static OMX_ERRORTYPE SendCommand(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_COMMANDTYPE Cmd,
+ OMX_IN OMX_U32 nParam1,
+ OMX_IN OMX_PTR pCmdData);
+ OMX_ERRORTYPE ISV_SendCommand(
+ OMX_IN OMX_COMMANDTYPE Cmd,
+ OMX_IN OMX_U32 nParam1,
+ OMX_IN OMX_PTR pCmdData);
+
+ static OMX_ERRORTYPE GetParameter(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_INDEXTYPE nParamIndex,
+ OMX_INOUT OMX_PTR pComponentParameterStructure);
+ OMX_ERRORTYPE ISV_GetParameter(
+ OMX_IN OMX_INDEXTYPE nParamIndex,
+ OMX_INOUT OMX_PTR pComponentParameterStructure);
+
+ static OMX_ERRORTYPE SetParameter(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_INDEXTYPE nIndex,
+ OMX_IN OMX_PTR pComponentParameterStructure);
+ OMX_ERRORTYPE ISV_SetParameter(
+ OMX_IN OMX_INDEXTYPE nIndex,
+ OMX_IN OMX_PTR pComponentParameterStructure);
+
+ static OMX_ERRORTYPE GetConfig(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_INDEXTYPE nIndex,
+ OMX_INOUT OMX_PTR pComponentConfigStructure);
+ OMX_ERRORTYPE ISV_GetConfig(
+ OMX_IN OMX_INDEXTYPE nIndex,
+ OMX_INOUT OMX_PTR pComponentConfigStructure);
+
+ static OMX_ERRORTYPE SetConfig(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_INDEXTYPE nIndex,
+ OMX_IN OMX_PTR pComponentConfigStructure);
+ OMX_ERRORTYPE ISV_SetConfig(
+ OMX_IN OMX_INDEXTYPE nIndex,
+ OMX_IN OMX_PTR pComponentConfigStructure);
+
+ static OMX_ERRORTYPE GetExtensionIndex(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_STRING cParameterName,
+ OMX_OUT OMX_INDEXTYPE* pIndexType);
+ OMX_ERRORTYPE ISV_GetExtensionIndex(
+ OMX_IN OMX_STRING cParameterName,
+ OMX_OUT OMX_INDEXTYPE* pIndexType);
+
+ static OMX_ERRORTYPE GetState(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_OUT OMX_STATETYPE* pState);
+ OMX_ERRORTYPE ISV_GetState(
+ OMX_OUT OMX_STATETYPE* pState);
+
+ static OMX_ERRORTYPE 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);
+ OMX_ERRORTYPE 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);
+
+ static OMX_ERRORTYPE 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);
+ OMX_ERRORTYPE ISV_AllocateBuffer(
+ OMX_INOUT OMX_BUFFERHEADERTYPE** ppBuffer,
+ OMX_IN OMX_U32 nPortIndex,
+ OMX_IN OMX_PTR pAppPrivate,
+ OMX_IN OMX_U32 nSizeBytes);
+
+ static OMX_ERRORTYPE FreeBuffer(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_U32 nPortIndex,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+ OMX_ERRORTYPE ISV_FreeBuffer(
+ OMX_IN OMX_U32 nPortIndex,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+
+ static OMX_ERRORTYPE EmptyThisBuffer(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+ OMX_ERRORTYPE ISV_EmptyThisBuffer(
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+
+ static OMX_ERRORTYPE FillThisBuffer(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+ OMX_ERRORTYPE ISV_FillThisBuffer(
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+
+ static OMX_ERRORTYPE SetCallbacks(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_CALLBACKTYPE* pCallbacks,
+ OMX_IN OMX_PTR pAppData);
+ OMX_ERRORTYPE ISV_SetCallbacks(
+ OMX_IN OMX_CALLBACKTYPE* pCallbacks,
+ OMX_IN OMX_PTR pAppData);
+
+ static OMX_ERRORTYPE ComponentRoleEnum(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_OUT OMX_U8 *cRole,
+ OMX_IN OMX_U32 nIndex);
+ OMX_ERRORTYPE ISV_ComponentRoleEnum(
+ OMX_OUT OMX_U8 *cRole,
+ OMX_IN OMX_U32 nIndex);
+
+ static OMX_ERRORTYPE FillBufferDone(
+ OMX_OUT OMX_HANDLETYPE hComponent,
+ OMX_OUT OMX_PTR pAppData,
+ OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer);
+ OMX_ERRORTYPE ISV_FillBufferDone(
+ OMX_OUT OMX_HANDLETYPE hComponent,
+ OMX_OUT OMX_PTR pAppData,
+ OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer);
+
+ static OMX_ERRORTYPE 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);
+ OMX_ERRORTYPE ISV_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);
+ /* end of component methods & helpers */
+
+ void SetTypeHeader(OMX_PTR type, OMX_U32 size);
+
+ // init & deinit functions
+ status_t init(int32_t width, int32_t height);
+ void deinit();
+
+ const static OMX_U8 OMX_SPEC_VERSION_MAJOR = 1;
+ const static OMX_U8 OMX_SPEC_VERSION_MINOR = 0;
+ const static OMX_U8 OMX_SPEC_VERSION_REVISION = 0;
+ const static OMX_U8 OMX_SPEC_VERSION_STEP = 0;
+
+ const static OMX_U32 OMX_SPEC_VERSION = 0
+ | (OMX_SPEC_VERSION_MAJOR << 0)
+ | (OMX_SPEC_VERSION_MINOR << 8)
+ | (OMX_SPEC_VERSION_REVISION << 16)
+ | (OMX_SPEC_VERSION_STEP << 24);
+
+ typedef enum OMX_ISVINDEXEXTTYPE {
+ OMX_IndexISVStartUsed = OMX_IndexVendorStartUnused + 0x0000F000,
+ OMX_IndexExtSetISVMode, /**< reference: OMX_U32 */
+ } OMX_ISVINDEXEXTTYPE;
+
+ typedef enum {
+ ISV_DISABLE = 0,
+ ISV_AUTO,
+ } ISV_MODE;
+
+private:
+ OMX_COMPONENTTYPE mBaseComponent; //returned by GetComponetHandle()
+ OMX_COMPONENTTYPE *mComponent; // passed from the real OMX core
+ OMX_CALLBACKTYPE *mpCallBacks;
+ ISVOMXCore *mCore; // owend by mComponent
+ OMX_CALLBACKTYPE *mpISVCallBacks;
+
+ // buffer manager
+ sp<ISVBufferManager> mISVBufferManager;
+
+ bool mThreadRunning;
+
+ // vpp thread observer
+ sp<ISVProcThreadObserver> mProcThreadObserver;
+
+ // vpp input buffer count + output buffer count
+ int32_t mNumISVBuffers;
+ int32_t mNumDecoderBuffers;
+ int32_t mNumDecoderBuffersBak;
+ int64_t mNumBypassFrames;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ uint32_t mUseAndroidNativeBufferIndex;
+ uint32_t mStoreMetaDataInBuffersIndex;
+
+ bool mUseAndroidNativeBuffer;
+ bool mUseAndroidNativeBuffer2;
+
+ bool mVPPEnabled;
+ bool mVPPOn;
+ bool mVPPFlushing;
+ bool mInitialized;
+#ifdef TARGET_VPP_USE_GEN
+ // vpp thread
+ sp<ISVProcessor> mProcThread;
+#else
+ static sp<ISVProcessor> mProcThread;
+#endif
+ // protect create mProcThread instance
+ bool mOwnProcessor;
+ static pthread_mutex_t ProcThreadInstanceLock;
+};
+
+#endif // #define ISV_OMXCOMPONENT_H_
diff --git a/ISV/include/isv_omxcore.h b/ISV/include/isv_omxcore.h
new file mode 100644
index 0000000..01d3cea
--- /dev/null
+++ b/ISV/include/isv_omxcore.h
@@ -0,0 +1,49 @@
+/*
+ * 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 ISV_OMXCORE_H_
+
+#define ISV_OMXCORE_H_
+
+#define ISV_CORE_DEBUG 0
+
+struct ISVOMXCore {
+ typedef OMX_ERRORTYPE (*InitFunc)();
+ typedef OMX_ERRORTYPE (*DeinitFunc)();
+ typedef OMX_ERRORTYPE (*ComponentNameEnumFunc)(
+ OMX_STRING, OMX_U32, OMX_U32);
+
+ typedef OMX_ERRORTYPE (*GetHandleFunc)(
+ OMX_HANDLETYPE *, OMX_STRING, OMX_PTR, OMX_CALLBACKTYPE *);
+
+ typedef OMX_ERRORTYPE (*FreeHandleFunc)(OMX_HANDLETYPE);
+
+ typedef OMX_ERRORTYPE (*GetRolesOfComponentFunc)(
+ OMX_STRING, OMX_U32 *, OMX_U8 **);
+
+ void *mLibHandle;
+
+ InitFunc mInit;
+ DeinitFunc mDeinit;
+ ComponentNameEnumFunc mComponentNameEnum;
+ GetHandleFunc mGetHandle;
+ FreeHandleFunc mFreeHandle;
+ GetRolesOfComponentFunc mGetRolesOfComponentHandle;
+
+ OMX_U32 mNumComponents;
+};
+
+#endif //ISV_OMXCORE_H_
diff --git a/ISV/include/isv_processor.h b/ISV/include/isv_processor.h
new file mode 100644
index 0000000..1b0b07c
--- /dev/null
+++ b/ISV/include/isv_processor.h
@@ -0,0 +1,128 @@
+/*
+ * 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 __ISV_PROCESSOR_H
+#define __ISV_PROCESSOR_H
+
+#include <media/stagefright/MetaData.h>
+#include "isv_worker.h"
+
+#include <utils/Mutex.h>
+#include <utils/threads.h>
+#include <utils/Errors.h>
+#include "isv_bufmanager.h"
+#define ISV_COMPONENT_LOCK_DEBUG 0
+#define ISV_THREAD_DEBUG 0
+
+using namespace android;
+
+typedef enum {
+ kPortIndexInput = 0,
+ kPortIndexOutput = 1
+}PORT_INDEX;
+
+class ISVBufferManager;
+class ISVProcessorObserver: public RefBase
+{
+public:
+ virtual OMX_ERRORTYPE releaseBuffer(PORT_INDEX index, OMX_BUFFERHEADERTYPE* pBuffer, bool bFlush) = 0;
+};
+
+class ISVProcessor : public Thread
+{
+public:
+ ISVProcessor(bool canCallJava, sp<ISVBufferManager> bufferManager, sp<ISVProcessorObserver> observer, uint32_t width, uint32_t height);
+ virtual ~ISVProcessor();
+
+ virtual status_t readyToRun();
+
+ // Derived class must implement threadLoop(). The thread starts its life
+ // here. There are two ways of using the Thread object:
+ // 1) loop: if threadLoop() returns true, it will be called again if
+ // requestExit() wasn't called.
+ // 2) once: if threadLoop() returns false, the thread will exit upon return.
+ virtual bool threadLoop();
+ bool isCurrentThread() const;
+
+ void start();
+ void stop();
+ bool isReadytoRun();
+
+ //add output buffer into mOutputBuffers
+ void addOutput(OMX_BUFFERHEADERTYPE* output);
+ //add intput buffer into mInputBuffers
+ void addInput(OMX_BUFFERHEADERTYPE* input);
+ //notify flush and wait flush finish
+ void notifyFlush();
+ void waitFlushFinished();
+
+private:
+ bool getBufForFirmwareOutput(Vector<ISVBuffer*> *fillBufList,
+ uint32_t *fillBufNum);
+ status_t updateFirmwareOutputBufStatus(uint32_t fillBufNum);
+ bool getBufForFirmwareInput(Vector<ISVBuffer*> *procBufList,
+ ISVBuffer **inputBuf,
+ uint32_t *procBufNum );
+ status_t updateFirmwareInputBufStatus(uint32_t procBufNum);
+ //flush input&ouput buffer queue
+ void flush();
+ //return whether this fps is valid
+ inline bool isFrameRateValid(uint32_t fps);
+ //config vpp filters
+ status_t configFilters(OMX_BUFFERHEADERTYPE* buffer);
+
+private:
+ sp<ISVProcessorObserver> mpOwner;
+ android_thread_id_t mThreadId;
+ bool mThreadRunning;
+
+ sp<ISVWorker> mISVWorker;
+ sp<ISVProfile> mISVProfile;
+ // buffer manager
+ sp<ISVBufferManager> mBufferManager;
+
+ Vector<OMX_BUFFERHEADERTYPE*> mOutputBuffers;
+ Mutex mOutputLock; // to protect access to mOutputBuffers
+ uint32_t mOutputProcIdx;
+
+ Vector<OMX_BUFFERHEADERTYPE*> mInputBuffers;
+ Mutex mInputLock; // to protect access to mFillBuffers
+ uint32_t mInputProcIdx;
+
+ // conditon for thread running
+ Mutex mLock;
+ Condition mRunCond;
+
+ // condition for seek finish
+ Mutex mEndLock;
+ Condition mEndCond;
+
+ uint32_t mNumTaskInProcesing;
+ uint32_t mNumRetry;
+ int64_t mLastTimeStamp;
+ bool mError;
+ bool mbFlush;
+ bool mbBypass;
+ bool mFlagEnd;
+ bool mFrcOn;
+
+ // ISV filter configuration
+ uint32_t mFilters;
+ FilterParam mFilterParam;
+};
+
+#endif /* __ISV_THREAD_H*/
diff --git a/ISV/include/isv_profile.h b/ISV/include/isv_profile.h
new file mode 100644
index 0000000..a79dbb5
--- /dev/null
+++ b/ISV/include/isv_profile.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2014 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 __ISV_PROFILE_H
+#define __ISV_PROFILE_H
+
+#define MAX_BUF_SIZE (4 * 1024)
+#define MAX_TAB_SIZE (10)
+#define MAX_STRING_LEN (50)
+
+#include <utils/RefBase.h>
+using namespace android;
+
+typedef enum _FRC_RATE {
+ FRC_RATE_1X = 1,
+ FRC_RATE_2X,
+ FRC_RATE_2_5X,
+ FRC_RATE_4X
+} FRC_RATE;
+
+typedef enum {
+ VPP_COMMON_ON = 1, // VPP is on
+ VPP_FRC_ON = 1 << 1, // FRC is on
+} VPP_SETTING_STATUS;
+
+typedef struct _ISVParameter {
+ char name[MAX_STRING_LEN];
+ float value;
+} ISVParameter;
+
+typedef struct _ISVConfig {
+ bool enabled;
+ uint32_t minResolution;
+ uint32_t maxResolution;
+ //bool isOn;
+ ISVParameter paraTables[MAX_TAB_SIZE];
+ uint32_t paraSize;
+} ISVConfig;
+
+typedef struct _ISVFRCRate {
+ uint32_t input_fps;
+ FRC_RATE rate;
+} ISVFRCRate;
+
+//FIXME: need align to ProcFilterType
+typedef enum _FilterType {
+ FilterNone = 0x00000001,
+ FilterNoiseReduction = 0x00000002,
+ FilterDeinterlacing = 0x00000004,
+ FilterSharpening = 0x00000008,
+ FilterColorBalance = 0x00000010,
+ FilterDeblocking = 0x00000020,
+ FilterFrameRateConversion = 0x00000040,
+ FilterSkinToneEnhancement = 0x00000080,
+ FilterTotalColorCorrection = 0x00000100,
+ FilterNonLinearAnamorphicScaling = 0x00000200,
+ FilterImageStabilization = 0x00000400,
+} FilterType;
+
+class ISVProfile : public RefBase
+{
+public:
+ ISVProfile(const uint32_t width, const uint32_t height);
+ ~ISVProfile();
+
+ /* get the global ISV setting status */
+ FRC_RATE getFRCRate(uint32_t inputFps);
+
+ /* get filter config data
+ * the filters' status are saved in uint32_t
+ */
+ uint32_t getFilterStatus();
+
+ /* the global setting for VPP */
+ static bool isVPPOn();
+
+ /* the global setting for FRC */
+ static bool isFRCOn();
+
+private:
+ /* Read the global setting for ISV */
+ static int32_t getGlobalStatus();
+
+ /* Get the config data from XML file */
+ void getDataFromXmlFile(void);
+
+ /* Update the filter status */
+ void updateFilterStatus();
+
+ /* handle the XML file */
+ static void startElement(void *userData, const char *name, const char **atts);
+ static void endElement(void *userData, const char *name);
+ int getFilterID(const char * name);
+ uint32_t getResolution(const char * name);
+ void getConfigData(const char *name, const char **atts);
+ void handleFilterParameter(const char *name, const char **atts);
+
+ /* dump the config data */
+ void dumpConfigData();
+
+ typedef enum _ProcFilterType {
+ ProcFilterNone = 0,
+ ProcFilterNoiseReduction,
+ ProcFilterDeinterlacing,
+ ProcFilterSharpening,
+ ProcFilterColorBalance,
+ ProcFilterDeblocking,
+ ProcFilterFrameRateConversion,
+ ProcFilterSkinToneEnhancement,
+ ProcFilterTotalColorCorrection,
+ ProcFilterNonLinearAnamorphicScaling,
+ ProcFilterImageStabilization,
+ ProcFilterCount
+ } ProcFilterType;
+
+private:
+ uint32_t mWidth;
+ uint32_t mHeight;
+
+ /* the filters' status according to resolution
+ * bit 0 used for ProcFilterNone
+ * bit 1 used for ProcFilterNoiseReduction
+ * ...
+ * bit 10 used for ProcFilterImageStabilization
+ */
+ uint32_t mStatus;
+
+ ISVConfig mConfigs[ProcFilterCount];
+ uint32_t mCurrentFilter; //used by parasing xml file
+ ISVFRCRate mFrcRates[MAX_TAB_SIZE];
+ uint32_t mCurrentFrcTab;
+
+ static const int mBufSize = MAX_BUF_SIZE;
+};
+
+#endif /* __ISV_PROFILE_H */
diff --git a/ISV/include/isv_worker.h b/ISV/include/isv_worker.h
new file mode 100644
index 0000000..3eb97c6
--- /dev/null
+++ b/ISV/include/isv_worker.h
@@ -0,0 +1,196 @@
+/*
+ * 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 __ISVWorker_H_
+#define __ISVWorker_H_
+
+#include <va/va.h>
+#include <va/va_vpp.h>
+#include <va/va_android.h>
+#include <OMX_Component.h>
+#include <utils/RefBase.h>
+#include "isv_profile.h"
+#include "isv_bufmanager.h"
+
+#define ANDROID_DISPLAY_HANDLE 0x18C34078
+#define Display unsigned int
+
+//FIXME: copy from OMX_Core.h
+
+/* interlaced frame flag: This flag is set to indicate the buffer contains a
+ * top and bottom field and display ordering is top field first.
+ * @ingroup buf
+ */
+#define OMX_BUFFERFLAG_TFF 0x00010000
+
+/* interlaced frame flag: This flag is set to indicate the buffer contains a
+ * top and bottom field and display ordering is bottom field first.
+ * @ingroup buf
+ */
+#define OMX_BUFFERFLAG_BFF 0x00020000
+
+using namespace android;
+
+typedef enum
+{
+ STATUS_OK = 0,
+ STATUS_NOT_SUPPORT,
+ STATUS_ALLOCATION_ERROR,
+ STATUS_ERROR,
+ STATUS_DATA_RENDERING
+} vpp_status;
+
+typedef enum
+{
+ DEINTERLACE_BOB = 0, // BOB DI
+ DEINTERLACE_ADI = 1, // ADI
+} deinterlace_t;
+
+//Avaiable filter types
+typedef enum
+{
+ FILTER_HQ = 0, // high-quality filter (AVS scaling)
+ FILTER_FAST = 1, // fast filter (bilinear scaling)
+} filter_t;
+
+typedef struct {
+ uint32_t srcWidth;
+ uint32_t srcHeight;
+ uint32_t dstWidth;
+ uint32_t dstHeight;
+ uint32_t denoiseLevel;
+ uint32_t sharpnessLevel;
+ uint32_t colorBalanceLevel;
+ deinterlace_t deinterlaceType;
+ filter_t scalarType;
+ uint32_t frameRate;
+ uint32_t hasEncoder;
+ FRC_RATE frcRate;
+} FilterParam;
+
+class ISVBuffer;
+
+class ISVWorker : public RefBase
+{
+
+ public:
+ // config filters on or off based on video info
+ status_t configFilters(uint32_t filters, const FilterParam* filterParam);
+
+ // Initialize: setupVA()->setupFilters()->setupPipelineCaps()
+ status_t init(uint32_t width, uint32_t height);
+ status_t deinit();
+
+ // Get output buffer number needed for processing
+ uint32_t getProcBufCount();
+
+ // Get output buffer number needed for filling
+ uint32_t getFillBufCount();
+
+ // Send input and output buffers to VSP to begin processing
+ status_t process(ISVBuffer* input, Vector<ISVBuffer*> output, uint32_t outputCount, bool isEOS, uint32_t flags);
+
+ // Fill output buffers given, it's a blocking call
+ status_t fill(Vector<ISVBuffer*> output, uint32_t outputCount);
+
+ // reset index
+ status_t reset();
+
+ // set video display mode
+ void setDisplayMode(int32_t mode);
+
+ // get video display mode
+ int32_t getDisplayMode();
+
+ // check HDMI connection status
+ bool isHdmiConnected();
+
+ uint32_t getVppOutputFps();
+
+ // alloc/free VA surface
+ status_t allocSurface(uint32_t* width, uint32_t* height,
+ uint32_t stride, uint32_t format, uint32_t handle, int32_t* surfaceId);
+ status_t freeSurface(int32_t* surfaceId);
+
+ ISVWorker();
+ ~ISVWorker() {}
+
+ private:
+ // Check if VPP is supported
+ bool isSupport() const;
+
+ // Get output buffer number needed for processing
+ uint32_t getOutputBufCount(uint32_t index);
+
+ // Check filter caps and create filter buffers
+ status_t setupFilters();
+
+ // Setup pipeline caps
+ status_t setupPipelineCaps();
+
+ //check if the input fps is suportted in array fpsSet.
+ bool isFpsSupport(int32_t fps, int32_t *fpsSet, int32_t fpsSetCnt);
+
+ // Debug only
+ // Dump YUV frame
+ status_t dumpYUVFrameData(VASurfaceID surfaceID);
+ status_t writeNV12(int width, int height, unsigned char *out_buf, int y_pitch, int uv_pitch);
+
+ ISVWorker(const ISVWorker &);
+ ISVWorker &operator=(const ISVWorker &);
+
+ public:
+ uint32_t mNumForwardReferences;
+
+ private:
+ // VA common variables
+ VAContextID mVAContext;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ Display * mDisplay;
+ VADisplay mVADisplay;
+ VAConfigID mVAConfig;
+
+ // Forward References Surfaces
+ Vector<VABufferID> mPipelineBuffers;
+ Mutex mPipelineBufferLock; // to protect access to mPipelineBuffers
+ VASurfaceID *mForwardReferences;
+ VASurfaceID mPrevInput;
+ VASurfaceID mPrevOutput;
+
+ // VPP Filters Buffers
+ uint32_t mNumFilterBuffers;
+ VABufferID mFilterBuffers[VAProcFilterCount];
+
+ // VPP filter configuration
+ VABufferID mFilterFrc;
+
+ // VPP filter configuration
+ uint32_t mFilters;
+ FilterParam mFilterParam;
+
+ // status
+ uint32_t mInputIndex;
+ uint32_t mOutputIndex;
+ uint32_t mOutputCount;
+
+ // FIXME: not very sure how to check color standard
+ VAProcColorStandardType in_color_standards[VAProcColorStandardCount];
+ VAProcColorStandardType out_color_standards[VAProcColorStandardCount];
+};
+
+#endif //__ISVWorker_H_
diff --git a/ISV/omx/isv_omxcomponent.cpp b/ISV/omx/isv_omxcomponent.cpp
new file mode 100644
index 0000000..300cdf3
--- /dev/null
+++ b/ISV/omx/isv_omxcomponent.cpp
@@ -0,0 +1,847 @@
+/*
+ * 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 <OMX_Component.h>
+#include "isv_omxcomponent.h"
+#include <media/hardware/HardwareAPI.h>
+#include "isv_profile.h"
+#include <OMX_IndexExt.h>
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "isv-omxil"
+
+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;
+
+#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),
+ mNumBypassFrames(SKIP_FRAME_NUM),
+ mWidth(0),
+ mHeight(0),
+ mUseAndroidNativeBufferIndex(0),
+ mStoreMetaDataInBuffersIndex(0),
+ mUseAndroidNativeBuffer(false),
+ mUseAndroidNativeBuffer2(false),
+ mVPPEnabled(false),
+ mVPPFlushing(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();
+ ALOGI("%s: mVPPOn=%d", __func__, mVPPOn);
+
+ if (mISVBufferManager == NULL) {
+ mISVBufferManager = new ISVBufferManager();
+ }
+
+}
+
+ISVComponent::~ISVComponent()
+{
+ ALOGI("%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);
+
+ 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;
+ ALOGI("%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);
+ def->nBufferCountActual += mNumISVBuffers;
+ def->nBufferCountMin += mNumISVBuffers;
+ }
+ }
+
+ 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__);
+ } else if (*def == ISV_DISABLE)
+ mVPPEnabled = false;
+ return OMX_ErrorNone;
+ }
+
+ OMX_ERRORTYPE 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;
+ 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 0
+ if (def->nPortIndex == kPortIndexInput) {
+ OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def->format.video;
+ mFilterParam.frameRate = video_def->xFramerate;
+
+ if (mISVProfile != NULL && mFilterParam.frameRate != 0) {
+ mFilterParam.frcRate = mISVProfile->getFRCRate(mFilterParam.frameRate);
+ }
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: frame rate is set to %d", __func__, mFilterParam.frameRate);
+ }
+#endif
+ }
+
+ 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);
+
+ return OMX_GetConfig(mComponent, nIndex, pComponentConfigStructure);
+}
+
+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<uint32_t>(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);
+
+ OMX_ERRORTYPE err = OMX_FreeBuffer(mComponent, nPortIndex, pBuffer);
+ if(err == OMX_ErrorNone
+ && mVPPEnabled
+ && mVPPOn
+ && nPortIndex == kPortIndexOutput) {
+ if (mISVBufferManager != NULL && OK != mISVBufferManager->freeBuffer(reinterpret_cast<uint32_t>(pBuffer->pBuffer)))
+ ALOGW("%s: pBuffer %p has not been registered into ISV", __func__, pBuffer);
+ }
+ return err;
+}
+
+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);
+
+ if (mISVBufferManager != NULL) {
+ ISVBuffer* isvBuffer = mISVBufferManager->mapBuffer(reinterpret_cast<uint32_t>(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()) {
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: isvBuffer %p failed to initBufferInfo", __func__, isvBuffer);
+ mVPPEnabled = false;
+ return OMX_FillThisBuffer(mComponent, pBuffer);
+ }
+ }
+
+ if (mNumDecoderBuffers > 0) {
+ mNumDecoderBuffers--;
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: fill pBuffer %p to the decoder, decoder still need extra %d buffers", __func__,
+ pBuffer, mNumDecoderBuffers);
+ 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 || mNumBypassFrames-- > 0) {
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: FillBufferDone pBuffer %p, timeStamp %.2f ms", __func__, pBuffer, pBuffer->nTimeStamp/1E3);
+ 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;
+ }
+ 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:
+ {
+ //FIXME: do we need clear ISV buffer queues for this situation?
+ //mProcThread->notifyFlush();
+ break;
+ }
+
+ default:
+ {
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: EVENT(%d, %ld, %ld)", __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)
+ : mBaseComponent(pBaseComponent),
+ mComponent(pComponent),
+ mpCallBacks(pCallBacks)
+{
+ 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) {
+ pBuffer->nFilledLen = 0;
+ pBuffer->nOffset = 0;
+ OMX_ERRORTYPE 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;
+ 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;
+}
diff --git a/ISV/omx/isv_omxcore.cpp b/ISV/omx/isv_omxcore.cpp
new file mode 100644
index 0000000..35e7a87
--- /dev/null
+++ b/ISV/omx/isv_omxcore.cpp
@@ -0,0 +1,330 @@
+/*
+ * 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 <OMX_Core.h>
+#include <OMX_Component.h>
+#include <dlfcn.h>
+
+#include "isv_omxcore.h"
+#include "isv_omxcomponent.h"
+#include "isv_profile.h"
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "isv-omxil"
+
+#define WRS_CORE_NAME "libwrs_omxil_core_pvwrapped.so"
+#define CORE_NUMBER 1
+#ifdef USE_MEDIASDK
+#define MSDK_CORE_NAME "libmfx_omx_core.so"
+#undef CORE_NUMBER
+#define CORE_NUMBER 2
+#endif
+
+
+using namespace android;
+
+static unsigned int g_initialized = 0;
+static unsigned int g_nr_instances = 0;
+static unsigned int g_nr_comp = 0;
+
+static pthread_mutex_t g_module_lock = PTHREAD_MUTEX_INITIALIZER;
+static ISVOMXCore g_cores[CORE_NUMBER];
+static Vector<ISVComponent*> g_isv_components;
+
+/**********************************************************************************
+ * core entry
+ */
+
+OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_Init(void)
+{
+ int ret;
+ ALOGD_IF(ISV_CORE_DEBUG, "%s: enter", __func__);
+
+ pthread_mutex_lock(&g_module_lock);
+ if (!g_initialized) {
+ for (OMX_U32 i = 0; i < CORE_NUMBER; i++) {
+
+ void* libHandle = NULL;
+ if (i == 0)
+ libHandle = dlopen(WRS_CORE_NAME, RTLD_LAZY);
+#ifdef USE_MEDIASDK
+ else
+ libHandle = dlopen(MSDK_CORE_NAME, RTLD_LAZY);
+#endif
+ if (libHandle != NULL) {
+ g_cores[i].mLibHandle = libHandle;
+ g_cores[i].mInit = (ISVOMXCore::InitFunc)dlsym(libHandle, "OMX_Init");
+ g_cores[i].mDeinit = (ISVOMXCore::DeinitFunc)dlsym(libHandle, "OMX_Deinit");
+
+ g_cores[i].mComponentNameEnum =
+ (ISVOMXCore::ComponentNameEnumFunc)dlsym(libHandle, "OMX_ComponentNameEnum");
+
+ g_cores[i].mGetHandle = (ISVOMXCore::GetHandleFunc)dlsym(libHandle, "OMX_GetHandle");
+ g_cores[i].mFreeHandle = (ISVOMXCore::FreeHandleFunc)dlsym(libHandle, "OMX_FreeHandle");
+
+ g_cores[i].mGetRolesOfComponentHandle =
+ (ISVOMXCore::GetRolesOfComponentFunc)dlsym(
+ libHandle, "OMX_GetRolesOfComponent");
+ if (g_cores[i].mInit != NULL) {
+ (*(g_cores[i].mInit))();
+ }
+ if (g_cores[i].mComponentNameEnum != NULL) {
+ // calculating number of components registered inside given OMX core
+ char tmpComponentName[OMX_MAX_STRINGNAME_SIZE] = { 0 };
+ OMX_U32 tmpIndex = 0;
+ while (OMX_ErrorNone == ((*(g_cores[i].mComponentNameEnum))(tmpComponentName, OMX_MAX_STRINGNAME_SIZE, tmpIndex))) {
+ tmpIndex++;
+ ALOGD_IF(ISV_CORE_DEBUG, "OMX IL core: declares component %s", tmpComponentName);
+ }
+ g_cores[i].mNumComponents = tmpIndex;
+ g_nr_comp += g_cores[i].mNumComponents;
+ ALOGD_IF(ISV_CORE_DEBUG, "OMX IL core: contains %ld components", g_cores[i].mNumComponents);
+ }
+ } else {
+ pthread_mutex_unlock(&g_module_lock);
+ ALOGW("OMX IL core not found");
+ return OMX_ErrorUndefined; // Do we need to return error message
+ }
+ }
+ g_initialized = 1;
+ }
+ pthread_mutex_unlock(&g_module_lock);
+
+ ALOGD_IF(ISV_CORE_DEBUG, "%s: exit done", __func__);
+ return OMX_ErrorNone;
+}
+
+OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_Deinit(void)
+{
+ ALOGD_IF(ISV_CORE_DEBUG, "%s: enter", __func__);
+ OMX_ERRORTYPE ret = OMX_ErrorNone;
+
+ ALOGV("%s: enter", __func__);
+ if (g_initialized == 0)
+ return OMX_ErrorNone;
+
+ pthread_mutex_lock(&g_module_lock);
+ for (OMX_U32 i = 0; i < CORE_NUMBER; i++) {
+ if (g_cores[i].mDeinit != NULL) {
+ (*(g_cores[i].mDeinit))();
+ }
+ }
+ pthread_mutex_unlock(&g_module_lock);
+
+ g_initialized = 0;
+
+ ALOGD_IF(ISV_CORE_DEBUG, "%s: exit %d", __func__, ret);
+ return ret;
+}
+
+OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_ComponentNameEnum(
+ OMX_OUT OMX_STRING cComponentName,
+ OMX_IN OMX_U32 nNameLength,
+ OMX_IN OMX_U32 nIndex)
+{
+ ALOGD_IF(ISV_CORE_DEBUG, "%s: enter", __func__);
+ pthread_mutex_lock(&g_module_lock);
+ OMX_U32 relativeIndex = nIndex;
+ if (nIndex >= g_nr_comp) {
+ pthread_mutex_unlock(&g_module_lock);
+ ALOGD_IF(ISV_CORE_DEBUG, "%s: exit done", __func__);
+ return OMX_ErrorNoMore;
+ }
+
+ for (OMX_U32 i = 0; i < CORE_NUMBER; i++) {
+ if (g_cores[i].mLibHandle == NULL) {
+ continue;
+ }
+ if (relativeIndex < g_cores[i].mNumComponents) {
+ pthread_mutex_unlock(&g_module_lock);
+ ALOGD_IF(ISV_CORE_DEBUG, "%s: found %luth component %s", __func__, nIndex, cComponentName);
+ return ((*(g_cores[i].mComponentNameEnum))(cComponentName, nNameLength, relativeIndex));
+ } else relativeIndex -= g_cores[i].mNumComponents;
+ }
+ pthread_mutex_unlock(&g_module_lock);
+ ALOGD_IF(ISV_CORE_DEBUG, "%s: exit error!!!", __func__);
+ return OMX_ErrorUndefined;
+}
+
+OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_GetHandle(
+ OMX_OUT OMX_HANDLETYPE* pHandle,
+ OMX_IN OMX_STRING cComponentName,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_CALLBACKTYPE *pCallBacks)
+{
+ struct list *entry;
+ OMX_ERRORTYPE ret;
+ OMX_HANDLETYPE tempHandle;
+
+ ALOGD_IF(ISV_CORE_DEBUG, "%s: enter, try to get %s", __func__, cComponentName);
+ pthread_mutex_lock(&g_module_lock);
+
+ // create a isv component instant
+ ISVComponent *pISVComponent = new ISVComponent(pAppData);
+ if (!pISVComponent) {
+ ALOGE("%s: failed to alloc isv omx component", __func__);
+ pthread_mutex_unlock(&g_module_lock);
+ return OMX_ErrorInsufficientResources;
+ }
+
+ OMX_CALLBACKTYPE *pISVCallBacks = pISVComponent->getCallBacks(pCallBacks);
+ if (!pISVCallBacks) {
+ ALOGE("%s: failed to get isv callback functions", __func__);
+ pthread_mutex_unlock(&g_module_lock);
+ return OMX_ErrorInsufficientResources;
+ }
+
+ /* find the real component*/
+ for (OMX_U32 i = 0; i < CORE_NUMBER; i++) {
+ if (g_cores[i].mLibHandle == NULL) {
+ continue;
+ }
+
+ OMX_ERRORTYPE omx_res = (*(g_cores[i].mGetHandle))(
+ &tempHandle,
+ const_cast<char *>(cComponentName),
+ pAppData, pISVCallBacks);
+ if(omx_res == OMX_ErrorNone) {
+ pISVComponent->setComponent(static_cast<OMX_COMPONENTTYPE*>(tempHandle), &g_cores[i]);
+ g_isv_components.push_back(pISVComponent);
+
+ *pHandle = pISVComponent->getBaseComponent();
+
+ ALOGD_IF(ISV_CORE_DEBUG, "%s: found component %s, pHandle %p", __func__, cComponentName, *pHandle);
+ pthread_mutex_unlock(&g_module_lock);
+ return OMX_ErrorNone;
+ }
+ }
+ pthread_mutex_unlock(&g_module_lock);
+
+ delete pISVComponent;
+ pISVComponent = NULL;
+ ALOGE("%s(): exit failure, %s not found", __func__, cComponentName);
+ return OMX_ErrorInvalidComponent;
+}
+
+OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_FreeHandle(
+ OMX_IN OMX_HANDLETYPE hComponent)
+{
+ OMX_ERRORTYPE ret;
+
+ ALOGD_IF(ISV_CORE_DEBUG, "%s: enter, try to free component hanle %p", __func__, hComponent);
+
+ pthread_mutex_lock(&g_module_lock);
+
+ for (OMX_U32 i = 0; i < g_isv_components.size(); i++) {
+ ISVComponent *pComp = g_isv_components.itemAt(i);
+ if (static_cast<OMX_HANDLETYPE>(pComp->getBaseComponent()) == hComponent) {
+ OMX_ERRORTYPE omx_res = pComp->freeComponent();
+ if (omx_res != OMX_ErrorNone) {
+ ALOGE("%s: free OMX handle %p failed", __func__, hComponent);
+ pthread_mutex_unlock(&g_module_lock);
+ return omx_res;
+ }
+ delete pComp;
+ g_isv_components.removeAt(i);
+ ALOGD_IF(ISV_CORE_DEBUG, "%s: free component %p success", __func__, hComponent);
+ pthread_mutex_unlock(&g_module_lock);
+ return OMX_ErrorNone;
+ }
+ }
+ pthread_mutex_unlock(&g_module_lock);
+ ALOGE("%s(): exit failure, component %p not found", __func__, hComponent);
+ return OMX_ErrorInvalidComponent;
+}
+
+OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_SetupTunnel(
+ OMX_IN OMX_HANDLETYPE __maybe_unused hOutput,
+ OMX_IN OMX_U32 __maybe_unused nPortOutput,
+ OMX_IN OMX_HANDLETYPE __maybe_unused hInput,
+ OMX_IN OMX_U32 __maybe_unused nPortInput)
+{
+ return OMX_ErrorNotImplemented;
+}
+
+OMX_API OMX_ERRORTYPE OMX_GetContentPipe(
+ OMX_OUT OMX_HANDLETYPE __maybe_unused *hPipe,
+ OMX_IN OMX_STRING __maybe_unused szURI)
+{
+ return OMX_ErrorNotImplemented;
+}
+
+OMX_API OMX_ERRORTYPE OMX_GetComponentsOfRole (
+ OMX_IN OMX_STRING __maybe_unused role,
+ OMX_INOUT OMX_U32 __maybe_unused *pNumComps,
+ OMX_INOUT OMX_U8 __maybe_unused **compNames)
+{
+ ALOGD_IF(ISV_CORE_DEBUG, "%s: enter", __func__);
+ return OMX_ErrorNotImplemented;
+}
+
+OMX_API OMX_ERRORTYPE OMX_GetRolesOfComponent (
+ OMX_IN OMX_STRING compName,
+ OMX_INOUT OMX_U32 *pNumRoles,
+ OMX_OUT OMX_U8 **roles)
+{
+ ALOGD_IF(ISV_CORE_DEBUG, "%s: enter", __func__);
+ pthread_mutex_lock(&g_module_lock);
+ for (OMX_U32 j = 0; j < CORE_NUMBER; j++) {
+ if (g_cores[j].mLibHandle == NULL) {
+ continue;
+ }
+
+ OMX_U32 numRoles;
+ OMX_ERRORTYPE err = (*(g_cores[j].mGetRolesOfComponentHandle))(
+ const_cast<OMX_STRING>(compName), &numRoles, NULL);
+
+ if (err != OMX_ErrorNone) {
+ continue;
+ }
+
+ if (numRoles > 0) {
+ OMX_U8 **array = new OMX_U8 *[numRoles];
+ for (OMX_U32 i = 0; i < numRoles; ++i) {
+ array[i] = new OMX_U8[OMX_MAX_STRINGNAME_SIZE];
+ }
+
+ OMX_U32 numRoles2 = numRoles;
+ err = (*(g_cores[j].mGetRolesOfComponentHandle))(
+ const_cast<OMX_STRING>(compName), &numRoles2, array);
+
+ *pNumRoles = numRoles;
+
+ for (OMX_U32 i = 0; i < numRoles; i++) {
+ if (i < numRoles-1)
+ roles[i+1] = roles[i] + OMX_MAX_STRINGNAME_SIZE;
+
+ strncpy((OMX_STRING)&roles[i][0],
+ (const OMX_STRING)&array[i][0], OMX_MAX_STRINGNAME_SIZE);
+ delete[] array[i];
+ array[i] = NULL;
+ }
+
+ delete[] array;
+ array = NULL;
+ }
+
+ pthread_mutex_unlock(&g_module_lock);
+ ALOGD_IF(ISV_CORE_DEBUG, "%s: exit done", __func__);
+ return OMX_ErrorNone;
+ }
+ pthread_mutex_unlock(&g_module_lock);
+
+ ALOGE("%s: invalid component", __func__);
+ return OMX_ErrorInvalidComponent;
+}
diff --git a/ISV/profile/isv_profile.cpp b/ISV/profile/isv_profile.cpp
new file mode 100644
index 0000000..9cf91c9
--- /dev/null
+++ b/ISV/profile/isv_profile.cpp
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2014 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 <libexpat/expat.h>
+#include <string.h>
+#include <stdio.h>
+#include <utils/Log.h>
+#include <cutils/properties.h>
+
+#include "isv_profile.h"
+
+#undef LOG_TAG
+#define LOG_TAG "ISVProfile"
+
+#define QCIF_AREA (176 * 144)
+
+using namespace android;
+static const char StatusOn[][5] = {"1frc", "1vpp"};
+
+ISVProfile::ISVProfile(const uint32_t width, const uint32_t height)
+{
+ int i;
+
+ mWidth = width;
+ mHeight = height;
+
+ mCurrentFilter = 0;
+ mCurrentFrcTab = 0;
+ mStatus = 0;
+
+ memset(mConfigs, 0, sizeof(ISVConfig) * ProcFilterCount);
+
+ for (i = 0; i < MAX_TAB_SIZE; i++) {
+ mFrcRates[i].input_fps = 0;
+ mFrcRates[i].rate = FRC_RATE_1X;
+ }
+
+ /* get the vpp global setting */
+ //getGlobalStatus();
+
+ /* load the config data from XML file */
+ getDataFromXmlFile();
+
+ /* update the filter status according to the configs */
+ updateFilterStatus();
+
+ /* dump data for debug */
+ dumpConfigData();
+}
+
+ISVProfile::~ISVProfile()
+{
+}
+
+FRC_RATE ISVProfile::getFRCRate(uint32_t inputFps)
+{
+ FRC_RATE rate = FRC_RATE_1X;
+ int i;
+
+ for (i = 0; i < MAX_TAB_SIZE; i++) {
+ if (mFrcRates[i].input_fps == inputFps) {
+ rate = mFrcRates[i].rate;
+ break;
+ }
+ }
+ return rate;
+}
+
+uint32_t ISVProfile::getFilterStatus()
+{
+ return mStatus;
+}
+
+bool ISVProfile::isVPPOn()
+{
+ int32_t status = getGlobalStatus();
+ if (status == -1) {
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("persist.intel.isv.vpp", value, NULL) &&
+ (!strcmp("1", value) || !strcasecmp("true", value))) {
+ status = VPP_COMMON_ON;
+ }
+ }
+ return (status & VPP_COMMON_ON);
+}
+
+bool ISVProfile::isFRCOn()
+{
+ int32_t status = getGlobalStatus();
+ if (status == -1) {
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("persist.intel.isv.frc", value, NULL) &&
+ (!strcmp("1", value) || !strcasecmp("true", value))) {
+ status = VPP_FRC_ON;
+ }
+ }
+ return (status & VPP_FRC_ON);
+}
+
+void ISVProfile::updateFilterStatus() {
+ int i;
+ uint32_t area = mWidth * mHeight;
+
+ for (i = 1; i < ProcFilterCount; i++) {
+ /* check config */
+ if (mConfigs[i].enabled == false)
+ continue;
+
+ if (area > mConfigs[i].minResolution && area <= mConfigs[i].maxResolution)
+ mStatus |= 1 << i;
+ /* we should cover QCIF */
+ else if (area == mConfigs[i].minResolution && area == QCIF_AREA)
+ mStatus |= 1 << i;
+ }
+}
+
+int ISVProfile::getFilterID(const char * name)
+{
+ int index = 0;
+
+ if (strcmp(name, "ProcFilterNoiseReduction") == 0)
+ index = ProcFilterNoiseReduction;
+ else if (strcmp(name, "ProcFilterDeinterlacing") == 0)
+ index = ProcFilterDeinterlacing;
+ else if (strcmp(name, "ProcFilterSharpening") == 0)
+ index = ProcFilterSharpening;
+ else if (strcmp(name, "ProcFilterColorBalance") == 0)
+ index = ProcFilterColorBalance;
+ else if (strcmp(name, "ProcFilterDeblocking") == 0)
+ index = ProcFilterDeblocking;
+ else if (strcmp(name, "ProcFilterFrameRateConversion") == 0)
+ index = ProcFilterFrameRateConversion;
+ else if (strcmp(name, "ProcFilterSkinToneEnhancement") == 0)
+ index = ProcFilterSkinToneEnhancement;
+ else if (strcmp(name, "ProcFilterTotalColorCorrection") == 0)
+ index = ProcFilterTotalColorCorrection;
+ else if (strcmp(name, "ProcFilterNonLinearAnamorphicScaling") == 0)
+ index = ProcFilterNonLinearAnamorphicScaling;
+ else if (strcmp(name, "ProcFilterImageStabilization") == 0)
+ index = ProcFilterImageStabilization;
+ else
+ index = 0;
+
+ mCurrentFilter = index;
+
+ return index;
+}
+
+uint32_t ISVProfile::getResolution(const char * name)
+{
+ uint32_t width = 0, height = 0;
+ char *p = NULL, *str = NULL;
+ int32_t lenth = strlen(name);
+
+ str = (char*)malloc(lenth+1);
+ if (NULL == str) {
+ ALOGE("%s: failed to malloc buffer", __func__);
+ return 0;
+ }
+ strncpy(str, name, lenth);
+ str[lenth] = '\0';
+
+ p = strtok(str, "x");
+ if (p)
+ width = atoi(p);
+ p = strtok(NULL, "x");
+ if (p)
+ height = atoi(p);
+
+ if (str) {
+ free(str);
+ str = NULL;
+ }
+ return width * height;
+}
+
+void ISVProfile::getConfigData(const char *name, const char **atts)
+{
+ int attIndex = 0;
+
+ if (strcmp(name, "VideoPostProcessSettings") == 0) {
+ return;
+ } else if (strcmp(name, "Filter") == 0) {
+ if (strcmp(atts[attIndex], "name") == 0) {
+ if (getFilterID(atts[attIndex + 1]) == 0) {
+ ALOGE("Couldn't parase the filter %s\n", atts[attIndex+1]);
+ }
+ } else {
+ ALOGE("couldn't handle \"%s\" element for Filter\n", name);
+ }
+ } else if (strcmp(name, "enabled") == 0) {
+ if (mCurrentFilter) {
+ if (!strcmp(atts[attIndex], "value") && !strcmp(atts[attIndex + 1], "true"))
+ mConfigs[mCurrentFilter].enabled = true;
+ } else {
+ ALOGE("Skip this element(%s) becaue this filter couldn't be supported\n", name);
+ }
+ } else if (strcmp(name, "minResolution") == 0) {
+ if (mCurrentFilter && !strcmp(atts[attIndex], "value")) {
+ if (!strcmp(atts[attIndex + 1], "0"))
+ mConfigs[mCurrentFilter].minResolution = 0;
+ else if (!strcmp(atts[attIndex + 1], "FFFFFFFF"))
+ mConfigs[mCurrentFilter].minResolution = 0xFFFFFFFF;
+ else
+ mConfigs[mCurrentFilter].minResolution = getResolution(atts[attIndex + 1]);
+ } else {
+ ALOGE("Skip this element(%s) becaue this filter couldn't be supported\n", name);
+ }
+ } else if (strcmp(name, "maxResolution") == 0) {
+ if (mCurrentFilter && !strcmp(atts[attIndex], "value")) {
+ if (!strcmp(atts[attIndex + 1], "0"))
+ mConfigs[mCurrentFilter].maxResolution = 0;
+ else if (!strcmp(atts[attIndex + 1], "FFFFFFFF"))
+ mConfigs[mCurrentFilter].maxResolution = 0xFFFFFFFF;
+ else
+ mConfigs[mCurrentFilter].maxResolution = getResolution(atts[attIndex + 1]);
+ } else {
+ ALOGE("Skip this element(%s) becaue this filter couldn't be supported\n", name);
+ }
+ } else if (strcmp(name, "FRCRate") == 0) {
+ if (mCurrentFilter == ProcFilterFrameRateConversion) {
+ if (!strcmp(atts[attIndex], "input") && !strcmp(atts[attIndex + 2], "rate")) {
+ mFrcRates[mCurrentFrcTab].input_fps = atoi(atts[attIndex + 1]);
+ if (!strcmp(atts[attIndex + 3], "2"))
+ mFrcRates[mCurrentFrcTab].rate = FRC_RATE_2X;
+ else if (!strcmp(atts[attIndex + 3], "2.5"))
+ mFrcRates[mCurrentFrcTab].rate = FRC_RATE_2_5X;
+ else if (!strcmp(atts[attIndex + 3], "4"))
+ mFrcRates[mCurrentFrcTab].rate = FRC_RATE_4X;
+ else
+ mFrcRates[mCurrentFrcTab].rate = FRC_RATE_1X;
+
+ /* update the pointer */
+ if (mCurrentFrcTab < MAX_TAB_SIZE)
+ mCurrentFrcTab++;
+ }
+ } else {
+ ALOGE("\"FRCRate\" element is only for ProcFilterFrameRateConversion\n");
+ }
+ } else if (strcmp(name, "parameter") == 0) {
+ handleFilterParameter(name, atts);
+ } else
+ ALOGE("Couldn't handle this element %s!\n", name);
+}
+
+void ISVProfile::handleFilterParameter(const char *name, const char **atts)
+{
+ int attIndex = 0;
+
+ if (!mCurrentFilter) {
+ ALOGE("\"%s\" must be in Filter element\n");
+ return;
+ }
+
+ if (strcmp(atts[attIndex], "name") || strcmp(atts[attIndex + 2], "value")) {
+ ALOGE("\"%s\" or \"%s\" couldn't match the %s format\n", atts[attIndex], atts[attIndex + 2], name);
+ return;
+ }
+
+}
+
+void ISVProfile::startElement(void *userData, const char *name, const char **atts)
+{
+ ISVProfile *profile = (ISVProfile *)userData;
+
+ profile->getConfigData(name, atts);
+}
+
+void ISVProfile::endElement(void *userData, const char *name)
+{
+ ISVProfile *profile = (ISVProfile *)userData;
+
+ if (!strcmp(name, "Filter"))
+ profile->mCurrentFilter = 0;
+}
+
+void ISVProfile::getDataFromXmlFile()
+{
+ int done;
+ void *pBuf = NULL;
+ FILE *fp = NULL;
+
+ static const char *defaultXmlFile = "/etc/video_isv_profile.xml";
+
+ fp = ::fopen(defaultXmlFile, "r");
+ if (NULL == fp) {
+ ALOGE("@%s, line:%d, couldn't open profile %s", __func__, __LINE__, defaultXmlFile);
+ return;
+ }
+
+ XML_Parser parser = ::XML_ParserCreate(NULL);
+ if (NULL == parser) {
+ ALOGE("@%s, line:%d, parser is NULL", __func__, __LINE__);
+ goto exit;
+ }
+ ::XML_SetUserData(parser, this);
+ ::XML_SetElementHandler(parser, startElement, endElement);
+
+ pBuf = malloc(mBufSize);
+ if (NULL == pBuf) {
+ ALOGE("@%s, line:%d, failed to malloc buffer", __func__, __LINE__);
+ goto exit;
+ }
+
+ do {
+ int len = (int)::fread(pBuf, 1, mBufSize, fp);
+ if (!len) {
+ if (ferror(fp)) {
+ clearerr(fp);
+ goto exit;
+ }
+ }
+ done = len < mBufSize;
+ if (XML_Parse(parser, (const char *)pBuf, len, done) == XML_STATUS_ERROR) {
+ ALOGE("@%s, line:%d, XML_Parse error", __func__, __LINE__);
+ goto exit;
+ }
+ } while (!done);
+
+exit:
+ if (parser)
+ ::XML_ParserFree(parser);
+ if (pBuf)
+ free(pBuf);
+ if (fp)
+ ::fclose(fp);
+}
+
+int32_t ISVProfile::getGlobalStatus()
+{
+ char path[80];
+ int userId = 0;
+ int32_t status = 0;
+
+ snprintf(path, 80, "/data/user/%d/com.intel.vpp/shared_prefs/vpp_settings.xml", userId);
+ ALOGI("%s: %s",__func__, path);
+ FILE *handle = fopen(path, "r");
+ if(handle == NULL) {
+ ALOGE("%s: failed to open file %s\n", __func__, path);
+ return -1;
+ }
+
+ const int MAXLEN = 1024;
+ char buf[MAXLEN] = {0};
+ memset(buf, 0 ,MAXLEN);
+ if(fread(buf, 1, MAXLEN, handle) <= 0) {
+ ALOGE("%s: failed to read vpp config file %d", __func__, userId);
+ fclose(handle);
+ return -1;
+ }
+ buf[MAXLEN - 1] = '\0';
+
+ if(strstr(buf, StatusOn[0]) != NULL)
+ status |= VPP_FRC_ON;
+
+ if(strstr(buf, StatusOn[1]) != NULL)
+ status |= VPP_COMMON_ON;
+
+ fclose(handle);
+ return status;
+}
+
+void ISVProfile::dumpConfigData()
+{
+ uint32_t i, j;
+ char filterNames[][50] = {
+ "ProcFilterNone",
+ "ProcFilterNoiseReduction",
+ "ProcFilterDeinterlacing",
+ "ProcFilterSharpening",
+ "ProcFilterColorBalance",
+ "ProcFilterDeblocking",
+ "ProcFilterFrameRateConversion",
+ "ProcFilterSkinToneEnhancement",
+ "ProcFilterTotalColorCorrection",
+ "ProcFilterNonLinearAnamorphicScaling",
+ "ProcFilterImageStabilization"
+ };
+ char rateNames[][20] = {
+ "FRC_RATE_0X",
+ "FRC_RATE_1X",
+ "FRC_RATE_2X",
+ "FRC_RATE_2_5X",
+ "FRC_RATE_4X",
+ };
+
+ ALOGI("========== VPP filter configs:==========\n");
+ for (i = 1; i < ProcFilterCount; i++) {
+ ALOGI("name=%s, enabled=%s, minResolution=%d, maxResolution=%d, isOn=%s\n",
+ filterNames[i],
+ (mConfigs[i].enabled == true) ? "true" : "false",
+ mConfigs[i].minResolution,
+ mConfigs[i].maxResolution,
+ ((mStatus & (1 << i)) == 0) ? "false" : "true");
+ if (mConfigs[i].paraSize) {
+ ALOGI("\t\t parameters: ");
+ for(j = 0; j < mConfigs[i].paraSize; j++)
+ ALOGI("%s=%f,", mConfigs[i].paraTables[j].name, mConfigs[i].paraTables[j].value);
+ ALOGI("\n");
+ }
+ }
+
+ ALOGI("========== FRC rate configs:===========\n");
+ for (i = 0; i < MAX_TAB_SIZE; i++) {
+ if (mFrcRates[i].input_fps == 0)
+ break;
+ ALOGI("input_fps=%d, rate=%s\n", mFrcRates[i].input_fps, rateNames[mFrcRates[i].rate]);
+ }
+}