Merge "Fix 5123908: Native crash rewinding movie"
diff --git a/libvideoeditor/lvpp/PreviewRenderer.cpp b/libvideoeditor/lvpp/PreviewRenderer.cpp
index 63eceef..59ac712 100755
--- a/libvideoeditor/lvpp/PreviewRenderer.cpp
+++ b/libvideoeditor/lvpp/PreviewRenderer.cpp
@@ -49,25 +49,27 @@
 
 int PreviewRenderer::init() {
     int err = 0;
+    ANativeWindow* anw = mSurface.get();
 
-    err = native_window_api_connect(mSurface.get(), NATIVE_WINDOW_API_CPU);
+    err = native_window_api_connect(anw, NATIVE_WINDOW_API_CPU);
     if (err) goto fail;
 
-    err = native_window_set_usage(mSurface.get(),
-            GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN);
+    err = native_window_set_usage(
+            anw, GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN);
     if (err) goto fail;
 
-    err = native_window_set_buffer_count(mSurface.get(), 3);
+    err = native_window_set_buffer_count(anw, 3);
     if (err) goto fail;
 
     err = native_window_set_scaling_mode(
-            mSurface.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+            anw, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
     if (err) goto fail;
 
     err = native_window_set_buffers_geometry(
-            mSurface.get(),
-            mWidth, mHeight,
-            HAL_PIXEL_FORMAT_YV12);
+            anw, mWidth, mHeight, HAL_PIXEL_FORMAT_YV12);
+    if (err) goto fail;
+
+    err = native_window_set_buffers_transform(anw, 0);
     if (err) goto fail;
 
 fail:
diff --git a/libvideoeditor/vss/mcs/src/M4MCS_API.c b/libvideoeditor/vss/mcs/src/M4MCS_API.c
index 8a93720..baa0dd5 100755
--- a/libvideoeditor/vss/mcs/src/M4MCS_API.c
+++ b/libvideoeditor/vss/mcs/src/M4MCS_API.c
@@ -3732,10 +3732,44 @@
                 pC->EncodingWidth = pC->InputFileProperties.uiVideoWidth;
             uiFrameHeight =
                 pC->EncodingHeight = pC->InputFileProperties.uiVideoHeight;
+
             /**
             * Set output video profile and level */
             pC->encodingVideoProfile = pC->InputFileProperties.uiVideoProfile;
             pC->encodingVideoLevel = pC->InputFileProperties.uiVideoLevel;
+
+            // Clip's original width and height may not be
+            // multiple of 16.
+            // Ensure encoding width and height are multiple of 16
+
+            uint32_t remainder = pC->EncodingWidth % 16;
+            if (remainder != 0) {
+                if (remainder >= 8) {
+                    // Roll forward
+                    pC->EncodingWidth =
+                        pC->EncodingWidth + (16-remainder);
+                } else {
+                    // Roll backward
+                    pC->EncodingWidth =
+                        pC->EncodingWidth - remainder;
+                }
+                uiFrameWidth = pC->EncodingWidth;
+            }
+
+            remainder = pC->EncodingHeight % 16;
+            if (remainder != 0) {
+                if (remainder >= 8) {
+                    // Roll forward
+                    pC->EncodingHeight =
+                        pC->EncodingHeight + (16-remainder);
+                } else {
+                    // Roll backward
+                    pC->EncodingHeight =
+                        pC->EncodingHeight - remainder;
+                }
+                uiFrameHeight = pC->EncodingHeight;
+            }
+
         }
         else
         {
@@ -10058,7 +10092,48 @@
 
     M4OSA_TRACE2_1("M4MCS_intCleanUp_ReadersDecoders called with pC=0x%x", pC);
 
+    /**/
+    /* ----- Free video decoder stuff, if needed ----- */
+
+    if( M4OSA_NULL != pC->pViDecCtxt )
+    {
+        err = pC->m_pVideoDecoder->m_pFctDestroy(pC->pViDecCtxt);
+        pC->pViDecCtxt = M4OSA_NULL;
+
+        if( M4NO_ERROR != err )
+        {
+            M4OSA_TRACE1_1(
+                "M4MCS_cleanUp: m_pVideoDecoder->pFctDestroy returns 0x%x",
+                err);
+            /**< don't return, we still have stuff to free */
+        }
+    }
+
+    /* ----- Free the audio decoder stuff ----- */
+
+    if( M4OSA_NULL != pC->pAudioDecCtxt )
+    {
+        err = pC->m_pAudioDecoder->m_pFctDestroyAudioDec(pC->pAudioDecCtxt);
+        pC->pAudioDecCtxt = M4OSA_NULL;
+
+        if( M4NO_ERROR != err )
+        {
+            M4OSA_TRACE1_1(
+                "M4MCS_cleanUp: m_pAudioDecoder->m_pFctDestroyAudioDec returns 0x%x",
+                err);
+            /**< don't return, we still have stuff to free */
+        }
+    }
+
+    if( M4OSA_NULL != pC->AudioDecBufferOut.m_dataAddress )
+    {
+        free(pC->AudioDecBufferOut.m_dataAddress);
+        pC->AudioDecBufferOut.m_dataAddress = M4OSA_NULL;
+    }
+
     /* ----- Free reader stuff, if needed ----- */
+    // We cannot free the reader before decoders because the decoders may read
+    // from the reader (in another thread) before being stopped.
 
     if( M4OSA_NULL != pC->
         pReaderContext ) /**< may be M4OSA_NULL if M4MCS_open was not called */
@@ -10106,44 +10181,6 @@
         free(pC->m_pDataVideoAddress2);
         pC->m_pDataVideoAddress2 = M4OSA_NULL;
     }
-    /**/
-    /* ----- Free video decoder stuff, if needed ----- */
-
-    if( M4OSA_NULL != pC->pViDecCtxt )
-    {
-        err = pC->m_pVideoDecoder->m_pFctDestroy(pC->pViDecCtxt);
-        pC->pViDecCtxt = M4OSA_NULL;
-
-        if( M4NO_ERROR != err )
-        {
-            M4OSA_TRACE1_1(
-                "M4MCS_cleanUp: m_pVideoDecoder->pFctDestroy returns 0x%x",
-                err);
-            /**< don't return, we still have stuff to free */
-        }
-    }
-
-    /* ----- Free the audio decoder stuff ----- */
-
-    if( M4OSA_NULL != pC->pAudioDecCtxt )
-    {
-        err = pC->m_pAudioDecoder->m_pFctDestroyAudioDec(pC->pAudioDecCtxt);
-        pC->pAudioDecCtxt = M4OSA_NULL;
-
-        if( M4NO_ERROR != err )
-        {
-            M4OSA_TRACE1_1(
-                "M4MCS_cleanUp: m_pAudioDecoder->m_pFctDestroyAudioDec returns 0x%x",
-                err);
-            /**< don't return, we still have stuff to free */
-        }
-    }
-
-    if( M4OSA_NULL != pC->AudioDecBufferOut.m_dataAddress )
-    {
-        free(pC->AudioDecBufferOut.m_dataAddress);
-        pC->AudioDecBufferOut.m_dataAddress = M4OSA_NULL;
-    }
 
     return M4NO_ERROR;
 }
diff --git a/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoDecoder.cpp b/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoDecoder.cpp
index f038b47..c5f1a0f 100755
--- a/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoDecoder.cpp
+++ b/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoDecoder.cpp
@@ -1384,6 +1384,13 @@
             continue;
         }
 
+        // The OMXCodec client should expect to receive 0-length buffers
+        // and drop the 0-length buffers.
+        if (pNextBuffer->range_length() == 0) {
+            pNextBuffer->release();
+            continue;
+        }
+
         // Now we have a good next buffer, release the previous one.
         if (pDecoderBuffer != NULL) {
             pDecoderBuffer->release();