videoeditorengine/h263decoder/src/vdeti.cpp
changeset 0 951a5db380a0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/videoeditorengine/h263decoder/src/vdeti.cpp	Fri Jan 29 14:08:33 2010 +0200
@@ -0,0 +1,445 @@
+/*
+* Copyright (c) 2010 Ixonos Plc.
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - Initial contribution
+*
+* Contributors:
+* Ixonos Plc
+*
+* Description:  
+* Frame decoding function.
+*
+*/
+
+
+
+/*
+ * Includes
+ */
+
+#include "h263dconfig.h"
+#include "vdeti.h"
+#include "debug.h"
+#include "sync.h"
+#include "vde.h"
+#include "vdemain.h"
+#include "core.h"
+/* MVE */
+#include "MPEG4Transcoder.h"
+
+/*
+ * Local function prototype
+ */
+
+static int vdeSeekNextValidDecodingStartPosition(
+   vdeInstance_t *instance, CMPEG4Transcoder *hTranscoder);
+
+
+/*
+ * Functions visible outside this module
+ */
+
+/* {{-output"vdeDecodeFrame.txt"}} */
+/*
+ * vdeDecodeFrame
+ *
+ * Parameters:
+ *    hInstance                  instance data
+ *
+ * Function:
+ *    This function decodes the bitstream by using
+ *    vdcDecodeFrame until it gets at least one decoded frame. It also shows 
+ *    the resulting frames (by calling renDraw). 
+ *    In addition, the function handles the parameter updating synchronization
+ *    by calling the VDE Queue module.
+ *
+ *    This function is intended to be called from the thread main function.
+ *    It won't return until it gets a new decoded frame. If the bitstream
+ *    is totally corrupted, this feature might cause a considerable delay
+ *    in the execution of the thread main function.
+ *
+ * Returns:
+ *    VDE_OK                     if the function was successful
+ *    VDE_OK_EOS                 if the end of stream has been reached
+ *    VDE_OK_BUT_FRAME_USELESS   if the function behaved normally, but no 
+ *                               decoding output was produced due to too
+ *                               corrupted input frame
+ *    VDE_ERROR                  if a fatal error, from which the decoder
+ *                               cannot be restored, has occured
+ *    VDE_ERROR_HALTED           the instance is halted, it should be closed
+ *
+ *    
+ */
+
+
+int vdeDecodeFrame(vdeHInstance_t hInstance, int /*aStartByteIndex*/, int /*aStartBitIndex*/, CMPEG4Transcoder *hTranscoder)
+/* {{-output"vdeDecodeFrame.txt"}} */
+{
+   int
+      sncCode,                   /* sync code from which to start decoding */
+      numOutputFrames,           /* number of output frames, 2 for PB-frames,
+                                    1 otherwise */
+      fOutputUseless,            /* 1 if frame(s) too corrupted to display,
+                                    0 otherwise */
+      i,                         /* loop variable */
+      vdcStatus,                 /* return value of vdcDecodeFrame or 
+                                    vdcDecodeMPEGVop */
+      fFullPictureFreeze = 0;    /* set to 1 if full-picture freeze is
+                                    going on as described in section L.4
+                                    of the H.263 recommendation */
+
+   vdeInstance_t 
+      *instance = (vdeInstance_t *) hInstance;
+                                 /* pointer to instance structure */
+
+    /* MVE */
+     int StartByteIndex ;
+     int StartBitIndex ;
+
+   instance->fPrevFrameDecoded = 0;
+
+   /* If the instance is in the EOS state */
+   if (instance->state == VDE_STATE_EOS) {
+
+      /* If MPEG-4 stream, visual_object_sequence_end_code terminates
+         a visual session, and therefore we return.
+         If H.263 stream, EOS (End of Sequence) has no semantics, and
+         therefore we return only if MoVi buffers wrapper indicates so. */
+      if (instance->fMPEG4)
+         /* Return an indication that the stream has ended */
+         return VDE_OK_EOS;
+   }
+
+   /* If the instance is in the "Halted" state */
+   if (instance->state == VDE_STATE_HALTED) {
+
+      /* If the current frame is INTRA */
+      if (vdcIsINTRA(instance->vdcHInstance, instance->inBuffer->baseAddr, 20)) {
+         /* Reset the state and try to decode */
+         instance->state = VDE_STATE_MIDDLE;
+         deb("vdeDecodeFrame: Trying to recover from halted state.\n");
+      }
+
+      else {
+         deb("vdeDecodeFrame: ERROR - already halted.\n");
+         /* Return an indication that the stream cannot be decoded further */
+         return VDE_ERROR_HALTED;
+      }
+   }
+
+   /* If the instance state indicates that we should resynchronize to INTRA
+      frame */
+   if (instance->state == VDE_STATE_RESYNC) {
+
+      /* If the current frame is INTRA */
+      if (vdcIsINTRA(instance->vdcHInstance, instance->inBuffer->baseAddr, 20)) {
+         /* Reset the state and continue decoding */
+         instance->state = VDE_STATE_MIDDLE;
+      }
+
+      else
+         return VDE_OK;
+   }
+
+   /* Read a synchronization code from the current position of the 
+   bitstream or seek the next valid sync code to start decoding */
+   sncCode = vdeSeekNextValidDecodingStartPosition(instance, hTranscoder);
+
+   /* If error in seeking sync code */
+   if (sncCode < 0)
+      /* Return error */
+      return sncCode;
+
+   /* Else if sync code not found 
+      Note: Can only happen in "one frame per one input bit buffer" case, 
+      i.e. not in videophone */
+   else if (sncCode == SNC_NO_SYNC)
+      /* Note: One could send a INTRA picture request if such a service is
+         available. However, it is assumed that the service is not available
+         in this non-videophone application, and therefore no update is
+         requested. */
+
+      /* Return indication of useless (too corrupted) frame */
+      return VDE_OK_BUT_FRAME_USELESS;
+
+   /* Set the instance to the "Middle" state */
+   instance->state = VDE_STATE_MIDDLE;
+
+   /* If the synchronization code == EOS */
+   if (sncCode == SNC_EOS) {
+
+      /* Set the instance to the EOS state */
+      instance->state = VDE_STATE_EOS;
+
+      /* Return an indication that the stream ended */
+      return VDE_OK_EOS;
+   }
+      
+   /* MVE */
+     StartByteIndex = instance->inBuffer->getIndex;
+     StartBitIndex  = instance->inBuffer->bitIndex;
+
+
+
+
+   /* Decode a frame */
+
+   if (instance->fMPEG4) {
+
+      vdcStatus = vdcDecodeMPEGVop(instance->vdcHInstance, instance->inBuffer,
+          instance->outBuffer, instance->bufEdit, instance->iColorEffect, instance->iGetDecodedFrame,
+          StartByteIndex, StartBitIndex, hTranscoder);
+   } 
+   else 
+   {
+
+
+       vdcStatus = vdcDecodeFrame(instance->vdcHInstance, instance->inBuffer, 
+           instance->outBuffer, instance->bufEdit, instance->iColorEffect,instance->iGetDecodedFrame, hTranscoder);
+
+   }
+
+
+   if (vdcStatus < 0) {
+      deb("vdeDecodeFrame: ERROR - vdcDecodeFrame failed.\n");
+
+      instance->state = VDE_STATE_HALTED;
+
+      if (vdcStatus == VDC_ERR_NO_INTRA)
+          return VDE_ERROR_NO_INTRA;
+      
+      return VDE_ERROR_HALTED;
+   }
+
+   /* If EOS occured */
+   if (vdcIsEOSReached(instance->vdcHInstance))
+      instance->state = VDE_STATE_EOS;
+
+   /* If the decoded frame is totally corrupted */
+   if ((vdcStatus == VDC_OK_BUT_FRAME_USELESS) || (vdcStatus == VDC_OK_BUT_NOT_CODED)) {
+
+      /* If continuous input buffer */
+
+      fOutputUseless = 1;
+   }
+
+   else {
+      fOutputUseless = 0;
+      instance->fPrevFrameDecoded = 1;
+   }
+
+
+   /* If H.263 bitstream and decoding (partially) successful */
+   if (!instance->fMPEG4 && !fOutputUseless) {
+   }
+
+   /*
+    * Return decoded images to the image store and 
+    * send them to Video Renderer if needed
+    */
+
+   numOutputFrames = vdcGetNumberOfOutputFrames(instance->vdcHInstance);
+
+   /* Loop to handle each output frame separately */
+   for (i = 0; i < numOutputFrames; i++) {
+      vdeImsItem_t *imsItem;
+
+      imsItem = vdcGetImsItem(instance->vdcHInstance, i);
+
+      vdeAssert(imsItem);
+
+      /* If the frame is useless */
+      if (fOutputUseless) {
+
+         /* Return the image buffer to the "Free" store */
+         if (vdeImsPutFree(&instance->imageStore, imsItem) < 0) {
+           deb("vdeDecodeFrame: ERROR - vdeImsPutFree failed.\n");
+           instance->state = VDE_STATE_HALTED;
+           return VDE_ERROR_HALTED;
+         }
+      }
+
+      /* Else the frame is ok */
+      else {
+
+         vdeImb_t *imb;
+
+         vdeImsStoreItemToImageBuffer(imsItem, &imb);
+
+
+         /* If full-picture freeze requested */
+         if (fFullPictureFreeze) {
+
+            /* Return the image buffer to the image buffer store
+               but don't send it to the renderer */
+            if (vdeImsPut(&instance->imageStore, imsItem) < 0) {
+               deb("vdeDecodeFrame: ERROR - vdeImsPut failed.\n");
+               instance->state = VDE_STATE_HALTED;
+               return VDE_ERROR_HALTED;
+            }
+         }
+
+         /* Else normal displaying */
+         else {
+            h263dFrameType_t frameType;
+            int renStatus;
+            u_int32 renHandle;
+
+            /* Get renderer for the output frame */
+            frameType.scope = H263D_FTYPE_NDEF;
+            frameType.width = renDriBitmapWidth(imb->drawItem);
+            frameType.height = renDriBitmapHeight(imb->drawItem);
+       
+            renStatus = vdeFrtGetItem(&instance->renStore, &frameType, &renHandle);
+
+            if (renStatus == VDE_OK_NOT_AVAILABLE)
+               renHandle = 0;
+
+
+            if (renStatus >= 0) {
+               /* Return the image buffer to the image buffer store
+                  and send it to the renderer (if possible) */
+               if (vdeImsPut(&instance->imageStore, imsItem) < 0) {
+                  deb("vdeDecodeFrame: ERROR - vdeImsPut failed.\n");
+                  instance->state = VDE_STATE_HALTED;
+                  return VDE_ERROR_HALTED;
+               }
+            }
+
+            else {
+               deb("vdeDecodeFrame: ERROR - vdeFrtGetItem failed.\n");
+               instance->state = VDE_STATE_HALTED;
+               return VDE_ERROR_HALTED;
+            }
+         }
+
+      }
+   }
+   
+   // fatal errors were returned already earlier
+   switch ( vdcStatus )
+    {
+    case VDC_OK_BUT_FRAME_USELESS:
+        {
+        return VDE_OK_BUT_FRAME_USELESS;
+        }
+//        break;
+    case VDC_OK_BUT_NOT_CODED:
+        {
+        return VDE_OK_BUT_NOT_CODED;
+        }
+//        break;
+    default:
+      {
+        break;
+//      return VDE_OK;
+      }
+    }
+    
+return VDE_OK;
+}
+
+
+/*
+ * Local functions
+ */
+
+/*
+ * vdeSeekNextValidDecodingStartPosition
+ *
+ * Parameters:
+ *    instance                   instance data
+ *
+ * Function:
+ *    This function seeks the next synchronization position from the bitstream
+ *    (starting from the current position) from which the decoder can start
+ *    decoding.
+ *
+ * Returns:
+ *    VDE_ERROR                  if a fatal error, from which the decoder
+ *                               cannot be restored, has occured
+ *
+ *    SNC_NO_SYNC                if no suitable sync code was found
+ *                               (can happen only in non-videophone case
+ *                               where only one frame is in one bit input
+ *                               buffer)
+ *
+ *    SNC_PSC                    H.263 Picture Start Code found
+ *
+ *    SNC_EOS                    H.263 End of Sequence found or
+ *                               MPEG-4 EOB found
+ *
+ *    SNC_GBSC                   H.263 GBSC found
+ *
+ *    SNC_VOP                    MPEG-4 VOP
+ *    SNC_GOV                    MPEG-4 GOV
+ *
+ *    
+ */
+
+static int vdeSeekNextValidDecodingStartPosition(
+   vdeInstance_t *instance, CMPEG4Transcoder *hTranscoder)
+{
+   int
+      sncCode = SNC_NO_SYNC;  /* sync code in current position */
+   int16 
+      error = 0;              /* error code returned from sync module */
+
+   /* Note: For the first INTRA of the stream,
+   do the H.263 vs. non-H.263 stream decision in a higher level,
+   now assume that there has simply been a bit error in the header,
+   and one should try from the next PSC */
+
+   if (instance->fMPEG4) {
+      vdcInstance_t* vdcinst = (vdcInstance_t *) instance->vdcHInstance;
+      int fcode = vdcinst->pictureParam.fcode_forward;
+
+      while (sncCode != SNC_VOP && 
+             sncCode != SNC_GOV && 
+             sncCode != SNC_EOB &&
+             sncCode != SNC_VIDPACK) {
+
+         sncCode = sncSeekMPEGStartCode(instance->inBuffer, (fcode ? fcode : 1), 1 /* VPs not relevant at this stage */, 0, &error);
+         if (error == ERR_BIB_NOT_ENOUGH_DATA)
+            return SNC_NO_SYNC;
+         else if (error)
+            return VDE_ERROR;
+         else if (sncCode == SNC_VOS)
+         {            
+            /* Visual Object Sequence start code found, VOS + VO + VOL headers have to be parsed now.. */
+            /* (The bitstream may contain multiple instances of VOS start codes before Visual
+                Object Sequence end code) */
+            if (vdcDecodeMPEGVolHeader(vdcinst, instance->inBuffer, hTranscoder) != 0)
+               return VDE_ERROR;
+         }
+      }
+
+      if (sncCode == SNC_EOB)
+         sncCode = SNC_EOS;
+   }
+   else 
+   {
+      while (
+         sncCode != SNC_PSC && 
+         sncCode != SNC_EOS &&
+         sncCode != SNC_GBSC ) {
+
+         sncCode = sncSeekSync(instance->inBuffer, &error);
+         if (error == ERR_BIB_NOT_ENOUGH_DATA)
+            return SNC_NO_SYNC;
+         else if (error)
+            return VDE_ERROR;
+      }
+   }
+
+   return sncCode;
+}
+
+
+// End of file