Enable VAVideoDecoder as thumbnail generation path (Video HAL)

BZ: 48580

Use Intel HW decoder as the thumbnail generation path to improve
performance.

Change-Id: Ifd6e966cdea40e8cc038963b31ab64ed4bd74551
Signed-off-by: wfeng6 <wei.feng@intel.com>
Reviewed-on: http://android.intel.com:8080/58656
Reviewed-by: buildbot <buildbot@intel.com>
Reviewed-by: Zhang, Xiaolin <xiaolin.zhang@intel.com>
Tested-by: Zhang, Xiaolin <xiaolin.zhang@intel.com>
diff --git a/Android.mk b/Android.mk
index b73ddce..1056c24 100644
--- a/Android.mk
+++ b/Android.mk
@@ -13,4 +13,5 @@
 include $(VENDORS_INTEL_MRST_LIBMIX_ROOT)/videodecoder/Android.mk
 include $(VENDORS_INTEL_MRST_LIBMIX_ROOT)/videoencoder/Android.mk
 include $(VENDORS_INTEL_MRST_LIBMIX_ROOT)/frameworks/asf_extractor/Android.mk
+include $(VENDORS_INTEL_MRST_LIBMIX_ROOT)/frameworks/vavideodecoder/Android.mk
 endif
diff --git a/frameworks/vavideodecoder/Android.mk b/frameworks/vavideodecoder/Android.mk
new file mode 100644
index 0000000..1a9faaf
--- /dev/null
+++ b/frameworks/vavideodecoder/Android.mk
@@ -0,0 +1,27 @@
+ifeq ($(strip $(USE_INTEL_ASF_EXTRACTOR)),true)
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_COPY_HEADERS_TO := libvavideodecoder
+LOCAL_COPY_HEADERS := VAVideoDecoder.h
+
+LOCAL_SRC_FILES := \
+    VAVideoDecoder.cpp \
+
+#LOCAL_SHARED_LIBRARIES += libasfparser
+
+LOCAL_C_INCLUDES := \
+    $(TOP)/frameworks/av/media/libstagefright/include \
+    $(TOP)/frameworks/native/include/media/openmax \
+    $(TARGET_OUT_HEADERS)/libmix_videodecoder \
+    $(TARGET_OUT_HEADERS)/libmix_asf_extractor \
+    $(TARGET_OUT_HEADERS)/libva/
+
+
+LOCAL_MODULE:= libvavideodecoder
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_STATIC_LIBRARY)
+
+endif
diff --git a/frameworks/vavideodecoder/VAVideoDecoder.cpp b/frameworks/vavideodecoder/VAVideoDecoder.cpp
new file mode 100644
index 0000000..a860e86
--- /dev/null
+++ b/frameworks/vavideodecoder/VAVideoDecoder.cpp
@@ -0,0 +1,340 @@
+/*
+* Copyright (c) 2009-2011 Intel Corporation.  All rights reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "VAVideoDecoder"
+#include <utils/Log.h>
+
+#include <media/stagefright/MediaBufferGroup.h>
+//#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+#include <media/openmax/OMX_IVCommon.h>
+#include "MetaDataExt.h"
+#include "VAVideoDecoder.h"
+#include "VideoDecoderInterface.h"
+#include "VideoDecoderHost.h"
+#include <media/stagefright/foundation/ADebug.h>
+namespace android {
+
+VAVideoDecoder::VAVideoDecoder(const sp<MediaSource> &source)
+    : mSource(source),
+      mStarted(false),
+      mRawOutput(false),
+      mInputBuffer(NULL),
+      mTargetTimeUs(-1),
+      mFrameIndex(0),
+      mErrorCount(0),
+      mDecoder(NULL) {
+
+    const char *mime;
+    CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
+    mDecoder = createVideoDecoder(mime);
+    if (mDecoder == NULL) {
+        LOGE("Failed to create video decoder for %s", mime);
+    }
+
+    mFormat = new MetaData;
+    mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VA);
+
+    int32_t width, height;
+    CHECK(mSource->getFormat()->findInt32(kKeyWidth, &width));
+    CHECK(mSource->getFormat()->findInt32(kKeyHeight, &height));
+    mFormat->setInt32(kKeyWidth, width);
+    mFormat->setInt32(kKeyHeight, height);
+    mFormat->setInt32(kKeyColorFormat, OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar);
+    mFormat->setCString(kKeyDecoderComponent, "VAVideoDecoder");
+
+    int64_t durationUs;
+    if (mSource->getFormat()->findInt64(kKeyDuration, &durationUs)) {
+        mFormat->setInt64(kKeyDuration, durationUs);
+    }
+
+}
+
+VAVideoDecoder::~VAVideoDecoder() {
+    if (mStarted) {
+        stop();
+    }
+    releaseVideoDecoder(mDecoder);
+    mDecoder = NULL;
+}
+
+status_t VAVideoDecoder::start(MetaData *params) {
+    CHECK(!mStarted);
+
+    if (mDecoder == NULL) {
+        LOGE("Decoder is not created.");
+        return UNKNOWN_ERROR;
+    }
+
+    int32_t ret;
+    char str[255];
+    sprintf(str, "%d", gettid());
+    ret = setenv("PSB_VIDEO_THUMBNAIL", str, 1);
+    if (ret) {
+        LOGW("Set environmnet'PSB_VIDEO_SURFACE_MMU' fail\n");
+    }
+    uint32_t type;
+    const void *data;
+    size_t size;
+    sp<MetaData> meta = mSource->getFormat();
+    VideoConfigBuffer configBuffer;
+    memset(&configBuffer, 0, sizeof(VideoConfigBuffer));
+
+    if (meta->findData(kKeyConfigData, &type, &data, &size) ||
+        meta->findData(kKeyESDS, &type, &data, &size) ||
+        meta->findData(kKeyAVCC, &type, &data, &size)) {
+        configBuffer.data = (uint8_t*)data;
+        configBuffer.size = size;
+    } else {
+        LOGW("No configuration data found!");
+    }
+
+    configBuffer.flag |= WANT_RAW_OUTPUT;
+    mFormat->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420SemiPlanar);
+    mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
+    mRawOutput = true;
+    LOGW("Decoder will output raw data.");
+
+    mFormat->findInt32(kKeyWidth, &configBuffer.width);
+    mFormat->findInt32(kKeyHeight, &configBuffer.height);
+
+    Decode_Status res = mDecoder->start(&configBuffer);
+    if (res != DECODE_SUCCESS) {
+        LOGE("Failed to start decoder. Error = %d", res);
+        return UNKNOWN_ERROR;
+    }
+
+    // TODO: update format meta, including frame cropping information.
+
+    // create MediaBuffer pool only when output is VASurface
+    if (mRawOutput == false) {
+        for (int32_t i = 0; i < NUM_OF_MEDIA_BUFFER; ++i) {
+            MediaBuffer *buffer = new MediaBuffer(sizeof(VideoRenderBuffer));
+            buffer->setObserver(this);
+            // output is  unreadable VASurface
+            buffer->meta_data()->setInt32(kKeyIsUnreadable, 1);
+            buffer->meta_data()->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VA);
+            buffer->meta_data()->setInt32(kKeyColorFormat,OMX_COLOR_FormatYUV420SemiPlanar);
+            mFrames.push(buffer);
+        }
+    }
+
+    mSource->start();
+    unsetenv("PSB_VIDEO_THUMBNAIL");
+
+    mFrameIndex = 0;
+    mErrorCount = 0;
+    mTargetTimeUs = -1;
+    mStarted = true;
+    return OK;
+}
+
+
+status_t VAVideoDecoder::stop() {
+    CHECK(mStarted);
+
+    if (mInputBuffer) {
+        mInputBuffer->release();
+        mInputBuffer = NULL;
+    }
+
+    for (size_t i = 0; i < mFrames.size(); ++i) {
+         MediaBuffer *buffer = mFrames.editItemAt(i);
+         buffer->setObserver(NULL);
+         buffer->release();
+    }
+    mFrames.clear();
+    mSource->stop();
+    mDecoder->stop();
+
+    mFrameIndex = 0;
+    mErrorCount = 0;
+    mRawOutput = false;
+    mStarted = false;
+
+    return OK;
+}
+
+sp<MetaData> VAVideoDecoder::getFormat() {
+    return mFormat;
+}
+
+MediaBuffer *VAVideoDecoder::getOutputBuffer(bool bDraining) {
+    const VideoRenderBuffer* buffer = mDecoder->getOutput(bDraining);
+    if (buffer == NULL) {
+        return NULL;
+    }
+    // indicate buffer is rendered
+    buffer->renderDone = true;
+
+    if (mTargetTimeUs >= 0) {
+        CHECK(buffer->timeStamp <= mTargetTimeUs);
+        if (buffer->timeStamp < mTargetTimeUs) {
+            // We're still waiting for the frame with the matching
+            // timestamp and we won't return the current one.
+            LOGV("skipping frame at %lld us", buffer->timeStamp);
+            return NULL;
+        } else {
+            LOGV("found target frame at %lld us", buffer->timeStamp);
+            mTargetTimeUs = -1;
+        }
+    }
+
+    MediaBuffer *mbuf = NULL;
+    if (mRawOutput == false) {
+        mbuf = mFrames.editItemAt(mFrameIndex);
+        mFrameIndex++;
+        if (mFrameIndex >= mFrames.size()) {
+            mFrameIndex = 0;
+        }
+        memcpy(mbuf->data(), buffer, sizeof(VideoRenderBuffer));
+        mbuf->meta_data()->setInt64(kKeyTime, buffer->timeStamp);
+        mbuf->set_range(0, mbuf->size());
+        mbuf->add_ref();
+    } else {
+        mbuf = new MediaBuffer(buffer->rawData->data, buffer->rawData->size);
+        mbuf->meta_data()->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
+        mbuf->meta_data()->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420SemiPlanar);
+        mbuf->meta_data()->setInt64(kKeyTime, buffer->timeStamp);
+    }
+
+    return mbuf;
+}
+
+status_t VAVideoDecoder::read(MediaBuffer **out, const ReadOptions *options)  {
+    *out = NULL;
+    if (mDecoder == NULL) {
+        LOGE("Decoder is not created.");
+        return UNKNOWN_ERROR;
+    }
+
+    int64_t seekTimeUs;
+    ReadOptions::SeekMode mode;
+    ReadOptions seekOptions;
+    bool seeking = false;
+
+    if (options && options->getSeekTo(&seekTimeUs, &mode)) {
+        LOGV("seek requested to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
+
+        if (seekTimeUs < 0) {
+            LOGE("Invalid seek time : %ld", (long int32_t)seekTimeUs);
+            seekTimeUs = 0;
+            //return ERROR_END_OF_STREAM;
+        }
+        //CHECK(seekTimeUs >= 0);
+
+        seekOptions.setSeekTo(seekTimeUs, mode);
+        mDecoder->flush();
+        seeking = true;
+    }
+
+    for (;;) {
+        status_t err = mSource->read(&mInputBuffer, &seekOptions);
+        seekOptions.clearSeekTo();
+
+        if (err != OK) {
+            LOGE("Failed to read buffer from source extractor.");
+            // drain the output buffer when end of stream
+            *out = getOutputBuffer(true);
+            return (*out == NULL)  ? err : (status_t)OK;
+        }
+
+        if (mInputBuffer->range_length() > 0) {
+            break;
+        }
+
+        mInputBuffer->release();
+        mInputBuffer = NULL;
+    }
+
+    if (mInputBuffer == NULL) {
+        LOGE("Unexpected NULL input buffer.");
+        return ERROR_END_OF_STREAM;
+    }
+
+    if (seeking) {
+        int64_t targetTimeUs;
+        if (mInputBuffer->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs) && targetTimeUs >= 0) {
+            mTargetTimeUs = targetTimeUs;
+        } else {
+            mTargetTimeUs = -1;
+        }
+    }
+
+    status_t err = UNKNOWN_ERROR;
+
+    // prepare decoding buffer
+    VideoDecodeBuffer decodeBuffer;
+    memset(&decodeBuffer, 0, sizeof(decodeBuffer));
+    decodeBuffer.data = (uint8_t*)mInputBuffer->data() + mInputBuffer->range_offset();
+    decodeBuffer.size = mInputBuffer->range_length();
+    decodeBuffer.flag = seeking ? HAS_DISCONTINUITY : 0;
+    mInputBuffer->meta_data()->findInt64(kKeyTime, &decodeBuffer.timeStamp);
+    Decode_Status res = mDecoder->decode(&decodeBuffer);
+
+    mInputBuffer->release();
+    mInputBuffer = NULL;
+
+    if (res == DECODE_FORMAT_CHANGE) {
+        LOGW("Format changed.");
+        // drain all the frames.
+        MediaBuffer *mbuf = NULL;
+        while ((mbuf = getOutputBuffer(true)) != NULL) {
+            mbuf->release();
+        }
+        const VideoFormatInfo *info = mDecoder->getFormatInfo();
+        uint32_t cropWidth, cropHeight;
+        if (info != NULL) {
+            cropWidth = info->width - (info->cropLeft + info->cropRight);
+            cropHeight = info->height - (info->cropBottom + info->cropTop);
+            mFormat->setInt32(kKeyWidth, cropWidth);
+            mFormat->setInt32(kKeyHeight, cropHeight);
+        }
+        // TODO: handle format change
+        err = INFO_FORMAT_CHANGED;
+    }
+    else if (res == DECODE_SUCCESS) {
+        mErrorCount = 0;
+        err = OK;
+        MediaBuffer *mbuf = getOutputBuffer();
+        if (mbuf == NULL) {
+            *out = new MediaBuffer(0);
+        } else {
+              *out = mbuf;
+        }
+    } else {
+        mErrorCount++;
+        LOGE("Failed to decode buffer (#%d). Error = %d", mErrorCount, res);
+        if (checkFatalDecoderError(res)) {
+            err = UNKNOWN_ERROR;
+        } else {
+            // For decoder errors that could be omitted,  not throw error and continue to decode.
+            err = OK;
+            *out = new MediaBuffer(0);
+        }
+    }
+
+    return err;
+}
+
+}// namespace android
+
diff --git a/frameworks/vavideodecoder/VAVideoDecoder.h b/frameworks/vavideodecoder/VAVideoDecoder.h
new file mode 100644
index 0000000..911b0dc
--- /dev/null
+++ b/frameworks/vavideodecoder/VAVideoDecoder.h
@@ -0,0 +1,65 @@
+/*
+* Copyright (c) 2009-2011 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 VA_VIDEO_DECODER_H_
+#define VA_VIDEO_DECODER_H_
+
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaSource.h>
+#include <utils/Vector.h>
+
+class IVideoDecoder;
+
+namespace android {
+
+struct VAVideoDecoder : public MediaSource,
+                        public MediaBufferObserver {
+    VAVideoDecoder(const sp<MediaSource> &source);
+
+    virtual status_t start(MetaData *params);
+    virtual status_t stop();
+    virtual sp<MetaData> getFormat();
+    virtual status_t read(MediaBuffer **buffer, const ReadOptions *options);
+    virtual void signalBufferReturned(MediaBuffer* buffer) {}
+
+protected:
+    virtual ~VAVideoDecoder();
+
+private:
+    MediaBuffer *getOutputBuffer(bool bDraining = false);
+    VAVideoDecoder(const VAVideoDecoder &);
+    VAVideoDecoder &operator=(const VAVideoDecoder &);
+
+private:
+    enum {
+        NUM_OF_MEDIA_BUFFER = 20,
+    };
+    sp<MediaSource> mSource;
+    bool mStarted;
+    bool mRawOutput;
+    sp<MetaData> mFormat;
+    Vector<MediaBuffer *> mFrames;
+    MediaBuffer *mInputBuffer;
+    int64_t mTargetTimeUs;
+    uint32_t mFrameIndex;
+    uint32_t mErrorCount;
+    IVideoDecoder *mDecoder;
+};
+
+} // namespace android
+
+#endif  // VA_VIDEO_DECODER_H_