videoeditorengine/h263decoder/src/vdeti.cpp
author Mikael Laine <mikael.laine@ixonos.com>
Fri, 29 Jan 2010 14:08:33 +0200
changeset 0 951a5db380a0
permissions -rw-r--r--
Committing the Video Editor package under the Eclipse Public License

/*
* 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