Speed up thumbnail generation.

We accept a tolerance parameter while decoding. We also tell the
stagefright decoder to jump so we can move to the new frame faster.

Change-Id: Iede3c1f909f1c42b2d5a53c782083367b00f62fb
diff --git a/libvideoeditor/vss/common/inc/M4DECODER_Common.h b/libvideoeditor/vss/common/inc/M4DECODER_Common.h
index 4608af1..dd9c0fa 100755
--- a/libvideoeditor/vss/common/inc/M4DECODER_Common.h
+++ b/libvideoeditor/vss/common/inc/M4DECODER_Common.h
@@ -230,7 +230,9 @@
  *
  * @param    pContext:        (OUT)    Context of the decoder
  * @param    pStreamHandler:    (IN)    Pointer to a video stream description
- * @param    pSrcInterface:    (IN)    Pointer to the M4READER_DataInterface structure that must
+ * @param    pGlobalInterface:  (IN)    Pointer to the M4READER_GlobalInterface structure that must
+ *                                       be used by the decoder to read data from the stream
+ * @param    pDataInterface:    (IN)    Pointer to the M4READER_DataInterface structure that must
  *                                       be used by the decoder to read data from the stream
  * @param    pAccessUnit        (IN)    Pointer to an access unit (allocated by the caller)
  *                                      where the decoded data are stored
@@ -243,7 +245,8 @@
 */
 typedef M4OSA_ERR  (M4DECODER_create_fct)    (M4OSA_Context *pContext,
                                                  M4_StreamHandler *pStreamHandler,
-                                                 M4READER_DataInterface *pSrcInterface,
+                                                 M4READER_GlobalInterface *pGlobalInterface,
+                                                 M4READER_DataInterface *pDataInterface,
                                                  M4_AccessUnit *pAccessUnit,
                                                  M4OSA_Void* pUserData);
 
@@ -313,6 +316,8 @@
  *                                    OUT:Time of the last decoded frame (in ms)
  * @param   bJump:      (IN)        0 if no jump occured just before this call
  *                                  1 if a a jump has just been made
+ * @param   tolerance:      (IN)        We may decode an earlier frame within the tolerance.
+ *                                      The time difference is specified in milliseconds.
  *
  * @return    M4NO_ERROR                 there is no error
  * @return    M4ERR_PARAMETER            at least one parameter is not properly set
@@ -320,7 +325,7 @@
  ************************************************************************
 */
 typedef M4OSA_ERR  (M4DECODER_decode_fct)    (M4OSA_Context context, M4_MediaTime* pTime,
-                                                 M4OSA_Bool bJump);
+                                                 M4OSA_Bool bJump, M4OSA_UInt32 tolerance);
 
 /**
  ************************************************************************
@@ -363,4 +368,3 @@
 } M4DECODER_VideoInterface;
 
 #endif /*__M4DECODER_COMMON_H__*/
-
diff --git a/libvideoeditor/vss/mcs/src/M4MCS_API.c b/libvideoeditor/vss/mcs/src/M4MCS_API.c
index 19053e9..79eedba 100755
--- a/libvideoeditor/vss/mcs/src/M4MCS_API.c
+++ b/libvideoeditor/vss/mcs/src/M4MCS_API.c
@@ -5583,8 +5583,8 @@
 #endif /* M4VSS_ENABLE_EXTERNAL_DECODERS ? */
 
         err = pC->m_pVideoDecoder->m_pFctCreate(&pC->pViDecCtxt,
-            &pC->pReaderVideoStream->m_basicProperties, pC->m_pReaderDataIt,
-            &pC->ReaderVideoAU, decoderUserData);
+            &pC->pReaderVideoStream->m_basicProperties, pC->m_pReader,
+            pC->m_pReaderDataIt, &pC->ReaderVideoAU, decoderUserData);
 
         if( (M4OSA_UInt32)(M4ERR_DECODER_H263_PROFILE_NOT_SUPPORTED) == err )
         {
@@ -7660,15 +7660,6 @@
 
     }
     /* - CRLV6775 -H.264 Trimming */
-    err = pC->m_pReader->m_pFctJump(pC->pReaderContext,
-        (M4_StreamHandler *)pC->pReaderVideoStream, &iCts);
-
-    if( M4NO_ERROR != err )
-    {
-        M4OSA_TRACE1_1(
-            "M4MCS_intStepBeginVideoJump: m_pFctJump(V) returns 0x%x!", err);
-        return err;
-    }
 
     /**
     * Decode one step */
@@ -7689,7 +7680,7 @@
     pC->isRenderDup = M4OSA_FALSE;
     err =
         pC->m_pVideoDecoder->m_pFctDecode(pC->pViDecCtxt, &pC->dViDecCurrentCts,
-        M4OSA_TRUE);
+        M4OSA_TRUE, 0);
 
     if( ( M4NO_ERROR != err) && (M4WAR_NO_MORE_AU != err)
         && (err != M4WAR_VIDEORENDERER_NO_NEW_FRAME) )
@@ -7752,7 +7743,7 @@
         pC->dViDecCurrentCts);
     pC->isRenderDup = M4OSA_FALSE;
     err = pC->m_pVideoDecoder->m_pFctDecode(pC->pViDecCtxt, &dDecTarget,
-        M4OSA_FALSE);
+        M4OSA_FALSE, 0);
 
     if( ( M4NO_ERROR != err) && (M4WAR_NO_MORE_AU != err)
         && (err != M4WAR_VIDEORENDERER_NO_NEW_FRAME) )
@@ -9273,7 +9264,7 @@
         mtTranscodedTime);
     pC->isRenderDup = M4OSA_FALSE;
     err = pC->m_pVideoDecoder->m_pFctDecode(pC->pViDecCtxt, &mtTranscodedTime,
-        M4OSA_FALSE);
+        M4OSA_FALSE, 0);
 
     if( M4WAR_NO_MORE_AU == err )
     {
diff --git a/libvideoeditor/vss/src/M4DECODER_Null.c b/libvideoeditor/vss/src/M4DECODER_Null.c
index 8a54f3d..a0dad30 100755
--- a/libvideoeditor/vss/src/M4DECODER_Null.c
+++ b/libvideoeditor/vss/src/M4DECODER_Null.c
@@ -92,6 +92,7 @@
 */

 M4OSA_ERR M4DECODER_NULL_create(M4OSA_Context *pContext,

                                 M4_StreamHandler *pStreamHandler,

+                                M4READER_GlobalInterface *pReaderGlobalInterface,
                                 M4READER_DataInterface *pReaderDataInterface,

                                 M4_AccessUnit* pAccessUnit,

                                 M4OSA_Void* pUserData) {

@@ -293,7 +294,8 @@
  ************************************************************************

 */

 M4OSA_ERR M4DECODER_NULL_decode(M4OSA_Context context,

-                                M4_MediaTime* pTime, M4OSA_Bool bJump) {

+                                M4_MediaTime* pTime, M4OSA_Bool bJump,
+                                M4OSA_UInt32 tolerance) {
 

     // Do nothing; input time stamp itself returned

     return M4NO_ERROR;

diff --git a/libvideoeditor/vss/src/M4VSS3GPP_Clip.c b/libvideoeditor/vss/src/M4VSS3GPP_Clip.c
index 0303877..a79128d 100755
--- a/libvideoeditor/vss/src/M4VSS3GPP_Clip.c
+++ b/libvideoeditor/vss/src/M4VSS3GPP_Clip.c
@@ -209,8 +209,11 @@
         decoderUserData = M4OSA_NULL;
 
         err = pClipCtxt->ShellAPI.m_pVideoDecoder->m_pFctCreate(
-                  &pClipCtxt->pViDecCtxt, &dummyStreamHandler,
-                  pClipCtxt->ShellAPI.m_pReaderDataIt, &pClipCtxt->VideoAU,
+                  &pClipCtxt->pViDecCtxt,
+                  &dummyStreamHandler,
+                  pClipCtxt->ShellAPI.m_pReader,
+                  pClipCtxt->ShellAPI.m_pReaderDataIt,
+                  &pClipCtxt->VideoAU,
                   decoderUserData);
 
         if (M4NO_ERROR != err) {
@@ -607,6 +610,7 @@
             err = pClipCtxt->ShellAPI.m_pVideoDecoder->m_pFctCreate(
                 &pClipCtxt->pViDecCtxt,
                 &pClipCtxt->pVideoStream->m_basicProperties,
+                pClipCtxt->ShellAPI.m_pReader,
                 pClipCtxt->ShellAPI.m_pReaderDataIt,
                 &pClipCtxt->VideoAU, decoderUserData);
 
@@ -792,47 +796,10 @@
     if( M4VSS3GPP_kClipStatus_READ == pClipCtxt->Vstatus )
     {
         /**
-        * Jump to the previous RAP in the clip (first get the time, then jump) */
-        if(M4VIDEOEDITING_kFileType_ARGB8888 != pClipCtxt->pSettings->FileType) {
-            iRapCts = iClipCts;
+        * The decoder must be told to jump */
+        bClipJump = M4OSA_TRUE;
+        pClipCtxt->iVideoDecCts = iClipCts;
 
-            err = pClipCtxt->ShellAPI.m_pReader->m_pFctGetPrevRapTime(
-                pClipCtxt->pReaderContext,
-                (M4_StreamHandler *)pClipCtxt->pVideoStream, &iRapCts);
-
-            if( M4WAR_READER_INFORMATION_NOT_PRESENT == err )
-            {
-                /* No RAP table, jump backward and predecode */
-                iRapCts = iClipCts - M4VSS3GPP_NO_STSS_JUMP_POINT;
-
-                if( iRapCts < 0 )
-                    iRapCts = 0;
-            }
-            else if( M4NO_ERROR != err )
-            {
-                M4OSA_TRACE1_1(
-                    "M4VSS3GPP_intClipDecodeVideoUpToCts: m_pFctGetPrevRapTime returns 0x%x!",
-                    err);
-                return err;
-            }
-
-            err =
-                pClipCtxt->ShellAPI.m_pReader->m_pFctJump(pClipCtxt->pReaderContext,
-                (M4_StreamHandler *)pClipCtxt->pVideoStream, &iRapCts);
-
-            if( M4NO_ERROR != err )
-            {
-                M4OSA_TRACE1_1(
-                    "M4VSS3GPP_intClipDecodeVideoUpToCts: m_pFctJump returns 0x%x!",
-                    err);
-                return err;
-            }
-
-            /**
-            * The decoder must be told that we jumped */
-            bClipJump = M4OSA_TRUE;
-            pClipCtxt->iVideoDecCts = iRapCts;
-        }
         /**
         * Remember the clip reading state */
         pClipCtxt->Vstatus = M4VSS3GPP_kClipStatus_DECODE_UP_TO;
@@ -873,7 +840,7 @@
     pClipCtxt->isRenderDup = M4OSA_FALSE;
     err =
         pClipCtxt->ShellAPI.m_pVideoDecoder->m_pFctDecode(pClipCtxt->pViDecCtxt,
-        &dDecodeTime, bClipJump);
+        &dDecodeTime, bClipJump, 0);
 
     if( ( M4NO_ERROR != err) && (M4WAR_NO_MORE_AU != err)
         && (err != M4WAR_VIDEORENDERER_NO_NEW_FRAME) )
diff --git a/libvideoeditor/vss/stagefrightshells/inc/VideoEditorVideoDecoder_internal.h b/libvideoeditor/vss/stagefrightshells/inc/VideoEditorVideoDecoder_internal.h
index 9be6cbd..cca5ee9 100755
--- a/libvideoeditor/vss/stagefrightshells/inc/VideoEditorVideoDecoder_internal.h
+++ b/libvideoeditor/vss/stagefrightshells/inc/VideoEditorVideoDecoder_internal.h
@@ -81,6 +81,7 @@
     sp<MediaSource>         mReaderSource; /**< Reader access > */
 
     /* READER */
+    M4READER_GlobalInterface *m_pReaderGlobal;
     M4READER_DataInterface  *m_pReader;
     M4_AccessUnit           *m_pNextAccessUnitToDecode;
 
diff --git a/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoDecoder.cpp b/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoDecoder.cpp
index 3447c2c..13dea53 100755
--- a/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoDecoder.cpp
+++ b/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoDecoder.cpp
@@ -35,13 +35,15 @@
 /********************
  *   DEFINITIONS    *
  ********************/
-#define OMX_QCOM_COLOR_FormatYVU420SemiPlanar 0x7FA30C00
 #define MAX_DEC_BUFFERS 10
 
 /********************
  *   SOURCE CLASS   *
  ********************/
 using namespace android;
+static M4OSA_ERR copyBufferToQueue(
+    VideoEditorVideoDecoder_Context* pDecShellContext,
+    MediaBuffer* pDecodedBuffer);
 
 class VideoEditorVideoDecoderSource : public MediaSource {
     public:
@@ -147,8 +149,41 @@
 
     Mutex::Autolock autolock(mLock);
     if (options != NULL) {
-        LOGE("Unexpected read options");
-        return BAD_VALUE;
+        int64_t time_us;
+        MediaSource::ReadOptions::SeekMode mode;
+        options->getSeekTo(&time_us, &mode);
+        if (mode != MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC) {
+            LOGE("Unexpected read options");
+            return BAD_VALUE;
+        }
+
+        M4OSA_ERR err;
+        M4OSA_Int32 rapTime = time_us / 1000;
+
+        /*--- Retrieve the previous RAP time ---*/
+        err = mpDecShellContext->m_pReaderGlobal->m_pFctGetPrevRapTime(
+                  mpDecShellContext->m_pReader->m_readerContext,
+                  (M4_StreamHandler*)mpDecShellContext->m_pVideoStreamhandler,
+                  &rapTime);
+
+        if (err == M4WAR_READER_INFORMATION_NOT_PRESENT) {
+            /* No RAP table, jump backward and predecode */
+            rapTime -= 40000;
+            if(rapTime < 0) rapTime = 0;
+        } else if (err != OK) {
+            LOGE("get rap time error = 0x%x\n", (uint32_t)err);
+            return UNKNOWN_ERROR;
+        }
+
+        err = mpDecShellContext->m_pReaderGlobal->m_pFctJump(
+                   mpDecShellContext->m_pReader->m_readerContext,
+                   (M4_StreamHandler*)mpDecShellContext->m_pVideoStreamhandler,
+                   &rapTime);
+
+        if (err != OK) {
+            LOGE("jump err = 0x%x\n", (uint32_t)err);
+            return BAD_VALUE;
+        }
     }
 
     *buffer_out = NULL;
@@ -704,7 +739,7 @@
     success = meta->findInt32(kKeyHeight, &vHeight);
     VIDEOEDITOR_CHECK(TRUE == success, M4ERR_PARAMETER);
 
-    LOGD("vWidth = %d, vHeight = %d", vWidth, vHeight);
+    LOGV("vWidth = %d, vHeight = %d", vWidth, vHeight);
 
     pDecShellContext->mGivenWidth = vWidth;
     pDecShellContext->mGivenHeight = vHeight;
@@ -717,12 +752,9 @@
         cropBottom = vHeight - 1;
 
         LOGV("got dimensions only %d x %d", width, height);
-        LOGD("got dimensions only %d x %d", width, height);
     } else {
         LOGV("got crop rect %d, %d, %d, %d",
              cropLeft, cropTop, cropRight, cropBottom);
-        LOGD("got crop rect %d, %d, %d, %d",
-             cropLeft, cropTop, cropRight, cropBottom);
     }
 
     pDecShellContext->mCropRect.left = cropLeft;
@@ -819,6 +851,7 @@
 
 M4OSA_ERR VideoEditorVideoDecoder_create(M4OSA_Context *pContext,
         M4_StreamHandler *pStreamHandler,
+        M4READER_GlobalInterface *pReaderGlobalInterface,
         M4READER_DataInterface *pReaderDataInterface,
         M4_AccessUnit *pAccessUnit, M4OSA_Void *pUserData) {
     M4OSA_ERR err = M4NO_ERROR;
@@ -842,6 +875,7 @@
     pDecShellContext->m_pVideoStreamhandler =
         (M4_VideoStreamHandler*)pStreamHandler;
     pDecShellContext->m_pNextAccessUnitToDecode = pAccessUnit;
+    pDecShellContext->m_pReaderGlobal = pReaderGlobalInterface;
     pDecShellContext->m_pReader = pReaderDataInterface;
     pDecShellContext->m_lastDecodedCTS = -1;
     pDecShellContext->m_lastRenderCts = -1;
@@ -980,6 +1014,7 @@
 
 M4OSA_ERR VideoEditorVideoSoftwareDecoder_create(M4OSA_Context *pContext,
         M4_StreamHandler *pStreamHandler,
+        M4READER_GlobalInterface *pReaderGlobalInterface,
         M4READER_DataInterface *pReaderDataInterface,
         M4_AccessUnit *pAccessUnit, M4OSA_Void *pUserData) {
     M4OSA_ERR err = M4NO_ERROR;
@@ -1002,6 +1037,7 @@
     pDecShellContext->m_pVideoStreamhandler =
         (M4_VideoStreamHandler*)pStreamHandler;
     pDecShellContext->m_pNextAccessUnitToDecode = pAccessUnit;
+    pDecShellContext->m_pReaderGlobal = pReaderGlobalInterface;
     pDecShellContext->m_pReader = pReaderDataInterface;
     pDecShellContext->m_lastDecodedCTS = -1;
     pDecShellContext->m_lastRenderCts = -1;
@@ -1229,15 +1265,15 @@
 }
 
 M4OSA_ERR VideoEditorVideoDecoder_decode(M4OSA_Context context,
-        M4_MediaTime* pTime, M4OSA_Bool bJump) {
+        M4_MediaTime* pTime, M4OSA_Bool bJump, M4OSA_UInt32 tolerance) {
     M4OSA_ERR lerr = M4NO_ERROR;
     VideoEditorVideoDecoder_Context* pDecShellContext =
         (VideoEditorVideoDecoder_Context*) context;
     int64_t lFrameTime;
-    VIDEOEDITOR_BUFFER_Buffer* tmpDecBuffer;
     MediaBuffer* pDecoderBuffer = NULL;
+    MediaBuffer* pNextBuffer = NULL;
     status_t errStatus;
-
+    bool needSeek = bJump;
 
     LOGV("VideoEditorVideoDecoder_decode begin");
 
@@ -1264,37 +1300,33 @@
     }
     pDecShellContext->mLastInputCts = *pTime;
 
-    while (pDecShellContext->m_lastDecodedCTS < *pTime) {
+    while (pDecoderBuffer == NULL || pDecShellContext->m_lastDecodedCTS + tolerance < *pTime) {
         LOGV("VideoEditorVideoDecoder_decode, frameCTS = %lf, DecodeUpTo = %lf",
             pDecShellContext->m_lastDecodedCTS, *pTime);
-        lerr = VIDEOEDITOR_BUFFER_getBuffer(pDecShellContext->m_pDecBufferPool,
-            VIDEOEDITOR_BUFFER_kEmpty, &tmpDecBuffer);
-        if (lerr == (M4OSA_UInt32)M4ERR_NO_BUFFER_AVAILABLE) {
-            lerr = VIDEOEDITOR_BUFFER_getOldestBuffer(
-                pDecShellContext->m_pDecBufferPool,
-                VIDEOEDITOR_BUFFER_kFilled, &tmpDecBuffer);
-            tmpDecBuffer->state = VIDEOEDITOR_BUFFER_kEmpty;
-            lerr = M4NO_ERROR;
+
+        // Read the buffer from the stagefright decoder
+        if (needSeek) {
+            MediaSource::ReadOptions options;
+            int64_t time_us = *pTime * 1000;
+            options.setSeekTo(time_us, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+            errStatus = pDecShellContext->mVideoDecoder->read(&pNextBuffer, &options);
+            needSeek = false;
+        } else {
+            errStatus = pDecShellContext->mVideoDecoder->read(&pNextBuffer);
         }
 
-        if (lerr != M4NO_ERROR) {
-            goto VIDEOEDITOR_VideoDecode_cleanUP;
-        }
-
-        if (pDecoderBuffer != NULL) {
-            pDecoderBuffer->release();
-            pDecoderBuffer = NULL;
-        }
-
-        errStatus = pDecShellContext->mVideoDecoder->read(&pDecoderBuffer);
+        // Handle EOS and format change
         if (errStatus == ERROR_END_OF_STREAM) {
             LOGV("End of stream reached, returning M4WAR_NO_MORE_AU ");
             pDecShellContext->mReachedEOS = M4OSA_TRUE;
             lerr = M4WAR_NO_MORE_AU;
+            // If we decoded a buffer before EOS, we still need to put it
+            // into the queue.
+            if (pDecoderBuffer && bJump) {
+                copyBufferToQueue(pDecShellContext, pDecoderBuffer);
+            }
             goto VIDEOEDITOR_VideoDecode_cleanUP;
-        } else if ( INFO_FORMAT_CHANGED == errStatus ) {
-            LOGV("VideoDecoder_decode:source returns INFO_FORMAT_CHANGED:TODO");
-
+        } else if (INFO_FORMAT_CHANGED == errStatus) {
             LOGV("VideoDecoder_decode : source returns INFO_FORMAT_CHANGED");
             lerr = VideoEditorVideoDecoder_configureFromMetadata(
                 pDecShellContext,
@@ -1307,136 +1339,36 @@
             continue;
         }
 
-        if( 0 < pDecoderBuffer->range_length() ) {
-        LOGV("VIDEOEDITOR_VideoDecoder frame buffer offset = %d, size = %d",
-            pDecoderBuffer->range_offset(),
-            pDecoderBuffer->range_length());
+        // Now we have a good next buffer, release the previous one.
+        if (pDecoderBuffer != NULL) {
+            pDecoderBuffer->release();
+            pDecoderBuffer = NULL;
+        }
+        pDecoderBuffer = pNextBuffer;
 
+        // Record the timestamp of last decoded buffer
         pDecoderBuffer->meta_data()->findInt64(kKeyTime, &lFrameTime);
         pDecShellContext->m_lastDecodedCTS = (M4_MediaTime)(lFrameTime/1000);
         LOGV("VideoEditorVideoDecoder_decode,decoded frametime = %lf,size = %d",
             (M4_MediaTime)lFrameTime, pDecoderBuffer->size() );
 
-        switch ( pDecShellContext->decOuputColorFormat ) {
-            case OMX_QCOM_COLOR_FormatYVU420SemiPlanar: {
-                M4VIFI_ImagePlane tmpPlane[3];
-                // Prepare the output image for conversion
-                if( pDecoderBuffer->range_length() != (
-                    pDecShellContext->m_pVideoStreamhandler->m_videoWidth *
-                    pDecShellContext->m_pVideoStreamhandler->m_videoHeight \
-                     * 3)/2 ) {
-                    LOGV("VideoEditorVideoDecoder_decod invalid frame size S=%d"
-                        "W=%d H=%d", pDecoderBuffer->range_length(),
-                        pDecShellContext->m_pVideoStreamhandler->m_videoWidth,
-                        pDecShellContext->m_pVideoStreamhandler->m_videoHeight);
-                    lerr = M4ERR_PARAMETER;
-                    goto VIDEOEDITOR_VideoDecode_cleanUP;
-                }
-                tmpPlane[0].u_width   =
-                    pDecShellContext->m_pVideoStreamhandler->m_videoWidth;
-                tmpPlane[0].u_height  =
-                    pDecShellContext->m_pVideoStreamhandler->m_videoHeight;
-                tmpPlane[0].u_topleft = 0;
-                tmpPlane[0].u_stride  = tmpPlane[0].u_width;
-                tmpPlane[0].pac_data  = (M4VIFI_UInt8*)tmpDecBuffer->pData;
-                tmpPlane[1].u_width   = tmpPlane[0].u_width/2;
-                tmpPlane[1].u_height  = tmpPlane[0].u_height/2;
-                tmpPlane[1].u_topleft = 0;
-                tmpPlane[1].u_stride  = tmpPlane[0].u_stride/2;
-                tmpPlane[1].pac_data  = tmpPlane[0].pac_data +
-                    (tmpPlane[0].u_stride * tmpPlane[0].u_height);
-                tmpPlane[2].u_width   = tmpPlane[1].u_width;
-                tmpPlane[2].u_height  = tmpPlane[1].u_height;
-                tmpPlane[2].u_topleft = 0;
-                tmpPlane[2].u_stride  = tmpPlane[1].u_stride;
-                tmpPlane[2].pac_data  = tmpPlane[1].pac_data +
-                    (tmpPlane[1].u_stride * tmpPlane[1].u_height);
-                M4VIFI_SemiplanarYVU420toYUV420(M4OSA_NULL,
-                    (M4VIFI_UInt8 *)pDecoderBuffer->data() + \
-                    pDecoderBuffer->range_offset(), &tmpPlane[0]);
-                break;
+        // If bJump is false, we need to save every decoded buffer
+        if (!bJump) {
+            lerr = copyBufferToQueue(pDecShellContext, pDecoderBuffer);
+            if (lerr != M4NO_ERROR) {
+                goto VIDEOEDITOR_VideoDecode_cleanUP;
             }
-            case OMX_COLOR_FormatYUV420Planar:
-            {
-                int32_t width = pDecShellContext->m_pVideoStreamhandler->m_videoWidth;
-                int32_t height = pDecShellContext->m_pVideoStreamhandler->m_videoHeight;
-                int32_t yPlaneSize = width * height;
-                int32_t uvPlaneSize = width * height / 4;
-                int32_t offsetSrc = 0;
-
-                if (( width == pDecShellContext->mGivenWidth )  &&
-                    ( height == pDecShellContext->mGivenHeight ))
-                {
-                    M4OSA_MemAddr8 pTmpBuff = (M4OSA_MemAddr8)pDecoderBuffer->data() + pDecoderBuffer->range_offset();
-
-                    memcpy((void *)tmpDecBuffer->pData, (void *)pTmpBuff, yPlaneSize);
-
-                    offsetSrc += pDecShellContext->mGivenWidth * pDecShellContext->mGivenHeight;
-                    memcpy((void *)((M4OSA_MemAddr8)tmpDecBuffer->pData + yPlaneSize),
-                        (void *)(pTmpBuff + offsetSrc), uvPlaneSize);
-
-                    offsetSrc += (pDecShellContext->mGivenWidth >> 1) * (pDecShellContext->mGivenHeight >> 1);
-                    memcpy((void *)((M4OSA_MemAddr8)tmpDecBuffer->pData + yPlaneSize + uvPlaneSize),
-                        (void *)(pTmpBuff + offsetSrc), uvPlaneSize);
-                }
-                else
-                {
-                    M4OSA_MemAddr8 pTmpBuff = (M4OSA_MemAddr8)pDecoderBuffer->data() + pDecoderBuffer->range_offset();
-                    M4OSA_MemAddr8 pTmpBuffDst = (M4OSA_MemAddr8)tmpDecBuffer->pData;
-                    int32_t index;
-
-                    for ( index = 0; index < height; index++)
-                    {
-                        memcpy((void *)pTmpBuffDst, (void *)pTmpBuff, width);
-                        pTmpBuffDst += width;
-                        pTmpBuff += pDecShellContext->mGivenWidth;
-                    }
-
-                    pTmpBuff += (pDecShellContext->mGivenWidth * ( pDecShellContext->mGivenHeight - height));
-                    for ( index = 0; index < height >> 1; index++)
-                    {
-                        memcpy((void *)pTmpBuffDst, (void *)pTmpBuff, width >> 1);
-                        pTmpBuffDst += width >> 1;
-                        pTmpBuff += pDecShellContext->mGivenWidth >> 1;
-                    }
-
-                    pTmpBuff += ((pDecShellContext->mGivenWidth * (pDecShellContext->mGivenHeight - height)) / 4);
-                    for ( index = 0; index < height >> 1; index++)
-                    {
-                        memcpy((void *)pTmpBuffDst, (void *)pTmpBuff, width >> 1);
-                        pTmpBuffDst += width >> 1;
-                        pTmpBuff += pDecShellContext->mGivenWidth >> 1;
-                    }
-                }
-
-                break;
-            }
-            default:
-                if (pDecShellContext->mI420ColorConverter) {
-                    if (pDecShellContext->mI420ColorConverter->convertDecoderOutputToI420(
-                        (uint8_t *)pDecoderBuffer->data(),// ?? + pDecoderBuffer->range_offset(),   // decoderBits
-                        pDecShellContext->mGivenWidth,  // decoderWidth
-                        pDecShellContext->mGivenHeight,  // decoderHeight
-                        pDecShellContext->mCropRect,  // decoderRect
-                        tmpDecBuffer->pData /* dstBits */) < 0) {
-                        LOGE("convertDecoderOutputToI420 failed");
-                    }
-                } else {
-                    LOGW("VideoDecoder_decode: unexpected color format 0x%X",
-                        pDecShellContext->decOuputColorFormat);
-                    lerr = M4ERR_PARAMETER;
-                    goto VIDEOEDITOR_VideoDecode_cleanUP;
-                }
-        }
-
-        tmpDecBuffer->buffCTS = pDecShellContext->m_lastDecodedCTS;
-        tmpDecBuffer->state = VIDEOEDITOR_BUFFER_kFilled;
-        tmpDecBuffer->size = pDecoderBuffer->size();
-
-        } else {
-            LOGV("VideoEditorVideoDecoder_decode : empty buffer was returned");
         }
     }
+
+    // If bJump is true, we only need to copy the last buffer
+    if (bJump) {
+        lerr = copyBufferToQueue(pDecShellContext, pDecoderBuffer);
+        if (lerr != M4NO_ERROR) {
+            goto VIDEOEDITOR_VideoDecode_cleanUP;
+        }
+    }
+
     pDecShellContext->mNbOutputFrames++;
     if ( 0 > pDecShellContext->mFirstOutputCts ) {
         pDecShellContext->mFirstOutputCts = *pTime;
@@ -1454,6 +1386,101 @@
     return lerr;
 }
 
+static M4OSA_ERR copyBufferToQueue(
+    VideoEditorVideoDecoder_Context* pDecShellContext,
+    MediaBuffer* pDecoderBuffer) {
+
+    M4OSA_ERR lerr = M4NO_ERROR;
+    VIDEOEDITOR_BUFFER_Buffer* tmpDecBuffer;
+
+    // Get a buffer from the queue
+    lerr = VIDEOEDITOR_BUFFER_getBuffer(pDecShellContext->m_pDecBufferPool,
+        VIDEOEDITOR_BUFFER_kEmpty, &tmpDecBuffer);
+    if (lerr == (M4OSA_UInt32)M4ERR_NO_BUFFER_AVAILABLE) {
+        lerr = VIDEOEDITOR_BUFFER_getOldestBuffer(
+            pDecShellContext->m_pDecBufferPool,
+            VIDEOEDITOR_BUFFER_kFilled, &tmpDecBuffer);
+        tmpDecBuffer->state = VIDEOEDITOR_BUFFER_kEmpty;
+        lerr = M4NO_ERROR;
+    }
+
+    if (lerr != M4NO_ERROR) return lerr;
+
+    // Color convert or copy from the given MediaBuffer to our buffer
+    if (pDecShellContext->mI420ColorConverter) {
+        if (pDecShellContext->mI420ColorConverter->convertDecoderOutputToI420(
+            (uint8_t *)pDecoderBuffer->data(),// ?? + pDecoderBuffer->range_offset(),   // decoderBits
+            pDecShellContext->mGivenWidth,  // decoderWidth
+            pDecShellContext->mGivenHeight,  // decoderHeight
+            pDecShellContext->mCropRect,  // decoderRect
+            tmpDecBuffer->pData /* dstBits */) < 0) {
+            LOGE("convertDecoderOutputToI420 failed");
+            lerr = M4ERR_NOT_IMPLEMENTED;
+        }
+    } else if (pDecShellContext->decOuputColorFormat == OMX_COLOR_FormatYUV420Planar) {
+        int32_t width = pDecShellContext->m_pVideoStreamhandler->m_videoWidth;
+        int32_t height = pDecShellContext->m_pVideoStreamhandler->m_videoHeight;
+        int32_t yPlaneSize = width * height;
+        int32_t uvPlaneSize = width * height / 4;
+        int32_t offsetSrc = 0;
+
+        if (( width == pDecShellContext->mGivenWidth )  &&
+            ( height == pDecShellContext->mGivenHeight ))
+        {
+            M4OSA_MemAddr8 pTmpBuff = (M4OSA_MemAddr8)pDecoderBuffer->data() + pDecoderBuffer->range_offset();
+
+            memcpy((void *)tmpDecBuffer->pData, (void *)pTmpBuff, yPlaneSize);
+
+            offsetSrc += pDecShellContext->mGivenWidth * pDecShellContext->mGivenHeight;
+            memcpy((void *)((M4OSA_MemAddr8)tmpDecBuffer->pData + yPlaneSize),
+                (void *)(pTmpBuff + offsetSrc), uvPlaneSize);
+
+            offsetSrc += (pDecShellContext->mGivenWidth >> 1) * (pDecShellContext->mGivenHeight >> 1);
+            memcpy((void *)((M4OSA_MemAddr8)tmpDecBuffer->pData + yPlaneSize + uvPlaneSize),
+                (void *)(pTmpBuff + offsetSrc), uvPlaneSize);
+        }
+        else
+        {
+            M4OSA_MemAddr8 pTmpBuff = (M4OSA_MemAddr8)pDecoderBuffer->data() + pDecoderBuffer->range_offset();
+            M4OSA_MemAddr8 pTmpBuffDst = (M4OSA_MemAddr8)tmpDecBuffer->pData;
+            int32_t index;
+
+            for ( index = 0; index < height; index++)
+            {
+                memcpy((void *)pTmpBuffDst, (void *)pTmpBuff, width);
+                pTmpBuffDst += width;
+                pTmpBuff += pDecShellContext->mGivenWidth;
+            }
+
+            pTmpBuff += (pDecShellContext->mGivenWidth * ( pDecShellContext->mGivenHeight - height));
+            for ( index = 0; index < height >> 1; index++)
+            {
+                memcpy((void *)pTmpBuffDst, (void *)pTmpBuff, width >> 1);
+                pTmpBuffDst += width >> 1;
+                pTmpBuff += pDecShellContext->mGivenWidth >> 1;
+            }
+
+            pTmpBuff += ((pDecShellContext->mGivenWidth * (pDecShellContext->mGivenHeight - height)) / 4);
+            for ( index = 0; index < height >> 1; index++)
+            {
+                memcpy((void *)pTmpBuffDst, (void *)pTmpBuff, width >> 1);
+                pTmpBuffDst += width >> 1;
+                pTmpBuff += pDecShellContext->mGivenWidth >> 1;
+            }
+        }
+    } else {
+        LOGE("VideoDecoder_decode: unexpected color format 0x%X",
+            pDecShellContext->decOuputColorFormat);
+        lerr = M4ERR_PARAMETER;
+    }
+
+    tmpDecBuffer->buffCTS = pDecShellContext->m_lastDecodedCTS;
+    tmpDecBuffer->state = VIDEOEDITOR_BUFFER_kFilled;
+    tmpDecBuffer->size = pDecoderBuffer->size();
+
+    return lerr;
+}
+
 M4OSA_ERR VideoEditorVideoDecoder_render(M4OSA_Context context,
         M4_MediaTime* pTime, M4VIFI_ImagePlane* pOutputPlane,
         M4OSA_Bool bForceRender) {