Merge "goldfish-codecs: Fix Cts failures for h264 decoder"
am: 6ee8d35c28

Change-Id: Ife5c9fbe1ea41b293e2f74a4a2afbdeca000b026
diff --git a/system/codecs/omx/avcdec/GoldfishAVCDec.cpp b/system/codecs/omx/avcdec/GoldfishAVCDec.cpp
index cc57f4c..cc19724 100644
--- a/system/codecs/omx/avcdec/GoldfishAVCDec.cpp
+++ b/system/codecs/omx/avcdec/GoldfishAVCDec.cpp
@@ -92,9 +92,6 @@
     mIsInFlush = false;
     mReceivedEOS = false;
 
-    memset(mTimeStamps, 0, sizeof(mTimeStamps));
-    memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid));
-
     /* Initialize both start and end times */
     mTimeStart = mTimeEnd = systemTime();
 
@@ -105,20 +102,15 @@
     // The resolution may have changed, so our safest bet is to just destroy the
     // current context and recreate another one, with the new width and height.
     mContext->destroyH264Context();
-    mContext->initH264Context(mWidth,
-                              mHeight,
-                              outputBufferWidth(),
-                              outputBufferHeight(),
-                              MediaH264Decoder::PixelFormat::YUV420P);
+    mContext.reset(nullptr);
 
     return OK;
 }
 
 status_t GoldfishAVCDec::setFlushMode() {
     /* Set the decoder in Flush mode, subsequent decode() calls will flush */
-    mContext->flush();
-
     mIsInFlush = true;
+    mContext->flush();
     return OK;
 }
 
@@ -127,8 +119,8 @@
     mContext.reset(new MediaH264Decoder());
     mContext->initH264Context(mWidth,
                               mHeight,
-                              outputBufferWidth(),
-                              outputBufferHeight(),
+                              mWidth,
+                              mHeight,
                               MediaH264Decoder::PixelFormat::YUV420P);
 
     /* Reset the plugin state */
@@ -160,36 +152,11 @@
     resetPlugin();
 }
 
-bool GoldfishAVCDec::getVUIParams() {
-    ALOGE("%s: NOT IMPLEMENTED", __func__);
-    /*
-    IV_API_CALL_STATUS_T status;
-    ih264d_ctl_get_vui_params_ip_t s_ctl_get_vui_params_ip;
-    ih264d_ctl_get_vui_params_op_t s_ctl_get_vui_params_op;
-
-    s_ctl_get_vui_params_ip.e_cmd = IVD_CMD_VIDEO_CTL;
-    s_ctl_get_vui_params_ip.e_sub_cmd =
-        (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_GET_VUI_PARAMS;
-
-    s_ctl_get_vui_params_ip.u4_size =
-        sizeof(ih264d_ctl_get_vui_params_ip_t);
-
-    s_ctl_get_vui_params_op.u4_size = sizeof(ih264d_ctl_get_vui_params_op_t);
-
-    status = ivdec_api_function(
-            (iv_obj_t *)mCodecCtx, (void *)&s_ctl_get_vui_params_ip,
-            (void *)&s_ctl_get_vui_params_op);
-
-    if (status != IV_SUCCESS) {
-        ALOGW("Error in getting VUI params: 0x%x",
-                s_ctl_get_vui_params_op.u4_error_code);
-        return false;
-    }
-
-    int32_t primaries = s_ctl_get_vui_params_op.u1_colour_primaries;
-    int32_t transfer = s_ctl_get_vui_params_op.u1_tfr_chars;
-    int32_t coeffs = s_ctl_get_vui_params_op.u1_matrix_coeffs;
-    bool fullRange = s_ctl_get_vui_params_op.u1_video_full_range_flag;
+bool GoldfishAVCDec::getVUIParams(h264_image_t& img) {
+    int32_t primaries = img.color_primaries;
+    bool fullRange = img.color_range == 2 ? true : false;
+    int32_t transfer = img.color_trc;
+    int32_t coeffs = img.colorspace;
 
     ColorAspects colorAspects;
     ColorUtils::convertIsoColorAspectsToCodecAspects(
@@ -202,31 +169,29 @@
         CHECK(err == OK);
     }
     return true;
-    */
-    return false;
 }
 
 bool GoldfishAVCDec::setDecodeArgs(
         OMX_BUFFERHEADERTYPE *inHeader,
-        OMX_BUFFERHEADERTYPE *outHeader,
-        size_t timeStampIx) {
+        OMX_BUFFERHEADERTYPE *outHeader) {
     size_t sizeY = outputBufferWidth() * outputBufferHeight();
     size_t sizeUV = sizeY / 4;
 
     /* When in flush and after EOS with zero byte input,
      * inHeader is set to zero. Hence check for non-null */
     if (inHeader) {
-        mCurrentTs = timeStampIx;
         mConsumedBytes = inHeader->nFilledLen - mInputOffset;
         mInPBuffer = inHeader->pBuffer + inHeader->nOffset + mInputOffset;
+        ALOGD("got input timestamp %lld in-addr-base %p real-data-offset %d inputoffset %d", (long long)(inHeader->nTimeStamp),
+                inHeader->pBuffer, (int)(inHeader->nOffset + mInputOffset), (int)mInputOffset);
     } else {
-        mCurrentTs = 0;
         mConsumedBytes = 0;
         mInPBuffer = nullptr;
     }
 
     if (outHeader) {
         if (outHeader->nAllocLen < sizeY + (sizeUV * 2)) {
+            ALOGE("outHeader->nAllocLen %d < needed size %d", outHeader->nAllocLen, (int)(sizeY + sizeUV * 2));
             android_errorWriteLog(0x534e4554, "27833616");
             return false;
         }
@@ -250,6 +215,8 @@
 }
 
 void GoldfishAVCDec::onQueueFilled(OMX_U32 portIndex) {
+    static int count1=0;
+    ALOGD("calling %s count %d", __func__, ++count1);
     UNUSED(portIndex);
     OMX_BUFFERHEADERTYPE *inHeader = NULL;
     BufferInfo *inInfo = NULL;
@@ -273,10 +240,11 @@
     List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
     List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
 
+    int count2=0;
     while (!outQueue.empty()) {
+        ALOGD("calling %s in while loop count %d", __func__, ++count2);
         BufferInfo *outInfo;
         OMX_BUFFERHEADERTYPE *outHeader;
-        size_t timeStampIx = 0;
 
         if (!mIsInFlush && (NULL == inHeader)) {
             if (!inQueue.empty()) {
@@ -319,26 +287,10 @@
             }
         }
 
-        /* Get a free slot in timestamp array to hold input timestamp */
-        {
-            size_t i;
-            timeStampIx = 0;
-            for (i = 0; i < MAX_TIME_STAMPS; i++) {
-                if (!mTimeStampsValid[i]) {
-                    timeStampIx = i;
-                    break;
-                }
-            }
-            if (inHeader != NULL) {
-                mTimeStampsValid[timeStampIx] = true;
-                mTimeStamps[timeStampIx] = inHeader->nTimeStamp;
-            }
-        }
-
         {
             nsecs_t timeDelay, timeTaken;
 
-            if (!setDecodeArgs(inHeader, outHeader, timeStampIx)) {
+            if (!setDecodeArgs(inHeader, outHeader)) {
                 ALOGE("Decoder arg setup failed");
                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
                 mSignalledError = true;
@@ -353,68 +305,74 @@
             // TODO: We also need to send the timestamp
             h264_result_t h264Res = {(int)MediaH264Decoder::Err::NoErr, 0};
             if (inHeader != nullptr) {
-                ALOGE("Decoding frame(sz=%lu)", (unsigned long)(inHeader->nFilledLen - mInputOffset));
+                ALOGD("Decoding frame(sz=%lu)", (unsigned long)(inHeader->nFilledLen - mInputOffset));
                 h264Res = mContext->decodeFrame(mInPBuffer,
-                                                inHeader->nFilledLen - mInputOffset);
+                                                inHeader->nFilledLen - mInputOffset,
+                                                inHeader->nTimeStamp);
                 mConsumedBytes = h264Res.bytesProcessed;
                 if (h264Res.ret == (int)MediaH264Decoder::Err::DecoderRestarted) {
-                    // The host will always restart when given a new set of SPS
-                    // and PPS frames.
                     mChangingResolution = true;
                 }
             } else {
-                ALOGE("No more input data. Attempting to get a decoded frame, if any.");
+                ALOGD("No more input data. Attempting to get a decoded frame, if any.");
             }
             h264_image_t img = mContext->getImage();
 
 
-            // TODO: support getVUIParams()
-//            getVUIParams();
+            getVUIParams(img);
 
             mTimeEnd = systemTime();
             /* Compute time taken for decode() */
             timeTaken = mTimeEnd - mTimeStart;
 
-            ALOGV("timeTaken=%6lldus delay=%6lldus numBytes=Nan",
-                    (long long) (timeTaken / 1000LL), (long long) (timeDelay / 1000LL));
 
-            if ((inHeader != NULL) && (img.data == nullptr)) {
-                /* If the input did not contain picture data, then ignore
-                 * the associated timestamp */
-                mTimeStampsValid[timeStampIx] = false;
+            if (inHeader) {
+                ALOGD("input time stamp %lld flag %d", inHeader->nTimeStamp, (int)(inHeader->nFlags));
             }
 
             // If the decoder is in the changing resolution mode and there is no output present,
             // that means the switching is done and it's ready to reset the decoder and the plugin.
             if (mChangingResolution && img.data == nullptr) {
                 mChangingResolution = false;
-                resetPlugin();
-                // The decoder on the host has actually already restarted given
-                // the new information, so we don't have to refeed the same
-                // information again.
-                mInputOffset += mConsumedBytes;
-                continue;
-            }
-
-            // Combine the resolution change and coloraspects change in one
-            // PortSettingChange event if necessary.
-            if (img.data != nullptr) {
+                ALOGD("re-create decoder because resolution changed");
                 bool portWillReset = false;
                 handlePortSettingsChange(&portWillReset, img.width, img.height);
-                if (portWillReset) {
-                    ALOGE("port resetting (img.width=%u, img.height=%u, mWidth=%u, mHeight=%u)",
+                {
+                    ALOGD("handling port reset");
+                    ALOGD("port resetting (img.width=%u, img.height=%u, mWidth=%u, mHeight=%u)",
                           img.width, img.height, mWidth, mHeight);
                     resetDecoder();
                     resetPlugin();
-                    return;
+
+                mContext->destroyH264Context();
+                mContext.reset(new MediaH264Decoder());
+                mContext->initH264Context(mWidth,
+                              mHeight,
+                              mWidth,
+                              mHeight,
+                              MediaH264Decoder::PixelFormat::YUV420P);
+                //mInputOffset += mConsumedBytes;
+                return;
                 }
             }
 
             if (img.data != nullptr) {
-                outHeader->nFilledLen = img.ret;
-                memcpy(outHeader->pBuffer, img.data, img.ret);
-                outHeader->nTimeStamp = mTimeStamps[mCurrentTs];
-                mTimeStampsValid[mCurrentTs] = false;
+                outHeader->nFilledLen =  (outputBufferWidth() * outputBufferHeight() * 3) / 2;
+                int myStride = outputBufferWidth();
+                for (int i=0; i < mHeight; ++i) {
+                    memcpy(outHeader->pBuffer + i * myStride, img.data + i * mWidth, mWidth);
+                }
+                int Y = myStride * outputBufferHeight();
+                for (int i=0; i < mHeight/2; ++i) {
+                    memcpy(outHeader->pBuffer + Y + i * myStride / 2 , img.data + mWidth * mHeight + i * mWidth/2, mWidth/2);
+                }
+                int UV = Y/4;
+                for (int i=0; i < mHeight/2; ++i) {
+                    memcpy(outHeader->pBuffer + Y + UV + i * myStride / 2 , img.data + mWidth * mHeight * 5/4 + i * mWidth/2, mWidth/2);
+                }
+
+                outHeader->nTimeStamp = img.pts;
+                ALOGD("got output timestamp %lld", (long long)(img.pts));
 
                 outInfo->mOwnedByUs = false;
                 outQueue.erase(outQueue.begin());
@@ -422,6 +380,7 @@
                 notifyFillBufferDone(outHeader);
                 outHeader = NULL;
             } else if (mIsInFlush) {
+                ALOGD("not img.data and it is in flush mode");
                 /* If in flush mode and no output is returned by the codec,
                  * then come out of flush mode */
                 mIsInFlush = false;
@@ -429,6 +388,7 @@
                 /* If EOS was recieved on input port and there is no output
                  * from the codec, then signal EOS on output port */
                 if (mReceivedEOS) {
+                    ALOGD("recived EOS, re-create host context");
                     outHeader->nFilledLen = 0;
                     outHeader->nFlags |= OMX_BUFFERFLAG_EOS;
 
@@ -438,6 +398,14 @@
                     notifyFillBufferDone(outHeader);
                     outHeader = NULL;
                     resetPlugin();
+                                    mContext->destroyH264Context();
+                mContext.reset(new MediaH264Decoder());
+                mContext->initH264Context(mWidth,
+                              mHeight,
+                              mWidth,
+                              mHeight,
+                              MediaH264Decoder::PixelFormat::YUV420P);
+
                 }
             }
             mInputOffset += mConsumedBytes;
diff --git a/system/codecs/omx/avcdec/GoldfishAVCDec.h b/system/codecs/omx/avcdec/GoldfishAVCDec.h
index f0e338c..d3da30d 100644
--- a/system/codecs/omx/avcdec/GoldfishAVCDec.h
+++ b/system/codecs/omx/avcdec/GoldfishAVCDec.h
@@ -64,13 +64,6 @@
     nsecs_t mTimeStart;   // Time at the start of decode()
     nsecs_t mTimeEnd;     // Time at the end of decode()
 
-    // Status of entries in the timestamp array
-    bool mTimeStampsValid[MAX_TIME_STAMPS];
-
-    // Timestamp array - Since codec does not take 64 bit timestamps,
-    // they are maintained in the plugin
-    OMX_S64 mTimeStamps[MAX_TIME_STAMPS];
-
 #ifdef FILE_DUMP_ENABLE
     char mInFile[200];
 #endif /* FILE_DUMP_ENABLE */
@@ -98,13 +91,11 @@
 
     bool setDecodeArgs(
             OMX_BUFFERHEADERTYPE *inHeader,
-            OMX_BUFFERHEADERTYPE *outHeader,
-            size_t timeStampIx);
+            OMX_BUFFERHEADERTYPE *outHeader);
 
-    bool getVUIParams();
+    bool getVUIParams(h264_image_t& img);
 
     std::unique_ptr<MediaH264Decoder> mContext;
-    uint64_t mCurrentTs = 0;
     uint64_t mConsumedBytes = 0;
     uint8_t* mInPBuffer = nullptr;
     uint8_t* mOutHeaderBuf = nullptr;
diff --git a/system/codecs/omx/avcdec/MediaH264Decoder.cpp b/system/codecs/omx/avcdec/MediaH264Decoder.cpp
index aa97c2d..6e1ada0 100644
--- a/system/codecs/omx/avcdec/MediaH264Decoder.cpp
+++ b/system/codecs/omx/avcdec/MediaH264Decoder.cpp
@@ -41,7 +41,7 @@
                              MediaOperation::DestroyContext);
 }
 
-h264_result_t MediaH264Decoder::decodeFrame(uint8_t* img, size_t szBytes) {
+h264_result_t MediaH264Decoder::decodeFrame(uint8_t* img, size_t szBytes, uint64_t pts) {
     auto transport = GoldfishMediaTransport::getInstance();
     uint8_t* hostSrc = transport->getInputAddr();
     if (img != nullptr && szBytes > 0) {
@@ -49,6 +49,7 @@
     }
     transport->writeParam(transport->offsetOf((uint64_t)(hostSrc)), 0);
     transport->writeParam((uint64_t)szBytes, 1);
+    transport->writeParam((uint64_t)pts, 2);
     transport->sendOperation(MediaCodecType::H264Codec,
                              MediaOperation::DecodeImage);
 
@@ -68,7 +69,7 @@
 }
 
 h264_image_t MediaH264Decoder::getImage() {
-    h264_image_t res = { nullptr, 0, 0, 0 };
+    h264_image_t res { };
     auto transport = GoldfishMediaTransport::getInstance();
     uint8_t* dst = transport->getOutputAddr();
     transport->writeParam(transport->offsetOf((uint64_t)(dst)), 0);
@@ -80,6 +81,14 @@
         res.data = dst;
         res.width = *(uint32_t*)(retptr + 8);
         res.height = *(uint32_t*)(retptr + 16);
+        res.pts = *(uint32_t*)(retptr + 24);
+        res.color_primaries = *(uint32_t*)(retptr + 32);
+        res.color_range = *(uint32_t*)(retptr + 40);
+        res.color_trc = *(uint32_t*)(retptr + 48);
+        res.colorspace = *(uint32_t*)(retptr + 56);
+    } else if (res.ret == (int)(Err::DecoderRestarted)) {
+        res.width = *(uint32_t*)(retptr + 8);
+        res.height = *(uint32_t*)(retptr + 16);
     }
 
     return res;
diff --git a/system/codecs/omx/avcdec/MediaH264Decoder.h b/system/codecs/omx/avcdec/MediaH264Decoder.h
index 510da28..1b1f0bd 100644
--- a/system/codecs/omx/avcdec/MediaH264Decoder.h
+++ b/system/codecs/omx/avcdec/MediaH264Decoder.h
@@ -26,6 +26,11 @@
     const uint8_t* data;
     uint32_t width;
     uint32_t height;
+    uint64_t pts; // presentation time stamp
+    uint64_t color_primaries;
+    uint64_t color_range;
+    uint64_t color_trc;
+    uint64_t colorspace;
     // on success, |ret| will indicate the size of |data|.
     // If failed, |ret| will contain some negative error code.
     int ret;
@@ -56,7 +61,7 @@
                          unsigned int outHeight,
                          PixelFormat pixFmt);
     void destroyH264Context();
-    h264_result_t decodeFrame(uint8_t* img, size_t szBytes);
+    h264_result_t decodeFrame(uint8_t* img, size_t szBytes, uint64_t pts);
     void flush();
     h264_image_t getImage();
 };