DecoderVP9Hybrid: add adaptive playback support

1. if the output buffer is big enough, drain the frame before
   dealing with new resolution frame
2. if the output buffer is not big enough, the output buffer should
   be reallocated

Bug: 17729532
BZ: 225243

Change-Id: Id252bea17a9f474bbb8dcb97da29cb2b98db5e37
Signed-off-by: ywan171 <yi.a.wang@intel.com>
diff --git a/videocodec/OMXVideoDecoderVP9Hybrid.cpp b/videocodec/OMXVideoDecoderVP9Hybrid.cpp
index 59370e3..8726e56 100644
--- a/videocodec/OMXVideoDecoderVP9Hybrid.cpp
+++ b/videocodec/OMXVideoDecoderVP9Hybrid.cpp
@@ -40,6 +40,8 @@
     mCheckBufferAvailable = NULL;
     mGetOutput = NULL;
     mGetRawDataOutput = NULL;
+    mGetFrameResolution = NULL;
+    mDeinitDecoder = NULL;
     mLastTimeStamp = 0;
     mWorkingMode = RAWDATA_MODE;
     mDecodedImageWidth = 0;
@@ -101,10 +103,13 @@
     mCheckBufferAvailable = (IsBufferAvailableFunc)dlsym(mLibHandle, "Decoder_IsBufferAvailable");
     mGetOutput = (GetOutputFunc)dlsym(mLibHandle, "Decoder_GetOutput");
     mGetRawDataOutput = (GetRawDataOutputFunc)dlsym(mLibHandle, "Decoder_GetRawDataOutput");
+    mGetFrameResolution = (GetFrameResolutionFunc)dlsym(mLibHandle, "Decoder_GetFrameResolution");
+    mDeinitDecoder = (DeinitFunc)dlsym(mLibHandle, "Decoder_Deinit");
     if (mOpenDecoder == NULL || mCloseDecoder == NULL
         || mInitDecoder == NULL || mSingalRenderDone == NULL
         || mDecoderDecode == NULL || mCheckBufferAvailable == NULL
-        || mGetOutput == NULL || mGetRawDataOutput == NULL) {
+        || mGetOutput == NULL || mGetRawDataOutput == NULL
+        || mGetFrameResolution == NULL || mDeinitDecoder == NULL) {
         return OMX_ErrorBadParameter;
     }
 
@@ -117,6 +122,54 @@
     return OMX_ErrorNone;
 }
 
+OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::ProcessorReset(void)
+{
+    uint32_t buff[MAX_GRAPHIC_BUFFER_NUM];
+    uint32_t i, bufferCount;
+    bool gralloc_mode = (mWorkingMode == GRAPHICBUFFER_MODE);
+    uint32_t bufferSize, bufferStride, bufferHeight;
+    if (!gralloc_mode) {
+        bufferSize = mDecodedImageWidth * mDecodedImageHeight * 1.5;
+        bufferStride = mDecodedImageWidth;
+        bufferHeight = mDecodedImageHeight;
+        bufferCount = 12;
+    } else {
+        bufferSize = mGraphicBufferParam.graphicBufferStride *
+                          mGraphicBufferParam.graphicBufferHeight * 1.5;
+        bufferStride = mGraphicBufferParam.graphicBufferStride;
+        bufferCount = mOMXBufferHeaderTypePtrNum;
+        bufferHeight = mGraphicBufferParam.graphicBufferHeight;
+
+        for (i = 0; i < bufferCount; i++ ) {
+            OMX_BUFFERHEADERTYPE *buf_hdr = mOMXBufferHeaderTypePtrArray[i];
+            buff[i] = (uint32_t)(buf_hdr->pBuffer);
+        }
+    }
+    mInitDecoder(mHybridCtx,bufferSize,bufferStride,bufferHeight,bufferCount,gralloc_mode, buff);
+
+    return OMX_ErrorNone;
+}
+
+bool OMXVideoDecoderVP9Hybrid::isReallocateNeeded(const uint8_t * data,uint32_t data_sz)
+{
+    bool gralloc_mode = (mWorkingMode == GRAPHICBUFFER_MODE);
+    uint32_t width, height;
+    bool ret = true;
+    if (gralloc_mode) {
+        ret = mGetFrameResolution(data,data_sz, &width, &height);
+        if (ret) {
+            ret = width > mGraphicBufferParam.graphicBufferWidth
+                || height > mGraphicBufferParam.graphicBufferHeight;
+            if (ret) {
+                mDecodedImageNewWidth = width;
+                mDecodedImageNewHeight = height;
+                return true;
+            }
+        }
+    }
+    return ret;
+}
+
 OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::ProcessorDeinit(void) {
     mCloseDecoder(mCtx,mHybridCtx);
     mOMXBufferHeaderTypePtrNum = 0;
@@ -181,9 +234,21 @@
     int32_t time_ms;
     gettimeofday(&tv_start,NULL);
 #endif
-    if (mDecoderDecode(mCtx,mHybridCtx,inBuffer->pBuffer + inBuffer->nOffset,inBuffer->nFilledLen, eos) == false) {
-        LOGE("on2 decoder failed to decode frame.");
-        return OMX_ErrorBadParameter;
+    int res = mDecoderDecode(mCtx,mHybridCtx,inBuffer->pBuffer + inBuffer->nOffset,inBuffer->nFilledLen, eos);
+    if (res != 0) {
+        if (res == -2) {
+            if (isReallocateNeeded(inBuffer->pBuffer + inBuffer->nOffset,inBuffer->nFilledLen)) {
+                retains[INPORT_INDEX] = BUFFER_RETAIN_GETAGAIN;
+                HandleFormatChange();
+                return OMX_ErrorNone;
+            }
+            // drain the last frame, keep the current input buffer
+            res = mDecoderDecode(mCtx,mHybridCtx,NULL,0,true);
+            retains[INPORT_INDEX] = BUFFER_RETAIN_GETAGAIN;
+        } else {
+            LOGE("on2 decoder failed to decode frame.");
+            return OMX_ErrorBadParameter;
+        }
     }
 
 #if LOG_TIME == 1
@@ -268,6 +333,7 @@
     if (mDecodedImageHeight == 0 && mDecodedImageWidth == 0) {
         mDecodedImageWidth = mDecodedImageNewWidth;
         mDecodedImageHeight = mDecodedImageNewHeight;
+        *isResolutionChange = OMX_TRUE;
     }
     if ((mDecodedImageNewWidth != mDecodedImageWidth)
         || (mDecodedImageNewHeight!= mDecodedImageHeight)) {
@@ -316,6 +382,8 @@
 
 OMX_ERRORTYPE OMXVideoDecoderVP9Hybrid::HandleFormatChange(void)
 {
+    ALOGI("handle format change from %dx%d to %dx%d",
+        mDecodedImageWidth,mDecodedImageHeight,mDecodedImageNewWidth,mDecodedImageNewHeight);
     mDecodedImageWidth = mDecodedImageNewWidth;
     mDecodedImageHeight = mDecodedImageNewHeight;
     // Sync port definition as it may change.
@@ -384,6 +452,7 @@
     paramPortDefinitionOutput.bEnabled = (OMX_BOOL)false;
     mOMXBufferHeaderTypePtrNum = 0;
     memset(&mGraphicBufferParam, 0, sizeof(mGraphicBufferParam));
+    mDeinitDecoder(mHybridCtx);
 
     this->ports[INPORT_INDEX]->SetPortDefinition(&paramPortDefinitionInput, true);
     this->ports[OUTPORT_INDEX]->SetPortDefinition(&paramPortDefinitionOutput, true);
@@ -456,6 +525,8 @@
     port_def.format.video.cMIMEType = (OMX_STRING)VA_VED_RAW_MIME_TYPE;
     // add borders for libvpx decode need.
     port_def.format.video.nFrameWidth += VPX_DECODE_BORDER * 2;
+    mDecodedImageWidth = port_def.format.video.nFrameWidth;
+    mDecodedImageHeight = port_def.format.video.nFrameHeight;
     // make heigth 32bit align
     port_def.format.video.nFrameHeight = (port_def.format.video.nFrameHeight + 0x1f) & ~0x1f;
     port_def.format.video.eColorFormat = GetOutputColorFormat(port_def.format.video.nFrameWidth);
diff --git a/videocodec/OMXVideoDecoderVP9Hybrid.h b/videocodec/OMXVideoDecoderVP9Hybrid.h
index 5775620..f0fc2f1 100644
--- a/videocodec/OMXVideoDecoderVP9Hybrid.h
+++ b/videocodec/OMXVideoDecoderVP9Hybrid.h
@@ -38,6 +38,7 @@
             OMX_BUFFERHEADERTYPE ***pBuffers,
             buffer_retain_t *retains,
             OMX_U32 numberBuffers);
+    virtual OMX_ERRORTYPE ProcessorReset(void);
 
     virtual OMX_ERRORTYPE ProcessorPreFillBuffer(OMX_BUFFERHEADERTYPE* buffer);
     virtual bool IsAllBufferAvailable(void);
@@ -57,6 +58,7 @@
     DECLARE_HANDLER(OMXVideoDecoderVP9Hybrid, ParamVideoVp9);
 
 private:
+    bool isReallocateNeeded(const uint8_t *data, uint32_t data_sz);
     void *mCtx;
     void *mHybridCtx;
     void *mLibHandle;
@@ -69,10 +71,12 @@
     typedef bool (*InitFunc)(void *,uint32_t, uint32_t, uint32_t, uint32_t,  bool, uint32_t *);
     typedef bool (*CloseFunc)(void *, void *);
     typedef bool (*SingalRenderDoneFunc)(void *, unsigned int);
-    typedef bool (*DecodeFunc)(void *, void *, unsigned char *, unsigned int, bool);
+    typedef int (*DecodeFunc)(void *, void *, unsigned char *, unsigned int, bool);
     typedef bool (*IsBufferAvailableFunc)(void *);
     typedef int (*GetOutputFunc)(void*, void *, unsigned int *, unsigned int *);
     typedef int (*GetRawDataOutputFunc)(void*, void *, unsigned char *, int, int);
+    typedef void (*DeinitFunc)(void *);
+    typedef bool (*GetFrameResolutionFunc)(const uint8_t *, uint32_t , uint32_t *, uint32_t *);
     OpenFunc mOpenDecoder;
     InitFunc mInitDecoder;
     CloseFunc mCloseDecoder;
@@ -81,6 +85,8 @@
     IsBufferAvailableFunc mCheckBufferAvailable;
     GetOutputFunc mGetOutput;
     GetRawDataOutputFunc mGetRawDataOutput;
+    GetFrameResolutionFunc mGetFrameResolution;
+    DeinitFunc mDeinitDecoder;
     int64_t mLastTimeStamp;
     enum {
         // OMX_PARAM_PORTDEFINITIONTYPE