Merge tag android-5.1.0_r1 into AOSP_5.1_MERGE
Change-Id: Iad354104e40ec797045e8bc250815c33e24bcdb7
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..a00e4fc
--- /dev/null
+++ b/ISV/base/isv_bufmanager.cpp
@@ -0,0 +1,256 @@
+/*
+ * 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"
+#ifndef TARGET_VPP_USE_GEN
+#include "hal_public.h"
+#endif
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "isv-omxil"
+
+using namespace android;
+
+#define GRALLOC_SUB_BUFFER_MAX 3
+#define RANDOM_BUFFER_SIZE 200
+static char random_buf[RANDOM_BUFFER_SIZE];
+
+ISVBuffer::~ISVBuffer() {
+ if (mWorker != NULL) {
+ ALOGV("%s: mSurface %d", __func__, mSurface);
+ mWorker->freeSurface(&mSurface);
+ }
+}
+
+status_t ISVBuffer::initBufferInfo(uint32_t hackFormat)
+{
+ 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 ((unsigned long)metaData->pHandle != mGrallocHandle) {
+ if (STATUS_OK != mWorker->freeSurface(&mSurface)) {
+ ALOGE("%s: free surface %d failed.", __func__, mSurface);
+ return UNKNOWN_ERROR;
+ }
+ } else
+ return OK;
+ }
+ mGrallocHandle = (unsigned long)metaData->pHandle;
+ } else {
+ if (mSurface != -1)
+ return OK;
+ mGrallocHandle = mBuffer;
+ }
+
+ int32_t err = 0;
+ if (!mpGralloc) {
+ err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, (hw_module_t const**)&mpGralloc);
+ if (0 != err)
+ return UNKNOWN_ERROR;
+ }
+#ifdef TARGET_VPP_USE_GEN
+ ufo_buffer_details_t info;
+
+ memset(&info, 0, sizeof(ufo_buffer_details_t));
+ err = mpGralloc->perform(mpGralloc, INTEL_UFO_GRALLOC_MODULE_PERFORM_GET_BO_INFO, mGrallocHandle, &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;
+ mSurfaceHeight = grallocHandle->iHeight;
+ mColorFormat = (hackFormat != 0) ? hackFormat : grallocHandle->iFormat;
+#endif
+ 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 ISVBuffer::clearIfNeed()
+{
+#ifndef TARGET_VPP_USE_GEN
+ static bool bRandomBufferInit = false;
+ if (!bRandomBufferInit) {
+ time_t my_time;
+ srand((unsigned)time(&my_time));
+ for (int32_t i = 0; i < RANDOM_BUFFER_SIZE; i++)
+ random_buf[i] = (char)(((double)rand()/(double)RAND_MAX) * 255.0);
+ bRandomBufferInit = true;
+ }
+
+ if ((mFlags & ISV_BUFFER_NEED_CLEAR) && mpGralloc) {
+ int32_t usage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+ void *vaddr[GRALLOC_SUB_BUFFER_MAX];
+
+ int32_t err = mpGralloc->lock(mpGralloc, (buffer_handle_t)mGrallocHandle, usage, 0, 0, mStride, mSurfaceHeight, &vaddr[0]);
+
+ if (0 != err) {
+ ALOGE("%s: get graphic buffer ptr failed", __func__);
+ return UNKNOWN_ERROR;
+ }
+
+ int32_t buffer_size = mStride * mSurfaceHeight * 3 / 2;
+ char* ptr = (char*)vaddr[0];
+ for (int32_t i = 0; i < buffer_size/RANDOM_BUFFER_SIZE; i++) {
+ memcpy(ptr, random_buf, sizeof(random_buf));
+ ptr += sizeof(random_buf);
+ }
+ mpGralloc->unlock(mpGralloc, (buffer_handle_t)mGrallocHandle);
+ ALOGD_IF(ISV_BUFFER_MANAGER_DEBUG, "%s: clear isv buffer %p finished, buffer size %d", __func__, this, buffer_size);
+ mFlags &= ~ISV_BUFFER_NEED_CLEAR;
+ }
+#endif
+ 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(unsigned long handle)
+{
+ Mutex::Autolock autoLock(mBufferLock);
+ for (uint32_t i = 0; i < mBuffers.size(); i++) {
+ ISVBuffer* isvBuffer = mBuffers.itemAt(i);
+ if (isvBuffer->getHandle() == 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(unsigned long 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() == 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,
+ mNeedClearBuffers ? ISVBuffer::ISV_BUFFER_NEED_CLEAR : 0);
+
+ 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() == (unsigned long)nativeBuffer->handle) {
+ ALOGE("%s: this buffer 0x%08x has already been registered", __func__, nativeBuffer->handle);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ ISVBuffer* isvBuffer = new ISVBuffer(mWorker,
+ (unsigned long)nativeBuffer->handle, (unsigned long)nativeBuffer->handle,
+ nativeBuffer->width, nativeBuffer->height,
+ nativeBuffer->stride, nativeBuffer->format,
+ mMetaDataMode ? ISVBuffer::ISV_BUFFER_METADATA : ISVBuffer::ISV_BUFFER_GRALLOC,
+ mNeedClearBuffers ? ISVBuffer::ISV_BUFFER_NEED_CLEAR : 0);
+
+ 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(unsigned long handle)
+{
+ Mutex::Autolock autoLock(mBufferLock);
+ for (uint32_t i = 0; i < mBuffers.size(); i++) {
+ ISVBuffer* isvBuffer = mBuffers.itemAt(i);
+ if (isvBuffer->getHandle() == handle)
+ return isvBuffer;
+ }
+ return NULL;
+}
+
+status_t ISVBufferManager::setBuffersFlag(uint32_t flag)
+{
+ Mutex::Autolock autoLock(mBufferLock);
+
+ if (flag & ISVBuffer::ISV_BUFFER_NEED_CLEAR) {
+ if (mBuffers.size() == 0)
+ mNeedClearBuffers = true;
+ else {
+ for (uint32_t i = 0; i < mBuffers.size(); i++) {
+ ISVBuffer* isvBuffer = mBuffers.itemAt(i);
+ isvBuffer->setFlag(ISVBuffer::ISV_BUFFER_NEED_CLEAR);
+ }
+ }
+ }
+ return OK;
+}
diff --git a/ISV/base/isv_processor.cpp b/ISV/base/isv_processor.cpp
new file mode 100644
index 0000000..990c15a
--- /dev/null
+++ b/ISV/base/isv_processor.cpp
@@ -0,0 +1,634 @@
+/*
+ * 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 10
+
+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),
+ 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();
+ mTimeWindow.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);
+ if (!outputBuffer) {
+ ALOGE("%s: failed to fetch output buffer for sync.", __func__);
+ return false;
+ }
+ unsigned long fillHandle = reinterpret_cast<unsigned long>(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;
+ bool cropChanged = false;
+
+ 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);
+ unsigned long inputHandle = reinterpret_cast<unsigned long>(inputBuffer->pBuffer);
+ ISVBuffer* inputBuf = mBufferManager->mapBuffer(inputHandle);
+ uint32_t flags = inputBuf->getFlags();
+
+ if (flags & ISVBuffer::ISV_BUFFER_CROP_CHANGED) {
+ err = mpOwner->reportOutputCrop();
+ if (err != OMX_ErrorNone) {
+ ALOGE("%s: failed to reportOutputCrop", __func__);
+ return UNKNOWN_ERROR;
+ }
+ cropChanged = true;
+ inputBuf->unsetFlag(ISVBuffer::ISV_BUFFER_CROP_CHANGED);
+ }
+
+ 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 == 24) {
+ if (fillBufNum == 2) {
+ outputBuffer->nTimeStamp = timeUs + 1000000ll * (i + 1) / 60 - 1000000ll * 1 / 24;
+ } else if (fillBufNum == 3) {
+ outputBuffer->nTimeStamp = timeUs + 1000000ll * (i + 3) / 60 - 1000000ll * 2 / 24;
+ }
+ }
+ else
+ outputBuffer->nTimeStamp = timeUs - 1000000ll * (fillBufNum - i - 1) / (mFilterParam.frameRate * 2);
+ }
+
+ //return filled buffers for rendering
+ //skip rendering for crop change
+ err = mpOwner->releaseBuffer(kPortIndexOutput, outputBuffer, cropChanged);
+
+ 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;
+
+ if (mbFlush) {
+ *inputBuf = NULL;
+ *procBufNum = 0;
+ return true;
+ }
+
+ 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__);
+ inputBuffer = mInputBuffers.itemAt(mInputProcIdx);
+ if (!inputBuffer) {
+ ALOGE("%s: failed to get input buffer for processing.", __func__);
+ return false;
+ }
+ unsigned long inputHandle = reinterpret_cast<unsigned long>(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__);
+ for (int32_t i = 0; i < procBufCount; i++) {
+ outputBuffer = mOutputBuffers.itemAt(mOutputProcIdx + i);
+ if (!outputBuffer) {
+ ALOGE("%s: failed to get output buffer for processing.", __func__);
+ return false;
+ }
+ unsigned long outputHandle = reinterpret_cast<unsigned long>(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);
+ if (ret == STATUS_OK) {
+ // 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;
+ }
+ 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::configFRC(uint32_t fps)
+{
+ if (isFrameRateValid(fps)) {
+ if (fps == 50 || fps == 60) {
+ ALOGD_IF(ISV_THREAD_DEBUG, "%s: %d fps don't need do FRC, so disable FRC", __func__, fps);
+ mFilters &= ~FilterFrameRateConversion;
+ mFilterParam.frcRate = FRC_RATE_1X;
+ } else {
+ mFilterParam.frameRate = fps;
+ mFilterParam.frcRate = mISVProfile->getFRCRate(mFilterParam.frameRate);
+ ALOGD_IF(ISV_THREAD_DEBUG, "%s: fps is set to %d, frc rate is %d", __func__,
+ mFilterParam.frameRate, mFilterParam.frcRate);
+ }
+ return OK;
+ }
+
+ return UNKNOWN_ERROR;
+}
+
+status_t ISVProcessor::calculateFps(int64_t timeStamp, uint32_t* fps)
+{
+ int32_t i = 0;
+ *fps = 0;
+
+ mTimeWindow.push_back(timeStamp);
+ if (mTimeWindow.size() > WINDOW_SIZE) {
+ mTimeWindow.removeAt(0);
+ }
+ else if (mTimeWindow.size() < WINDOW_SIZE)
+ return NOT_ENOUGH_DATA;
+
+ int64_t delta = mTimeWindow[WINDOW_SIZE-1] - mTimeWindow[0];
+ if (delta == 0)
+ return NOT_ENOUGH_DATA;
+
+ *fps = ceil(1.0 / delta * 1E6 * (WINDOW_SIZE-1));
+ return OK;
+}
+
+status_t ISVProcessor::configFilters(OMX_BUFFERHEADERTYPE* buffer)
+{
+ if ((mFilters & FilterFrameRateConversion) != 0) {
+ if (!isFrameRateValid(mFilterParam.frameRate)) {
+ if (mNumRetry++ < MAX_RETRY_NUM) {
+ uint32_t fps = 0;
+ if (OK != calculateFps(buffer->nTimeStamp, &fps))
+ return NOT_ENOUGH_DATA;
+
+ if (OK != configFRC(fps))
+ return NOT_ENOUGH_DATA;
+ } 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..3f699a5
--- /dev/null
+++ b/ISV/base/isv_worker.cpp
@@ -0,0 +1,1040 @@
+/*
+ * 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, unsigned long 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, stde;
+ VAProcFilterParameterBufferDeinterlacing deint;
+ VAProcFilterParameterBufferColorBalance color[COLOR_NUM];
+ VAProcFilterParameterBufferFrameRateConversion frc;
+ VABufferID deblockId, denoiseId, deintId, sharpenId, colorId, frcId, stdeId;
+ uint32_t numCaps;
+ VAProcFilterCap deblockCaps, denoiseCaps, sharpenCaps, frcCaps, stdeCaps;
+ 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, "8.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;
+ case VAProcFilterSkinToneEnhancement:
+ if((mFilters & FilterSkinToneEnhancement) != 0) {
+ // check filter caps
+ numCaps = 1;
+ vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext,
+ VAProcFilterSkinToneEnhancement,
+ &stdeCaps,
+ &numCaps);
+ CHECK_VASTATUS("vaQueryVideoProcFilterCaps for skintone");
+ // create parameter buffer
+ stde.type = VAProcFilterSkinToneEnhancement;
+#ifdef TARGET_VPP_USE_GEN
+ char propValueString[PROPERTY_VALUE_MAX];
+
+ // placeholder for vpg driver: can't support skintone factor auto adjust, so leave config to user.
+ property_get("vpp.filter.skintone.factor", propValueString, "8.0");
+ stde.value = atof(propValueString);
+ stde.value = (stde.value < 0.0f) ? 0.0f : stde.value;
+ stde.value = (stde.value > 8.0f) ? 8.0f : stde.value;
+#else
+ stde.value = stdeCaps.range.default_value;
+#endif
+ vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
+ VAProcFilterParameterBufferType, sizeof(stde), 1,
+ &stde, &stdeId);
+ CHECK_VASTATUS("vaCreateBuffer for skintone");
+ mFilterBuffers[mNumFilterBuffers] = stdeId;
+ mNumFilterBuffers++;
+ }
+ break;
+ default:
+ ALOGW("%s: Not supported filter 0x%08x", __func__, supportedFilters[i]);
+ 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 = STATUS_OK;
+ uint32_t i = 0;
+
+ if (isEOS) {
+ if (mInputIndex == 0) {
+ ALOGV("%s: don't need to flush VSP", __func__);
+ return STATUS_OK;
+ }
+ input = VA_INVALID_SURFACE;
+ outputCount = 1;
+ output[0] = mPrevOutput;
+ } else {
+ if (!inputBuffer || outputBuffer.size() != outputCount) {
+ ALOGE("%s: invalid input/output buffer", __func__);
+ return STATUS_ERROR;
+ }
+
+ if (outputCount < 1 || outputCount > 4) {
+ ALOGE("%s: invalid outputCount", __func__);
+ return STATUS_ERROR;
+ }
+
+ input = inputBuffer->getSurface();
+ 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;
+ ALOGV("reset");
+ if (mOutputCount > 0) {
+ 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..18c3209
--- /dev/null
+++ b/ISV/include/isv_bufmanager.h
@@ -0,0 +1,179 @@
+/*
+ * 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"
+#ifndef TARGET_VPP_USE_GEN
+#include "hal_public.h"
+#endif
+
+using namespace android;
+
+#define ISV_BUFFER_MANAGER_DEBUG 0
+
+class ISVWorker;
+
+class ISVBuffer
+{
+public:
+ typedef enum {
+ ISV_BUFFER_GRALLOC,
+ ISV_BUFFER_METADATA,
+ } ISV_BUFFERTYPE;
+
+ typedef enum {
+ ISV_BUFFER_NEED_CLEAR = 0x00000001,
+ ISV_BUFFER_CROP_CHANGED = 0x00000002,
+ } ISV_BUFFERFLAG;
+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,
+ unsigned long buffer, unsigned long grallocHandle,
+ uint32_t width, uint32_t height,
+ uint32_t stride, uint32_t colorFormat,
+ ISV_BUFFERTYPE type, uint32_t flag)
+ :mWorker(worker),
+ mBuffer(buffer),
+ mGrallocHandle(grallocHandle),
+ mWidth(width),
+ mHeight(height),
+ mSurfaceHeight(0),
+ mStride(stride),
+ mColorFormat(colorFormat),
+ mType(type),
+ mSurface(-1),
+ mFlags(flag),
+ mpGralloc(NULL) {}
+
+ ISVBuffer(sp<ISVWorker> worker,
+ unsigned long buffer,
+ ISV_BUFFERTYPE type,
+ uint32_t flag)
+ :mWorker(worker),
+ mBuffer(buffer),
+ mGrallocHandle(0),
+ mWidth(0),
+ mHeight(0),
+ mSurfaceHeight(0),
+ mStride(0),
+ mColorFormat(0),
+ mType(type),
+ mSurface(-1),
+ mFlags(flag),
+ mpGralloc(NULL) {}
+
+ ~ISVBuffer();
+
+ // init buffer info
+ // FIXME: hackFormat is for VP9, should be removed in future
+ status_t initBufferInfo(uint32_t hackFormat);
+
+ // get va surface
+ int32_t getSurface() { return mSurface; }
+ // get buffer handle
+ unsigned long getHandle() { return mBuffer; }
+ // set/clear/get flag
+ uint32_t getFlags() { return mFlags; }
+ void setFlag(uint32_t flag) { mFlags |= flag; return; }
+ void unsetFlag(uint32_t flag) { mFlags &= ~flag; return; }
+ status_t clearIfNeed();
+
+private:
+
+ sp<ISVWorker> mWorker;
+ unsigned long mBuffer;
+ unsigned long mGrallocHandle;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ uint32_t mSurfaceHeight;
+ uint32_t mStride;
+ uint32_t mColorFormat;
+ ISV_BUFFERTYPE mType;
+ int32_t mSurface;
+ uint32_t mFlags;
+ gralloc_module_t* mpGralloc;
+};
+
+class ISVBufferManager: public RefBase
+{
+public:
+ ISVBufferManager()
+ :mWorker(NULL),
+ mMetaDataMode(false),
+ mNeedClearBuffers(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(unsigned long handle);
+ status_t freeBuffer(unsigned long handle);
+
+ // Map to ISVBuffer
+ ISVBuffer* mapBuffer(unsigned long handle);
+ // set isv worker
+ void setWorker(sp<ISVWorker> worker) { mWorker = worker; }
+ void setMetaDataMode(bool metaDataMode) { mMetaDataMode = metaDataMode; }
+ // set buffer flag.
+ status_t setBuffersFlag(uint32_t flag);
+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
+ bool mNeedClearBuffers;
+};
+
+
+#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..5acea30
--- /dev/null
+++ b/ISV/include/isv_omxcomponent.h
@@ -0,0 +1,300 @@
+/*
+ * 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
+
+#ifdef TARGET_VPP_USE_GEN
+#define MIN_INPUT_NUM (3)
+#define MIN_OUTPUT_NUM (3)
+#else
+#define MIN_INPUT_NUM (4) // 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
+#endif
+#define MIN_ISV_BUFFER_NUM ((MIN_OUTPUT_NUM) + (MIN_INPUT_NUM))
+#define UNDEQUEUED_NUM (4) // display system hold 4 buffers
+
+using namespace android;
+class ISVComponent;
+
+class ISVProcThreadObserver: public ISVProcessorObserver
+{
+public:
+ ISVProcThreadObserver(OMX_COMPONENTTYPE *pBaseComponent, OMX_COMPONENTTYPE *pComponent, OMX_CALLBACKTYPE *pCallBacks, sp<ISVBufferManager> bufferManager);
+ ~ISVProcThreadObserver();
+
+ virtual OMX_ERRORTYPE releaseBuffer(PORT_INDEX index, OMX_BUFFERHEADERTYPE* pBuffer, bool flush);
+ virtual OMX_ERRORTYPE reportOutputCrop();
+private:
+ OMX_COMPONENTTYPE *mBaseComponent;
+ OMX_COMPONENTTYPE *mComponent;
+ OMX_CALLBACKTYPE *mpCallBacks;
+ sp<ISVBufferManager> mISVBufferManager;
+};
+
+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;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ uint32_t mUseAndroidNativeBufferIndex;
+ uint32_t mStoreMetaDataInBuffersIndex;
+ uint32_t mHackFormat;
+
+ bool mUseAndroidNativeBuffer;
+ bool mUseAndroidNativeBuffer2;
+
+ bool mVPPEnabled;
+ bool mVPPOn;
+ bool mVPPFlushing;
+ bool mOutputCropChanged;
+ 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..c50fb65
--- /dev/null
+++ b/ISV/include/isv_processor.h
@@ -0,0 +1,134 @@
+/*
+ * 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;
+ virtual OMX_ERRORTYPE reportOutputCrop() = 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();
+
+ //configure FRC factor
+ status_t configFRC(uint32_t fps);
+ //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);
+ //auto calculate fps if the framework doesn't set the correct fps
+ status_t calculateFps(int64_t timeStamp, 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;
+
+ const static uint32_t WINDOW_SIZE = 4; // must >= 2
+ Vector<int64_t>mTimeWindow;
+ // conditon for thread running
+ Mutex mLock;
+ Condition mRunCond;
+
+ // condition for seek finish
+ Mutex mEndLock;
+ Condition mEndCond;
+
+ uint32_t mNumTaskInProcesing;
+ uint32_t mNumRetry;
+ 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..d9a04fd
--- /dev/null
+++ b/ISV/include/isv_profile.h
@@ -0,0 +1,157 @@
+/*
+ * 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);
+ void handleCommonParameter(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 default value of VPP/FRC.
+ * They will be read from config xml file.
+ */
+ int32_t mDefaultVPPStatus;
+ int32_t mDefaultFRCStatus;
+
+ /* 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..2efee2a
--- /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, unsigned long 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..94d6f6d
--- /dev/null
+++ b/ISV/omx/isv_omxcomponent.cpp
@@ -0,0 +1,920 @@
+/*
+ * 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>
+#include <hal_public.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),
+ mWidth(0),
+ mHeight(0),
+ mUseAndroidNativeBufferIndex(0),
+ mStoreMetaDataInBuffersIndex(0),
+ mHackFormat(0),
+ mUseAndroidNativeBuffer(false),
+ mUseAndroidNativeBuffer2(false),
+ mVPPEnabled(false),
+ mVPPFlushing(false),
+ mOutputCropChanged(false),
+ mInitialized(false),
+#ifdef TARGET_VPP_USE_GEN
+ mProcThread(NULL),
+#endif
+ mOwnProcessor(false)
+{
+ memset(&mBaseComponent, 0, sizeof(OMX_COMPONENTTYPE));
+ /* handle initialization */
+ SetTypeHeader(&mBaseComponent, sizeof(mBaseComponent));
+ mBaseComponent.pApplicationPrivate = pAppData;
+ mBaseComponent.pComponentPrivate = static_cast<OMX_PTR>(this);
+
+ /* connect handle's functions */
+ mBaseComponent.GetComponentVersion = NULL;
+ mBaseComponent.SendCommand = SendCommand;
+ mBaseComponent.GetParameter = GetParameter;
+ mBaseComponent.SetParameter = SetParameter;
+ mBaseComponent.GetConfig = GetConfig;
+ mBaseComponent.SetConfig = SetConfig;
+ mBaseComponent.GetExtensionIndex = GetExtensionIndex;
+ mBaseComponent.GetState = GetState;
+ mBaseComponent.ComponentTunnelRequest = NULL;
+ mBaseComponent.UseBuffer = UseBuffer;
+ mBaseComponent.AllocateBuffer = AllocateBuffer;
+ mBaseComponent.FreeBuffer = FreeBuffer;
+ mBaseComponent.EmptyThisBuffer = EmptyThisBuffer;
+ mBaseComponent.FillThisBuffer = FillThisBuffer;
+ mBaseComponent.SetCallbacks = SetCallbacks;
+ mBaseComponent.ComponentDeInit = NULL;
+ mBaseComponent.UseEGLImage = NULL;
+ mBaseComponent.ComponentRoleEnum = ComponentRoleEnum;
+ g_isv_components.push_back(static_cast<ISVComponent*>(this));
+
+ mVPPOn = ISVProfile::isFRCOn() || ISVProfile::isVPPOn();
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: mVPPOn %d", __func__, mVPPOn);
+
+ if (mISVBufferManager == NULL) {
+ mISVBufferManager = new ISVBufferManager();
+ }
+
+}
+
+ISVComponent::~ISVComponent()
+{
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s", __func__);
+ if (mpISVCallBacks) {
+ free(mpISVCallBacks);
+ mpISVCallBacks = NULL;
+ }
+
+ for (OMX_U32 i = 0; i < g_isv_components.size(); i++) {
+ if (g_isv_components.itemAt(i) == static_cast<ISVComponent*>(this)) {
+ g_isv_components.removeAt(i);
+ }
+ }
+
+ memset(&mBaseComponent, 0, sizeof(OMX_COMPONENTTYPE));
+ deinit();
+ mVPPOn = false;
+ mISVBufferManager = NULL;
+}
+
+status_t ISVComponent::init(int32_t width, int32_t height)
+{
+ if (mInitialized)
+ return STATUS_OK;
+
+ bool frcOn = false;
+ if (mProcThreadObserver == NULL)
+ mProcThreadObserver = new ISVProcThreadObserver(&mBaseComponent, mComponent, mpCallBacks, mISVBufferManager);
+
+ pthread_mutex_lock(&ProcThreadInstanceLock);
+ if (mProcThread == NULL) {
+ mProcThread = new ISVProcessor(false, mISVBufferManager, mProcThreadObserver, width, height);
+ mOwnProcessor = true;
+ mProcThread->start();
+ }
+#ifndef TARGET_VPP_USE_GEN
+ else {
+ mVPPEnabled = false;
+ mOwnProcessor = false;
+ ALOGI("%s: failed to alloc isv processor", __func__);
+ pthread_mutex_unlock(&ProcThreadInstanceLock);
+ return STATUS_ERROR;
+ }
+#endif
+ pthread_mutex_unlock(&ProcThreadInstanceLock);
+
+ mInitialized = true;
+ return STATUS_OK;
+}
+
+void ISVComponent::deinit()
+{
+ pthread_mutex_lock(&ProcThreadInstanceLock);
+ if (mOwnProcessor) {
+ if (mProcThread != NULL) {
+ mProcThread->stop();
+ mProcThread = NULL;
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: delete ISV processor ", __func__);
+ }
+ }
+ pthread_mutex_unlock(&ProcThreadInstanceLock);
+
+ mProcThreadObserver = NULL;
+
+ mInitialized = false;
+}
+
+OMX_CALLBACKTYPE* ISVComponent::getCallBacks(OMX_CALLBACKTYPE* pCallBacks)
+{
+ //reset component callback functions
+ mpCallBacks = pCallBacks;
+ if (mpISVCallBacks) {
+ free(mpISVCallBacks);
+ mpISVCallBacks = NULL;
+ }
+
+ mpISVCallBacks = (OMX_CALLBACKTYPE *)calloc(1, sizeof(OMX_CALLBACKTYPE));
+ if (!mpISVCallBacks) {
+ ALOGE("%s: failed to alloc isv callbacks", __func__);
+ return NULL;
+ }
+ mpISVCallBacks->EventHandler = EventHandler;
+ mpISVCallBacks->EmptyBufferDone = pCallBacks->EmptyBufferDone;
+ mpISVCallBacks->FillBufferDone = FillBufferDone;
+ return mpISVCallBacks;
+}
+
+OMX_ERRORTYPE ISVComponent::SendCommand(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_COMMANDTYPE Cmd,
+ OMX_IN OMX_U32 nParam1,
+ OMX_IN OMX_PTR pCmdData)
+{
+ GET_ISVOMX_COMPONENT(hComponent);
+
+ return pComp->ISV_SendCommand(Cmd, nParam1, pCmdData);
+}
+
+OMX_ERRORTYPE ISVComponent::ISV_SendCommand(
+ OMX_IN OMX_COMMANDTYPE Cmd,
+ OMX_IN OMX_U32 nParam1,
+ OMX_IN OMX_PTR pCmdData)
+{
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: Cmd index 0x%08x, nParam1 %d", __func__, Cmd, nParam1);
+
+ if (mVPPEnabled && mVPPOn) {
+ if ((Cmd == OMX_CommandFlush && (nParam1 == kPortIndexOutput || nParam1 == OMX_ALL))
+ || (Cmd == OMX_CommandStateSet && nParam1 == OMX_StateIdle)
+ || (Cmd == OMX_CommandPortDisable && nParam1 == 1)) {
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: receive flush command, notify vpp thread to flush(Seek begin)", __func__);
+ mVPPFlushing = true;
+ mProcThread->notifyFlush();
+ }
+ }
+
+ return OMX_SendCommand(mComponent, Cmd, nParam1, pCmdData);
+}
+
+OMX_ERRORTYPE ISVComponent::GetParameter(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_INDEXTYPE nParamIndex,
+ OMX_INOUT OMX_PTR pComponentParameterStructure)
+{
+ GET_ISVOMX_COMPONENT(hComponent);
+
+ return pComp->ISV_GetParameter(nParamIndex, pComponentParameterStructure);
+}
+
+OMX_ERRORTYPE ISVComponent::ISV_GetParameter(
+ OMX_IN OMX_INDEXTYPE nParamIndex,
+ OMX_INOUT OMX_PTR pComponentParameterStructure)
+{
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: nIndex 0x%08x", __func__, nParamIndex);
+
+ OMX_ERRORTYPE err = OMX_GetParameter(mComponent, nParamIndex, pComponentParameterStructure);
+
+ if (err == OMX_ErrorNone && mVPPEnabled && mVPPOn) {
+ OMX_PARAM_PORTDEFINITIONTYPE *def =
+ static_cast<OMX_PARAM_PORTDEFINITIONTYPE*>(pComponentParameterStructure);
+
+ if (nParamIndex == OMX_IndexParamPortDefinition
+ && def->nPortIndex == kPortIndexOutput) {
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: orignal bufferCountActual %d, bufferCountMin %d", __func__, def->nBufferCountActual, def->nBufferCountMin);
+#ifndef TARGET_VPP_USE_GEN
+ //FIXME: THIS IS A HACK!! Request NV12 buffer for YV12 format
+ //because VSP only support NV12 output
+ OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def->format.video;
+ if (video_def->eColorFormat == VA_FOURCC_YV12) {
+ //FIXME workaround Disable ISV for YV12 input
+ mVPPEnabled = false;
+ ALOGI("%s: Disable ISV for YV12 input. mVPPEnabled %d", __func__, mVPPEnabled);
+ } else {
+ //FIXME workaround avc low resolution playback
+ def->nBufferCountActual += mNumISVBuffers + 9;
+ def->nBufferCountMin += mNumISVBuffers + 9;
+ }
+#endif
+ }
+ }
+
+ return err;
+}
+
+OMX_ERRORTYPE ISVComponent::SetParameter(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_INDEXTYPE nIndex,
+ OMX_IN OMX_PTR pComponentParameterStructure)
+{
+ GET_ISVOMX_COMPONENT(hComponent);
+
+ return pComp->ISV_SetParameter(nIndex, pComponentParameterStructure);
+}
+
+OMX_ERRORTYPE ISVComponent::ISV_SetParameter(
+ OMX_IN OMX_INDEXTYPE nIndex,
+ OMX_IN OMX_PTR pComponentParameterStructure)
+{
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: nIndex 0x%08x", __func__, nIndex);
+
+ if (nIndex == static_cast<OMX_INDEXTYPE>(OMX_IndexExtSetISVMode)) {
+ ISV_MODE* def = static_cast<ISV_MODE*>(pComponentParameterStructure);
+
+ if (*def == ISV_AUTO) {
+ mVPPEnabled = true;
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: mVPPEnabled -->true", __func__);
+#ifndef TARGET_VPP_USE_GEN
+ if (mVPPOn) {
+ uint32_t number = MIN_INPUT_NUM + MIN_OUTPUT_NUM;
+ OMX_INDEXTYPE index;
+ status_t error =
+ OMX_GetExtensionIndex(
+ mComponent,
+ (OMX_STRING)"OMX.Intel.index.vppBufferNum",
+ &index);
+ if (error == OK) {
+ error = OMX_SetParameter(mComponent, index, (OMX_PTR)&number);
+ } else {
+ // ingore this error
+ ALOGW("Get vpp number index failed");
+ }
+ }
+#endif
+ } else if (*def == ISV_DISABLE)
+ mVPPEnabled = false;
+ return OMX_ErrorNone;
+ }
+
+ 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 (def->nPortIndex == kPortIndexInput) {
+ OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def->format.video;
+
+ if (mProcThread != NULL)
+ mProcThread->configFRC(video_def->xFramerate);
+ }
+ }
+
+ if (mUseAndroidNativeBuffer
+ && nIndex == static_cast<OMX_INDEXTYPE>(mUseAndroidNativeBufferIndex)) {
+ UseAndroidNativeBufferParams *def =
+ static_cast<UseAndroidNativeBufferParams*>(pComponentParameterStructure);
+
+ if (mISVBufferManager != NULL && OK != mISVBufferManager->useBuffer(def->nativeBuffer)) {
+ ALOGE("%s: failed to register graphic buffers to ISV, set mVPPEnabled -->false", __func__);
+ mVPPEnabled = false;
+ }
+ }
+
+ if (nIndex == static_cast<OMX_INDEXTYPE>(mStoreMetaDataInBuffersIndex)) {
+ StoreMetaDataInBuffersParams *params = static_cast<StoreMetaDataInBuffersParams*>(pComponentParameterStructure);
+ if (params->nPortIndex == kPortIndexOutput) {
+ if (mISVBufferManager != NULL) {
+ bool bMetaDataMode = params->bStoreMetaData == OMX_TRUE;
+ mISVBufferManager->setMetaDataMode(bMetaDataMode);
+ } else {
+ ALOGE("%s: falied to set Meta Data Mode ", __func__);
+ }
+ }
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: receive ISVStoreMetaDataInBuffers mISVWorkMode %d", __func__, (params->bStoreMetaData == OMX_TRUE));
+ }
+ }
+ return err;
+}
+
+OMX_ERRORTYPE ISVComponent::GetConfig(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_INDEXTYPE nIndex,
+ OMX_INOUT OMX_PTR pComponentConfigStructure)
+{
+ GET_ISVOMX_COMPONENT(hComponent);
+
+ return pComp->ISV_GetConfig(nIndex, pComponentConfigStructure);
+}
+
+OMX_ERRORTYPE ISVComponent::ISV_GetConfig(
+ OMX_IN OMX_INDEXTYPE nIndex,
+ OMX_INOUT OMX_PTR pComponentConfigStructure)
+{
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: nIndex 0x%08x", __func__, nIndex);
+
+ OMX_ERRORTYPE err = OMX_GetConfig(mComponent, nIndex, pComponentConfigStructure);
+ if (err == OMX_ErrorNone && mVPPEnabled && mVPPOn) {
+ if (nIndex == OMX_IndexConfigCommonOutputCrop) {
+ OMX_CONFIG_RECTTYPE *rect = static_cast<OMX_CONFIG_RECTTYPE*>(pComponentConfigStructure);
+ if (rect->nPortIndex == kPortIndexOutput &&
+ rect->nWidth < mWidth &&
+ rect->nHeight < mHeight) {
+ mISVBufferManager->setBuffersFlag(ISVBuffer::ISV_BUFFER_NEED_CLEAR);
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: mark all buffers need clear", __func__);
+ }
+ }
+ }
+ return err;
+}
+
+OMX_ERRORTYPE ISVComponent::SetConfig(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_INDEXTYPE nIndex,
+ OMX_IN OMX_PTR pComponentConfigStructure)
+{
+ GET_ISVOMX_COMPONENT(hComponent);
+
+ return pComp->ISV_SetConfig(nIndex, pComponentConfigStructure);
+}
+
+OMX_ERRORTYPE ISVComponent::ISV_SetConfig(
+ OMX_IN OMX_INDEXTYPE nIndex,
+ OMX_IN OMX_PTR pComponentConfigStructure)
+{
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: nIndex 0x%08x", __func__, nIndex);
+
+ if (nIndex == static_cast<OMX_INDEXTYPE>(OMX_IndexConfigAutoFramerateConversion)) {
+ OMX_CONFIG_BOOLEANTYPE *config = static_cast<OMX_CONFIG_BOOLEANTYPE*>(pComponentConfigStructure);
+ if (config->bEnabled) {
+ mVPPEnabled = true;
+ ALOGI("%s: mVPPEnabled=true", __func__);
+ } else {
+ mVPPEnabled = false;
+ ALOGI("%s: mVPPEnabled=false", __func__);
+ }
+ return OMX_ErrorNone;
+ }
+
+ return OMX_SetConfig(mComponent, nIndex, pComponentConfigStructure);
+}
+
+OMX_ERRORTYPE ISVComponent::GetExtensionIndex(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_STRING cParameterName,
+ OMX_OUT OMX_INDEXTYPE* pIndexType)
+{
+ GET_ISVOMX_COMPONENT(hComponent);
+
+ return pComp->ISV_GetExtensionIndex(cParameterName, pIndexType);
+}
+
+OMX_ERRORTYPE ISVComponent::ISV_GetExtensionIndex(
+ OMX_IN OMX_STRING cParameterName,
+ OMX_OUT OMX_INDEXTYPE* pIndexType)
+{
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: cParameterName %s", __func__, cParameterName);
+ if(!strncmp(cParameterName, "OMX.intel.index.SetISVMode", strlen(cParameterName))) {
+ *pIndexType = static_cast<OMX_INDEXTYPE>(OMX_IndexExtSetISVMode);
+ return OMX_ErrorNone;
+ }
+
+ OMX_ERRORTYPE err = OMX_GetExtensionIndex(mComponent, cParameterName, pIndexType);
+
+ if(err == OMX_ErrorNone &&
+ !strncmp(cParameterName, "OMX.google.android.index.useAndroidNativeBuffer2", strlen(cParameterName)))
+ mUseAndroidNativeBuffer2 = true;
+
+ if(err == OMX_ErrorNone &&
+ !strncmp(cParameterName, "OMX.google.android.index.useAndroidNativeBuffer", strlen(cParameterName))) {
+ mUseAndroidNativeBuffer = true;
+ mUseAndroidNativeBufferIndex = static_cast<uint32_t>(*pIndexType);
+ }
+
+ if(err == OMX_ErrorNone &&
+ !strncmp(cParameterName, "OMX.google.android.index.storeMetaDataInBuffers", strlen(cParameterName))) {
+ mStoreMetaDataInBuffersIndex = static_cast<uint32_t>(*pIndexType);
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: storeMetaDataInBuffersIndex 0x%08x return %d", __func__, mStoreMetaDataInBuffersIndex, err);
+ }
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: cParameterName %s, nIndex 0x%08x", __func__,
+ cParameterName, *pIndexType);
+ return err;
+}
+
+OMX_ERRORTYPE ISVComponent::GetState(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_OUT OMX_STATETYPE* pState)
+{
+ GET_ISVOMX_COMPONENT(hComponent);
+
+ return pComp->ISV_GetState(pState);
+}
+
+OMX_ERRORTYPE ISVComponent::ISV_GetState(
+ OMX_OUT OMX_STATETYPE* pState)
+{
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s", __func__);
+
+ return OMX_GetState(mComponent, pState);
+}
+
+OMX_ERRORTYPE ISVComponent::UseBuffer(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_INOUT OMX_BUFFERHEADERTYPE **ppBufferHdr,
+ OMX_IN OMX_U32 nPortIndex,
+ OMX_IN OMX_PTR pAppPrivate,
+ OMX_IN OMX_U32 nSizeBytes,
+ OMX_IN OMX_U8 *pBuffer)
+{
+ GET_ISVOMX_COMPONENT(hComponent);
+
+ return pComp->ISV_UseBuffer(ppBufferHdr, nPortIndex,
+ pAppPrivate, nSizeBytes, pBuffer);
+}
+
+OMX_ERRORTYPE ISVComponent::ISV_UseBuffer(
+ OMX_INOUT OMX_BUFFERHEADERTYPE **ppBufferHdr,
+ OMX_IN OMX_U32 nPortIndex,
+ OMX_IN OMX_PTR pAppPrivate,
+ OMX_IN OMX_U32 nSizeBytes,
+ OMX_IN OMX_U8 *pBuffer)
+{
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s", __func__);
+
+ OMX_ERRORTYPE err = OMX_UseBuffer(mComponent, ppBufferHdr, nPortIndex,
+ pAppPrivate, nSizeBytes, pBuffer);
+#ifndef USE_IVP
+ if(err == OMX_ErrorNone
+ && mVPPEnabled
+ && mVPPOn
+ && nPortIndex == kPortIndexOutput
+ /*&& mUseAndroidNativeBuffer2*/) {
+ if (mISVBufferManager != NULL) {
+ if (OK != mISVBufferManager->useBuffer(reinterpret_cast<unsigned long>(pBuffer))) {
+ ALOGE("%s: failed to register graphic buffers to ISV, set mVPPEnabled -->false", __func__);
+ mVPPEnabled = false;
+ } else
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: mVPP useBuffer success. buffer handle %p", __func__, pBuffer);
+ }
+ }
+#endif
+ return err;
+}
+
+OMX_ERRORTYPE ISVComponent::AllocateBuffer(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_INOUT OMX_BUFFERHEADERTYPE **ppBuffer,
+ OMX_IN OMX_U32 nPortIndex,
+ OMX_IN OMX_PTR pAppPrivate,
+ OMX_IN OMX_U32 nSizeBytes)
+{
+ GET_ISVOMX_COMPONENT(hComponent);
+
+ return pComp->ISV_AllocateBuffer(ppBuffer, nPortIndex,
+ pAppPrivate, nSizeBytes);
+}
+
+OMX_ERRORTYPE ISVComponent::ISV_AllocateBuffer(
+ OMX_INOUT OMX_BUFFERHEADERTYPE **ppBuffer,
+ OMX_IN OMX_U32 nPortIndex,
+ OMX_IN OMX_PTR pAppPrivate,
+ OMX_IN OMX_U32 nSizeBytes)
+{
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s", __func__);
+
+ return OMX_AllocateBuffer(mComponent, ppBuffer, nPortIndex,
+ pAppPrivate, nSizeBytes);
+}
+
+OMX_ERRORTYPE ISVComponent::FreeBuffer(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_U32 nPortIndex,
+ OMX_IN OMX_BUFFERHEADERTYPE *pBuffer)
+{
+ GET_ISVOMX_COMPONENT(hComponent);
+
+ return pComp->ISV_FreeBuffer(nPortIndex, pBuffer);
+}
+
+OMX_ERRORTYPE ISVComponent::ISV_FreeBuffer(
+ OMX_IN OMX_U32 nPortIndex,
+ OMX_IN OMX_BUFFERHEADERTYPE *pBuffer)
+{
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: pBuffer %p", __func__, pBuffer);
+
+ if(mVPPEnabled && mVPPOn
+ && nPortIndex == kPortIndexOutput) {
+ if (mISVBufferManager != NULL && OK != mISVBufferManager->freeBuffer(reinterpret_cast<unsigned long>(pBuffer->pBuffer)))
+ ALOGW("%s: pBuffer %p has not been registered into ISV", __func__, pBuffer);
+ }
+ return OMX_FreeBuffer(mComponent, nPortIndex, pBuffer);
+}
+
+OMX_ERRORTYPE ISVComponent::EmptyThisBuffer(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
+{
+ GET_ISVOMX_COMPONENT(hComponent);
+
+ return pComp->ISV_EmptyThisBuffer(pBuffer);
+}
+
+OMX_ERRORTYPE ISVComponent::ISV_EmptyThisBuffer(
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
+{
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: pBuffer %p", __func__, pBuffer);
+
+ return OMX_EmptyThisBuffer(mComponent, pBuffer);
+}
+
+OMX_ERRORTYPE ISVComponent::FillThisBuffer(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_BUFFERHEADERTYPE *pBuffer)
+{
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: API entry.", __func__);
+ GET_ISVOMX_COMPONENT(hComponent);
+
+ return pComp->ISV_FillThisBuffer(pBuffer);
+}
+
+OMX_ERRORTYPE ISVComponent::ISV_FillThisBuffer(
+ OMX_IN OMX_BUFFERHEADERTYPE *pBuffer)
+{
+ if(!mVPPEnabled || !mVPPOn)
+ return OMX_FillThisBuffer(mComponent, pBuffer);
+
+ ISVBuffer* isvBuffer = NULL;
+
+ if (mISVBufferManager != NULL) {
+ isvBuffer = mISVBufferManager->mapBuffer(reinterpret_cast<unsigned long>(pBuffer->pBuffer));
+ if (isvBuffer == NULL) {
+ ALOGE("%s: failed to map ISVBuffer, set mVPPEnabled -->false", __func__);
+ mVPPEnabled = false;
+ return OMX_FillThisBuffer(mComponent, pBuffer);
+ }
+
+ if (OK != isvBuffer->initBufferInfo(mHackFormat)) {
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: isvBuffer %p failed to initBufferInfo", __func__, isvBuffer);
+ mVPPEnabled = false;
+ return OMX_FillThisBuffer(mComponent, pBuffer);
+ }
+ }
+
+ if (mNumDecoderBuffers > 0) {
+ mNumDecoderBuffers--;
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: fill pBuffer %p to the decoder, decoder still need extra %d buffers", __func__,
+ pBuffer, mNumDecoderBuffers);
+
+ if (isvBuffer != NULL)
+ isvBuffer->clearIfNeed();
+
+ return OMX_FillThisBuffer(mComponent, pBuffer);
+ }
+ mProcThread->addOutput(pBuffer);
+
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE ISVComponent::FillBufferDone(
+ OMX_OUT OMX_HANDLETYPE hComponent,
+ OMX_OUT OMX_PTR pAppData,
+ OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer)
+{
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: API entry. ISV component num %d, component handle %p on index 0", __func__,
+ g_isv_components.size(),
+ g_isv_components.itemAt(0));
+ for (OMX_U32 i = 0; i < g_isv_components.size(); i++) {
+ if (static_cast<OMX_HANDLETYPE>(g_isv_components.itemAt(i)->mComponent) == hComponent)
+ return g_isv_components.itemAt(i)->ISV_FillBufferDone(hComponent, pAppData, pBuffer);
+ }
+ return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE ISVComponent::ISV_FillBufferDone(
+ OMX_OUT OMX_HANDLETYPE __maybe_unused hComponent,
+ OMX_OUT OMX_PTR pAppData,
+ OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer)
+{
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: %p <== buffer_handle_t %p. mVPPEnabled %d, mVPPOn %d", __func__,
+ pBuffer, pBuffer->pBuffer, mVPPEnabled, mVPPOn);
+ if (!mpCallBacks) {
+ ALOGE("%s: no call back functions were registered.", __func__);
+ return OMX_ErrorUndefined;
+ }
+
+ if(!mVPPEnabled || !mVPPOn || mVPPFlushing || pBuffer->nFilledLen == 0) {
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: FillBufferDone pBuffer %p, timeStamp %.2f ms", __func__, pBuffer, pBuffer->nTimeStamp/1E3);
+ return mpCallBacks->FillBufferDone(&mBaseComponent, pAppData, pBuffer);
+ }
+
+ if (mOutputCropChanged && mISVBufferManager != NULL) {
+ ISVBuffer* isvBuffer = mISVBufferManager->mapBuffer(reinterpret_cast<unsigned long>(pBuffer->pBuffer));
+ if (isvBuffer != NULL)
+ isvBuffer->setFlag(ISVBuffer::ISV_BUFFER_CROP_CHANGED);
+ mOutputCropChanged = false;
+ }
+
+ 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:
+ {
+ if (nData1 == kPortIndexOutput && nData2 == OMX_IndexConfigCommonOutputCrop) {
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: output crop changed", __func__);
+ mOutputCropChanged = true;
+ return OMX_ErrorNone;
+ }
+ 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,
+ sp<ISVBufferManager> bufferManager)
+ : mBaseComponent(pBaseComponent),
+ mComponent(pComponent),
+ mpCallBacks(pCallBacks),
+ mISVBufferManager(bufferManager)
+{
+ ALOGV("VPPProcThreadObserver!");
+}
+
+ISVProcThreadObserver::~ISVProcThreadObserver()
+{
+ ALOGV("~VPPProcThreadObserver!");
+ mBaseComponent = NULL;
+ mComponent = NULL;
+ mpCallBacks = NULL;
+}
+
+OMX_ERRORTYPE ISVProcThreadObserver::releaseBuffer(PORT_INDEX index, OMX_BUFFERHEADERTYPE* pBuffer, bool bFLush)
+{
+ if (!mBaseComponent || !mComponent || !mpCallBacks)
+ return OMX_ErrorUndefined;
+
+ OMX_ERRORTYPE err = OMX_ErrorNone;
+ if (bFLush) {
+ pBuffer->nFilledLen = 0;
+ pBuffer->nOffset = 0;
+ err = mpCallBacks->FillBufferDone(&mBaseComponent, mBaseComponent->pApplicationPrivate, pBuffer);
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: flush pBuffer %p", __func__, pBuffer);
+ return err;
+ }
+
+ if (index == kPortIndexInput) {
+ pBuffer->nFilledLen = 0;
+ pBuffer->nOffset = 0;
+ pBuffer->nFlags = 0;
+
+ if (mISVBufferManager != NULL) {
+ ISVBuffer* isvBuffer = mISVBufferManager->mapBuffer(reinterpret_cast<unsigned long>(pBuffer->pBuffer));
+ if (isvBuffer != NULL)
+ isvBuffer->clearIfNeed();
+ }
+
+ err = OMX_FillThisBuffer(mComponent, pBuffer);
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: FillBuffer pBuffer %p", __func__, pBuffer);
+ } else {
+ err = mpCallBacks->FillBufferDone(&mBaseComponent, mBaseComponent->pApplicationPrivate, pBuffer);
+ ALOGD_IF(ISV_COMPONENT_DEBUG, "%s: FillBufferDone pBuffer %p, timeStamp %.2f ms", __func__, pBuffer, pBuffer->nTimeStamp/1E3);
+ }
+
+ return err;
+}
+
+OMX_ERRORTYPE ISVProcThreadObserver::reportOutputCrop()
+{
+ if (!mBaseComponent || !mComponent || !mpCallBacks)
+ return OMX_ErrorUndefined;
+
+ OMX_ERRORTYPE err = OMX_ErrorNone;
+ err = mpCallBacks->EventHandler(&mBaseComponent, mBaseComponent->pApplicationPrivate,
+ OMX_EventPortSettingsChanged,
+ kPortIndexOutput, OMX_IndexConfigCommonOutputCrop, NULL);
+ return err;
+}
diff --git a/ISV/omx/isv_omxcore.cpp b/ISV/omx/isv_omxcore.cpp
new file mode 100644
index 0000000..5f6933b
--- /dev/null
+++ b/ISV/omx/isv_omxcore.cpp
@@ -0,0 +1,326 @@
+/*
+ * 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");
+ }
+ }
+ 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;
+ ALOGD_IF(ISV_CORE_DEBUG, "%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..86fdd02
--- /dev/null
+++ b/ISV/profile/isv_profile.cpp
@@ -0,0 +1,463 @@
+/*
+ * 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 "isv_profile.h"
+
+#undef LOG_TAG
+#define LOG_TAG "ISVProfile"
+
+#define QCIF_AREA (176 * 144)
+
+#define DEFAULT_XML_FILE "/etc/video_isv_profile.xml"
+
+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;
+ mDefaultVPPStatus = 0;
+ mDefaultFRCStatus = 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();
+ return (status != -1) ? (((status & VPP_COMMON_ON) != 0) ? true : false) : false;
+}
+
+bool ISVProfile::isFRCOn()
+{
+ int32_t status = getGlobalStatus();
+ return (status != -1) ? (((status & VPP_FRC_ON) != 0) ? true : false) : false;
+}
+
+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) {
+ /* <parameter /> */
+ handleFilterParameter(name, atts);
+ } else if (strcmp(name, "Parameter") == 0) {
+ /* <Parameter /> */
+ handleCommonParameter(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::handleCommonParameter(const char *name, const char **atts)
+{
+ int attIndex = 0;
+
+ 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;
+ }
+
+ /* The default status of VPP */
+ if (strcmp(atts[attIndex + 1], "DefaultVPPStatus") == 0)
+ mDefaultVPPStatus = atoi(atts[attIndex + 3]);
+ /* The default status of FRC */
+ else if (strcmp(atts[attIndex + 1], "DefaultFRCStatus") == 0)
+ mDefaultFRCStatus = atoi(atts[attIndex + 3]);
+}
+
+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;
+
+ fp = ::fopen(DEFAULT_XML_FILE, "r");
+ if (NULL == fp) {
+ ALOGE("@%s, line:%d, couldn't open profile %s", __func__, __LINE__, DEFAULT_XML_FILE);
+ 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;
+ FILE *setting_handle, *config_handle;
+
+ snprintf(path, 80, "/data/user/%d/com.intel.vpp/shared_prefs/vpp_settings.xml", userId);
+ ALOGV("%s: %s",__func__, path);
+ setting_handle = fopen(path, "r");
+ if(setting_handle == NULL) {
+ ALOGE("%s: failed to open file %s\n", __func__, path);
+
+ /* Read the Filter config file to get default value */
+ config_handle = fopen(DEFAULT_XML_FILE, "r");
+ if (config_handle == NULL) {
+ ALOGE("%s: failed to open file %s\n", __func__, DEFAULT_XML_FILE);
+ return -1;
+ }
+
+ char xml_buf[MAX_BUF_SIZE + 1] = {0};
+ memset(xml_buf, 0, MAX_BUF_SIZE);
+ if (fread(xml_buf, 1, MAX_BUF_SIZE, config_handle) <= 0) {
+ ALOGE("%s: failed to read config xml file!\n", __func__);
+ fclose(config_handle);
+ return -1;
+ }
+ xml_buf[MAX_BUF_SIZE] = '\0';
+
+ if (strstr(xml_buf, "name=\"DefaultVPPStatus\" value=\"1\"") != NULL)
+ status |= VPP_COMMON_ON;
+ if (strstr(xml_buf, "name=\"DefaultFRCStatus\" value=\"1\"") != NULL)
+ status |= VPP_FRC_ON;
+
+ ALOGV("%s: using the default status: VPP=%d, FRC=%d\n", __func__,
+ ((status & VPP_COMMON_ON) == 0) ? 0 : 1,
+ ((status & VPP_FRC_ON) == 0) ? 0: 1);
+
+ fclose(config_handle);
+ return status;
+ }
+
+ const int MAXLEN = 1024;
+ char buf[MAXLEN] = {0};
+ memset(buf, 0 ,MAXLEN);
+ if(fread(buf, 1, MAXLEN, setting_handle) <= 0) {
+ ALOGE("%s: failed to read vpp config file %d", __func__, userId);
+ fclose(setting_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(setting_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",
+ };
+
+ ALOGV("========== VPP filter configs:==========\n");
+ for (i = 1; i < ProcFilterCount; i++) {
+ ALOGV("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) {
+ ALOGV("\t\t parameters: ");
+ for(j = 0; j < mConfigs[i].paraSize; j++)
+ ALOGE("%s=%f,", mConfigs[i].paraTables[j].name, mConfigs[i].paraTables[j].value);
+ ALOGV("\n");
+ }
+ }
+
+ ALOGV("========== FRC rate configs:===========\n");
+ for (i = 0; i < MAX_TAB_SIZE; i++) {
+ if (mFrcRates[i].input_fps == 0)
+ break;
+ ALOGV("input_fps=%d, rate=%s\n", mFrcRates[i].input_fps, rateNames[mFrcRates[i].rate]);
+ }
+
+ ALOGI("========== common parameter configs:===========\n");
+ ALOGI("mDefaultVPPStatus=%d\n", mDefaultVPPStatus);
+ ALOGI("mDefaultFRCStatus=%d\n", mDefaultFRCStatus);
+
+}
diff --git a/ituxd/jni/thermalJNI.cpp b/ituxd/jni/thermalJNI.cpp
index 4c92775..8a64906 100644
--- a/ituxd/jni/thermalJNI.cpp
+++ b/ituxd/jni/thermalJNI.cpp
@@ -248,9 +248,35 @@
}
}
+static jint readSysfsTemp(JNIEnv* env, jobject obj, jstring jPath)
+{
+ const char *path = NULL;
+ const int SIZE = 64;
+ char buf[SIZE];
+ // Convention: To allow returning of normal negative temperatures
+ // (say -10C), let us return errno as a negative offset from
+ // absolute zero millidegree C.
+ const int ABS_ZERO = -273000;
+ int ret;
+
+ path = jPath ? env->GetStringUTFChars(jPath, NULL) : NULL;
+ if (!path) {
+ jniThrowNullPointerException(env, "path");
+ return (ABS_ZERO - ENOENT);
+ }
+
+ ret = readFromFile(path, buf, SIZE, true);
+ env->ReleaseStringUTFChars(jPath, path);
+ if (ret > 0) {
+ return atoi(buf);
+ }
+ return (ret + ABS_ZERO);
+}
+
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"native_readSysfs", "(Ljava/lang/String;)Ljava/lang/String;", (void*)readSysfs},
+ {"native_readSysfsTemp", "(Ljava/lang/String;)I", (void*)readSysfsTemp},
{"native_writeSysfs", "(Ljava/lang/String;I)I", (void*)writeSysfs},
{"native_getThermalZoneIndex", "(Ljava/lang/String;)I", (void*)getThermalZoneIndex},
{"native_getThermalZoneIndexContains", "(Ljava/lang/String;)I",
diff --git a/ituxd/src/com/intel/thermal/RawThermalZone.java b/ituxd/src/com/intel/thermal/RawThermalZone.java
index 4baba9a..9953a02 100644
--- a/ituxd/src/com/intel/thermal/RawThermalZone.java
+++ b/ituxd/src/com/intel/thermal/RawThermalZone.java
@@ -75,9 +75,10 @@
}
} else {
//zone temp is max of all sensor temp
- for (ThermalSensor ts : getThermalSensorList()) {
- if (ts != null && ts.getSensorActiveStatus()) {
- curTemp = ts.getCurrTemp();
+ for (int i = 0; i < mThermalSensors.size(); i++) {
+ if (mThermalSensors.get(i) != null &&
+ mThermalSensors.get(i).getSensorActiveStatus()) {
+ curTemp = mThermalSensors.get(i).getCurrTemp();
if (curTemp > maxCurTemp) {
maxCurTemp = curTemp;
}
diff --git a/ituxd/src/com/intel/thermal/ThermalManager.java b/ituxd/src/com/intel/thermal/ThermalManager.java
index b68bd3d..e9e5597 100644
--- a/ituxd/src/com/intel/thermal/ThermalManager.java
+++ b/ituxd/src/com/intel/thermal/ThermalManager.java
@@ -207,6 +207,9 @@
public static final int INVALID_TEMP = 0xDEADBEEF;
+ /* Absolute zero in millidegree C */
+ public static final int ABS_ZERO = -273000;
+
/* base sysfs path for sensors */
public static final String sSysfsSensorBasePath = "/sys/class/thermal/thermal_zone";
diff --git a/ituxd/src/com/intel/thermal/ThermalSensor.java b/ituxd/src/com/intel/thermal/ThermalSensor.java
index 78c7739..eb6d75f 100644
--- a/ituxd/src/com/intel/thermal/ThermalSensor.java
+++ b/ituxd/src/com/intel/thermal/ThermalSensor.java
@@ -219,14 +219,11 @@
* Method that actually does a Sysfs read.
*/
public int readSensorTemp() {
- int val = ThermalManager.INVALID_TEMP;
- try {
- String tempStr = ThermalUtils.readSysfs(mInputTempPath);
- if (tempStr != null) {
- val = Integer.parseInt(tempStr.trim());
- }
- } catch (NumberFormatException e) {
- Log.i(TAG, "NumberFormatException in readSensorTemp():" + mInputTempPath);
+ int val = ThermalUtils.readSysfsTemp(mInputTempPath);
+ if (val <= ThermalManager.ABS_ZERO) {
+ // Error will be returned as negative offset from absolute zero in milli degree C
+ Log.e(TAG, "readSensorTemp failed with error:" + (val - ThermalManager.ABS_ZERO));
+ val = ThermalManager.INVALID_TEMP;
}
return val;
}
diff --git a/ituxd/src/com/intel/thermal/ThermalUtils.java b/ituxd/src/com/intel/thermal/ThermalUtils.java
index 7126f9b..0094e5b 100644
--- a/ituxd/src/com/intel/thermal/ThermalUtils.java
+++ b/ituxd/src/com/intel/thermal/ThermalUtils.java
@@ -37,6 +37,7 @@
/* Native methods to access Sysfs Interfaces */
private native static String native_readSysfs(String path);
+ private native static int native_readSysfsTemp(String path);
private native static int native_writeSysfs(String path, int val);
private native static int native_getThermalZoneIndex(String name);
private native static int native_getThermalZoneIndexContains(String name);
@@ -54,6 +55,15 @@
}
}
+ public static int readSysfsTemp(String path) {
+ try {
+ return native_readSysfsTemp(path);
+ } catch (UnsatisfiedLinkError e) {
+ Log.i(TAG, "caught UnsatisfiedLinkError in readSysfsTemp");
+ return INVALID_TEMP;
+ }
+ }
+
public static int writeSysfs(String path, int val) {
try {
return native_writeSysfs(path, val);
@@ -143,22 +153,11 @@
}
public static void getTjMax() {
- String temp_tjmax;
-
- temp_tjmax = readSysfs(ThermalManager.TJMAX_PATH);
- if (temp_tjmax != null) {
- try {
- ThermalManager.sTjMaxTemp = Integer.parseInt(temp_tjmax);
- Log.i(TAG, "TjMax temp = " + ThermalManager.sTjMaxTemp);
- } catch (NumberFormatException e) {
- ThermalManager.sTjMaxTemp = ThermalManager.sDefaultTjMax;
- Log.i(TAG, "TjMax value invalid, Default TjMax value =" +
- ThermalManager.sTjMaxTemp);
- }
- } else {
- ThermalManager.sTjMaxTemp = ThermalManager.sDefaultTjMax;
+ ThermalManager.sTjMaxTemp = readSysfsTemp(ThermalManager.TJMAX_PATH);
+ if (ThermalManager.sTjMaxTemp <= ThermalManager.ABS_ZERO) {
Log.i(TAG, "TjMax temp read failed, Default TjMax value =" +
ThermalManager.sTjMaxTemp);
+ ThermalManager.sTjMaxTemp = ThermalManager.sDefaultTjMax;
}
}
diff --git a/ituxd/src/com/intel/thermal/ThermalZone.java b/ituxd/src/com/intel/thermal/ThermalZone.java
index a3af5af..9844f9e 100644
--- a/ituxd/src/com/intel/thermal/ThermalZone.java
+++ b/ituxd/src/com/intel/thermal/ThermalZone.java
@@ -481,9 +481,9 @@
* zone operates in polling mode.
*/
public boolean isZoneStateChanged() {
- for (ThermalSensor ts : mThermalSensors) {
- if (ts.getSensorActiveStatus()) {
- ts.updateSensorTemp();
+ for (int i = 0; i < mThermalSensors.size(); i++) {
+ if (mThermalSensors.get(i).getSensorActiveStatus()) {
+ mThermalSensors.get(i).updateSensorTemp();
}
}
return updateZoneParams();
diff --git a/ituxd/src/com/intel/thermal/VirtualThermalZone.java b/ituxd/src/com/intel/thermal/VirtualThermalZone.java
index 1f4fd4d..52364ca 100644
--- a/ituxd/src/com/intel/thermal/VirtualThermalZone.java
+++ b/ituxd/src/com/intel/thermal/VirtualThermalZone.java
@@ -175,14 +175,15 @@
// In UEvent mode, the obtained temperature is the zone temperature
return true;
} else {
- for (ThermalSensor ts : getThermalSensorList()) {
- if (ts != null && ts.getSensorActiveStatus()) {
+ for (int i = 0; i < mThermalSensors.size(); i++) {
+ if (mThermalSensors.get(i) != null
+ && mThermalSensors.get(i).getSensorActiveStatus()) {
if (flag == false) {
// one time initialization of zone temp
curZoneTemp = 0;
flag = true;
}
- weightedTemp = getWeightedTemp(ts);
+ weightedTemp = getWeightedTemp(mThermalSensors.get(i));
if (weightedTemp != ThermalManager.INVALID_TEMP) {
curZoneTemp += weightedTemp;
}