SoftAVCDec: Handle interlaced streams where two fields are sent in one input

When both fields are sent in a single input buffer, only the first field was
being decoded. Fix this by not releasing input buffer when some bytes are still
left unused in the input buffer.
If both fields are sent in a separate call, decoder handles that correctly and
returns an output frame for every two fields

Bug: 32364044
Test: Manually tested by decoding clip attached in the above bug

Change-Id: Idab5acd9cbaefc5d2560a70d375f3a532d9e78eb
diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
index 61b9bfd..801eebd 100644
--- a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
+++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
@@ -120,7 +120,8 @@
       mIvColorFormat(IV_YUV_420P),
       mChangingResolution(false),
       mSignalledError(false),
-      mStride(mWidth){
+      mStride(mWidth),
+      mInputOffset(0){
     initPorts(
             kNumBuffers, INPUT_BUF_SIZE, kNumBuffers, CODEC_MIME_TYPE);
 
@@ -214,6 +215,7 @@
 status_t SoftAVC::resetPlugin() {
     mIsInFlush = false;
     mReceivedEOS = false;
+    mInputOffset = 0;
     memset(mTimeStamps, 0, sizeof(mTimeStamps));
     memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid));
 
@@ -400,8 +402,8 @@
     if (inHeader) {
         ps_dec_ip->u4_ts = timeStampIx;
         ps_dec_ip->pv_stream_buffer =
-            inHeader->pBuffer + inHeader->nOffset;
-        ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen;
+            inHeader->pBuffer + inHeader->nOffset + mInputOffset;
+        ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen - mInputOffset;
     } else {
         ps_dec_ip->u4_ts = 0;
         ps_dec_ip->pv_stream_buffer = NULL;
@@ -472,6 +474,8 @@
 
 void SoftAVC::onQueueFilled(OMX_U32 portIndex) {
     UNUSED(portIndex);
+    OMX_BUFFERHEADERTYPE *inHeader = NULL;
+    BufferInfo *inInfo = NULL;
 
     if (mSignalledError) {
         return;
@@ -498,17 +502,11 @@
     List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
 
     while (!outQueue.empty()) {
-        BufferInfo *inInfo;
-        OMX_BUFFERHEADERTYPE *inHeader;
-
         BufferInfo *outInfo;
         OMX_BUFFERHEADERTYPE *outHeader;
-        size_t timeStampIx;
+        size_t timeStampIx = 0;
 
-        inInfo = NULL;
-        inHeader = NULL;
-
-        if (!mIsInFlush) {
+        if (!mIsInFlush && (NULL == inHeader)) {
             if (!inQueue.empty()) {
                 inInfo = *inQueue.begin();
                 inHeader = inInfo->mHeader;
@@ -575,7 +573,7 @@
                 return;
             }
             // If input dump is enabled, then write to file
-            DUMP_TO_FILE(mInFile, s_dec_ip.pv_stream_buffer, s_dec_ip.u4_num_Bytes);
+            DUMP_TO_FILE(mInFile, s_dec_ip.pv_stream_buffer, s_dec_ip.u4_num_Bytes, mInputOffset);
 
             GETTIME(&mTimeStart, NULL);
             /* Compute time elapsed between end of previous decode()
@@ -683,24 +681,26 @@
                     resetPlugin();
                 }
             }
+            mInputOffset += s_dec_op.u4_num_bytes_consumed;
         }
-
-        /* If input EOS is seen and decoder is not in flush mode,
-         * set the decoder in flush mode.
-         * There can be a case where EOS is sent along with last picture data
-         * In that case, only after decoding that input data, decoder has to be
-         * put in flush. This case is handled here  */
-
-        if (mReceivedEOS && !mIsInFlush) {
-            setFlushMode();
-        }
-
-        if (inHeader != NULL) {
+        // If more than 4 bytes are remaining in input, then do not release it
+        if (inHeader != NULL && ((inHeader->nFilledLen - mInputOffset) <= 4)) {
             inInfo->mOwnedByUs = false;
             inQueue.erase(inQueue.begin());
             inInfo = NULL;
             notifyEmptyBufferDone(inHeader);
             inHeader = NULL;
+            mInputOffset = 0;
+
+            /* If input EOS is seen and decoder is not in flush mode,
+             * set the decoder in flush mode.
+             * There can be a case where EOS is sent along with last picture data
+             * In that case, only after decoding that input data, decoder has to be
+             * put in flush. This case is handled here  */
+
+            if (mReceivedEOS && !mIsInFlush) {
+                setFlushMode();
+            }
         }
     }
 }
diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.h b/media/libstagefright/codecs/avcdec/SoftAVCDec.h
index a73187b..38b24a6 100644
--- a/media/libstagefright/codecs/avcdec/SoftAVCDec.h
+++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.h
@@ -98,6 +98,7 @@
     bool mFlushNeeded;
     bool mSignalledError;
     size_t mStride;
+    size_t mInputOffset;
 
     status_t initDecoder();
     status_t deInitDecoder();
@@ -140,10 +141,10 @@
         ALOGD("Could not open file %s", m_filename);    \
     }                                                   \
 }
-#define DUMP_TO_FILE(m_filename, m_buf, m_size)         \
+#define DUMP_TO_FILE(m_filename, m_buf, m_size, m_offset)\
 {                                                       \
     FILE *fp = fopen(m_filename, "ab");                 \
-    if (fp != NULL && m_buf != NULL) {                  \
+    if (fp != NULL && m_buf != NULL && m_offset == 0) { \
         int i;                                          \
         i = fwrite(m_buf, 1, m_size, fp);               \
         ALOGD("fwrite ret %d to write %d", i, m_size);  \
@@ -151,10 +152,12 @@
             ALOGD("Error in fwrite, returned %d", i);   \
             perror("Error in write to file");           \
         }                                               \
-        fclose(fp);                                     \
-    } else {                                            \
+    } else if (fp == NULL) {                            \
         ALOGD("Could not write to file %s", m_filename);\
     }                                                   \
+    if (fp) {                                           \
+        fclose(fp);                                     \
+    }                                                   \
 }
 #else /* FILE_DUMP_ENABLE */
 #define INPUT_DUMP_PATH
@@ -163,7 +166,7 @@
 #define OUTPUT_DUMP_EXT
 #define GENERATE_FILE_NAMES()
 #define CREATE_DUMP_FILE(m_filename)
-#define DUMP_TO_FILE(m_filename, m_buf, m_size)
+#define DUMP_TO_FILE(m_filename, m_buf, m_size, m_offset)
 #endif /* FILE_DUMP_ENABLE */
 
 } // namespace android