videoeditorengine/h263decoder/src/core.cpp
changeset 0 951a5db380a0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/videoeditorengine/h263decoder/src/core.cpp	Fri Jan 29 14:08:33 2010 +0200
@@ -0,0 +1,1357 @@
+/*
+* 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:  
+* H.263 decoder core functions.
+*
+*/
+
+
+/* 
+ * Includes 
+ */
+#include "h263dConfig.h"
+#include "vdc263.h"
+#include "core.h"
+#include "debug.h"
+#include "decblock.h" /* for dblFree and dblLoad */
+#include "decgob.h"
+#include "decpich.h"
+#include "h263dapi.h" /* for H263D_BC_MUX_MODE_SEPARATE_CHANNEL and H263D_ERD_ */
+#include "stckheap.h"
+#include "sync.h"
+#include "vdeims.h"
+#include "vdeimb.h"
+#include "viddemux.h"
+#include "biblin.h"
+#include "MPEG4Transcoder.h"
+
+
+/*
+ * Typedefs and structs
+ */
+
+/* This structure is used to indicate the expected decoding position. */
+typedef enum {
+   EDP_START_OF_FRAME,
+   EDP_START_OF_GOB_SEGMENT,
+   EDP_START_OF_SLICE_SEGMENT,
+   EDP_END_OF_FRAME
+} vdcExpectedDecodingPosition_t;
+
+
+/*
+ * Local function prototypes
+ */ 
+
+int vdcFillImageBuffers(
+   vdcInstance_t *instance,
+   int numOfCodedMBs,
+   vdeImb_t *imbP);
+
+
+/*
+ * Global functions
+ */
+
+/* {{-output"vdcClose.txt"}} */
+/*
+ * vdcClose
+ *    
+ *
+ * Parameters:
+ *    hInstance                  handle of instance data
+ *
+ * Function:
+ *    This function closes the instance. The function frees all the resources
+ *    allocated for the instance. The instance handle is no longer valid
+ *    after calling this function.
+ *
+ * Returns:
+ *    >= 0                       if the function was successful
+ *    < 0                        if an error occured
+ *
+ */
+
+int vdcClose(vdcHInstance_t hInstance)
+/* {{-output"vdcClose.txt"}} */
+{
+   vdcInstance_t *instance = (vdcInstance_t *) hInstance;
+   int retValue = VDC_OK;
+
+   if (instance == NULL)
+      return retValue;
+
+   mvcFree(&instance->mvcData);
+
+   if ( instance->prevPicHeader != NULL )
+      free( instance->prevPicHeader );
+
+   aicFree(&instance->aicData);
+
+              
+   if ( instance->user_data != NULL )
+      free( instance->user_data );
+
+
+   vdcDealloc(instance);
+
+   return retValue;
+}
+
+
+/* {{-output"vdcDecodeFrame.txt"}} */
+/*
+ * vdcDecodeFrame
+ *    
+ *
+ * Parameters:
+ *    hInstance                  handle of instance data
+ *
+ *    inBuffer                   pointer to bit buffer, the current position
+ *                               of the buffer must start with a PSC
+ *
+ * Function:
+ *    The vdcDecodeFrame function implements the decoding process described
+ *    in the H.263 recommendation (version 2). However, it does not support
+ *    the following features of the recommendation:
+ *       decoding using the H.261 standard (bit 2 in PTYPE),
+ *       source format changes during a video sequence.
+ *
+ *    The function decodes the next frame in
+ *    the buffer (inBuffer) meaning that the decoding continues until the next
+ *    PSC or EOS is found or until the end of the buffer is not reached.
+ *
+ * Returns:
+ *    VDC_OK                     if the function was succesful
+ *    VDC_OK_BUT_BIT_ERROR       if bit errors were detected but
+ *                               decoded frames are provided by concealing
+ *                               the errors
+ *    VDC_OK_BUT_FRAME_USELESS   if severe bit errors were detected
+ *                               (no concealment was possible) or
+ *                               the bitstream ended unexpectedly
+ *    VDC_ERR                    if a processing error occured,
+ *                               the instance should be closed
+ *
+ */
+
+
+int vdcDecodeFrame(vdcHInstance_t hInstance, bibBuffer_t *inBuffer, bibBuffer_t *outBuffer,
+                   bibBufferEdit_t *bufEdit, int aColorEffect, TBool aGetDecodedFrame,
+                   CMPEG4Transcoder *hTranscoder)
+
+/* {{-output"vdcDecodeFrame.txt"}} */
+{
+   int prevGN = -1;           /* GOB number of the latest decoded GOB */
+   int prevGNWithHeader = -1; /* GOB number of the latest decoded GOB with
+                                 a GOB header */
+
+   int numStuffBits;          /* Number of stuffing bits before the sync code */
+
+   int sncCode;               /* the latest synchronization code, see 
+                                 sncCheckSync for the possible values */
+
+   int rtr = -1;              /* reference tr, 0.. */
+   int trp = -1;              /* tr for prediction, -1 if not indicated in 
+                                 the bitstream */
+
+   int retValue = VDC_OK;     /* return value of this function */
+
+
+   int16 error = 0;           /* Used to pass error codes from the sync module */
+
+   u_char
+      *currYFrame = NULL,     /* current P frame */
+      *currUFrame = NULL,
+      *currVFrame = NULL,
+      *refYFrame = NULL,      /* reference frame */
+      *refUFrame = NULL,
+      *refVFrame = NULL;
+
+   u_char *fCodedMBs = NULL;  /* Pointer to table, which indicates coded \
+                                 macroblocks by non-zero value */
+   int numOfCodedMBs = 0;     /* The number of coded macroblocks */
+
+   int *quantParams = NULL;   /* Pointer to table, in which the quantization
+                                 parameter for each macroblock is stored */
+
+   int decStatus = 0;         /* Decoding status, returned from decgob.c */
+   int corruptedSegments = 0; /* counter for corrupted segments */
+   int decodedSegments = 0;   /* counter for decoded segments (used in slice mode) */
+   int headerSuccess = 0;     /* success of picture header */
+   int numDecodedMBs = 0;     /* Total number of decoded MBs */
+   int numMBsInFrame = 0;     /* Number of MBs in frame */
+
+
+   vdcExpectedDecodingPosition_t expectedDecodingPosition;
+                              /* Tells in which part of the bitstream
+                                 the decoding should be */
+
+   vdcInstance_t *instance = (vdcInstance_t *) hInstance;
+                              /* instance data */
+      
+   vdcAssert(instance != NULL);
+
+   /* Initializations */
+
+   instance->currFrame = NULL;
+   expectedDecodingPosition = EDP_START_OF_FRAME;
+   instance->pictureParam.prevTR = instance->pictureParam.tr;
+
+   /* Main loop */
+   for (;;) {
+      int bitErrorIndication = 0;
+
+      sncCode = sncCheckSync(inBuffer, &numStuffBits, &error);
+
+      /* If sncCheckSync failed */
+      if (error && error != ERR_BIB_NOT_ENOUGH_DATA) {
+         deb1p("vdcDecodeFrame: ERROR - sncCheckSync returned %d.\n", error);
+         retValue = VDC_ERR;
+         goto exitFunction;
+      }
+
+      /* If EOS was got */
+      if (sncCode == SNC_EOS)
+         instance->fEOS = 1;
+
+      /* If frame ends appropriately */
+      if (expectedDecodingPosition == EDP_END_OF_FRAME &&
+         (sncCode == SNC_PSC || sncCode == SNC_EOS || 
+          sncCode == SNC_STUFFING || error == ERR_BIB_NOT_ENOUGH_DATA )) {
+         goto exitFunction;
+      }
+
+      /* Else if frame (or stream) data ends suddenly */
+      else if (error == ERR_BIB_NOT_ENOUGH_DATA) {
+         retValue = VDC_OK_BUT_BIT_ERROR;
+         goto exitFunction;
+      }
+
+      /* Else if EOS was reached */
+      else if (sncCode == SNC_EOS) {
+         /* The current frame is useless since it ends before it is complete.
+            On the other hand, there is no point in concealing it since
+            it is the last frame of the sequence. */
+         retValue = VDC_OK_BUT_FRAME_USELESS;
+         goto exitFunction;
+      }
+
+      /* Else if frame starts as expected */
+      else if (expectedDecodingPosition == EDP_START_OF_FRAME &&
+         sncCode == SNC_PSC) {
+
+         dphInParam_t pichIn;
+         dphInOutParam_t pichInOut;
+         dphOutParam_t pichOut;
+
+         pichIn.numStuffBits = numStuffBits;
+         pichIn.fNeedDecodedFrame = aGetDecodedFrame | hTranscoder->NeedDecodedYUVFrame();
+
+         pichIn.fReadBits = 1;
+         pichInOut.vdcInstance = instance;
+         pichInOut.inBuffer = inBuffer;
+
+         if ( instance->fRPS ) {
+            /* Store the previous TR for VRC needs */
+            if ( instance->nOfDecodedFrames > 0 )
+               trp = instance->pictureParam.tr;
+            else
+               trp = -1;
+         }
+         /* Get picture header */
+         headerSuccess = dphGetPictureHeader(&pichIn, &pichInOut, &pichOut, &bitErrorIndication);
+
+         if (headerSuccess != DPH_OK) {
+            
+            deb("vdcDecodeFrame: Header decoding unsuccessful due to errors, picture will be discarded.\n");
+            retValue = VDC_OK_BUT_FRAME_USELESS;
+            goto exitFunction;
+         }
+
+         numMBsInFrame = renDriNumOfMBs(instance->currFrame->imb->drawItem);
+
+         currYFrame = pichOut.currYFrame;
+         currUFrame = pichOut.currUFrame;
+         currVFrame = pichOut.currVFrame;
+
+         numOfCodedMBs = 0;
+         fCodedMBs = renDriCodedMBs(instance->currFrame->imb->drawItem);
+         memset(fCodedMBs, 0, numMBsInFrame * sizeof(u_char));
+
+         /* Initialize quantization parameter array */
+         quantParams = instance->currFrame->imb->yQuantParams;
+         memset(quantParams, 0, numMBsInFrame * sizeof(int));
+
+         /* If this is the first frame and callback function has been set, report frame size */ 
+         if (instance->nOfDecodedFrames == 0 && instance->reportPictureSizeCallback) {
+            h263dReportPictureSizeCallback_t cb = 
+               (h263dReportPictureSizeCallback_t)instance->reportPictureSizeCallback;
+            cb(instance->hParent, instance->pictureParam.lumWidth, instance->pictureParam.lumHeight);
+         }
+
+         /* If picture header was ok */
+         if (headerSuccess == DPH_OK)
+         {
+            /* Get and decode Supplemental Enhancement Information */
+            int seiSuccess = dphGetSEI(instance, inBuffer, &bitErrorIndication);
+
+            /* If fatal error while reading SEI */
+            if (seiSuccess < 0) {
+               retValue = VDC_ERR;
+               deb("vdcDecodeFrame: dphGetSEI failed.\n");
+               goto exitFunction;
+            }
+
+            /* Else if bit error while reading SEI */
+            else if (seiSuccess == DPH_OK_BUT_BIT_ERROR) {
+               /* We can't trust that the 1st segment can be decoded.
+                  Thus, let's continue with the 2nd segment. */
+               if ( instance->pictureParam.fSS )
+                  expectedDecodingPosition = EDP_START_OF_SLICE_SEGMENT;
+               else
+                  expectedDecodingPosition = EDP_START_OF_GOB_SEGMENT;
+               sncCode = sncSeekSync(inBuffer, &error);
+               if (error && error != ERR_BIB_NOT_ENOUGH_DATA) {
+                  retValue = VDC_ERR;
+                  deb("vdcDecodeFrame: sncSeekSync failed.\n");
+                  goto exitFunction;
+               }
+               continue;
+            }
+
+
+         }
+
+         if ( hTranscoder->H263PictureHeaderEnded(&pichOut, &pichInOut) != VDC_OK )
+            {
+              retValue = VDC_ERR;
+              goto exitFunction;
+            }
+
+         if (instance->pictureParam.fSS)
+         /* Decode the 1st Slice segment - not supported */
+         {
+             retValue = VDC_OK_BUT_FRAME_USELESS;
+             goto exitFunction;
+         }
+         else
+         /* Decode the 1st GOB segment */
+         {
+            dgobGOBSegmentInParam_t dgobi;
+            dgobGOBSegmentInOutParam_t dgobio;
+
+            dgobi.numStuffBits = 0;
+            dgobi.pictParam = &instance->pictureParam;
+            dgobi.inBuffer = inBuffer;
+
+            dgobi.outBuffer = outBuffer;
+            dgobi.bufEdit = bufEdit;
+
+            dgobi.iColorEffect = aColorEffect; 
+            dgobi.iGetDecodedFrame=aGetDecodedFrame;
+            dgobio.StartByteIndex=0;
+            dgobio.StartBitIndex=7;
+
+            /* fGFIDShouldChange not relevant here */
+
+            dgobio.prevGNWithHeader = 0;
+            dgobio.prevGN = 0;
+            /* dgobio.gfid, not relevant here */
+            dgobio.fCodedMBs = fCodedMBs;
+            dgobio.numOfCodedMBs = numOfCodedMBs;
+            dgobio.quantParams = quantParams;
+            dgobio.mvcData = &instance->mvcData;
+            dgobio.imageStore = instance->imageStore;
+            dgobio.trp = pichOut.trp;
+            dgobio.rtr = 0; /* not relevant since no reference frame exists yet */
+            dgobio.refY = refYFrame;
+            dgobio.refU = refUFrame;
+            dgobio.refV = refVFrame;
+            dgobio.currPY = currYFrame;
+            dgobio.currPU = currUFrame;
+            dgobio.currPV = currVFrame;
+
+            /* the first GOB doesn't have a header */
+            hTranscoder->H263GOBSliceHeaderBegin();
+            hTranscoder->H263GOBSliceHeaderEnded(NULL, NULL);
+
+            decStatus = dgobGetAndDecodeGOBSegmentContents(&dgobi, 
+               instance->pictureParam.pictureType != VDX_PIC_TYPE_I,
+               pichOut.pquant, &dgobio, hTranscoder);
+
+            if (decStatus < 0) {
+               retValue = VDC_ERR;
+               goto exitFunction;
+            }
+
+            hTranscoder->H263OneGOBSliceWithHeaderEnded();
+
+            prevGNWithHeader = dgobio.prevGNWithHeader;
+            prevGN = dgobio.prevGN;
+            numOfCodedMBs = dgobio.numOfCodedMBs;
+            trp = dgobio.trp;
+            rtr = dgobio.rtr;
+            refYFrame = dgobio.refY;
+            refUFrame = dgobio.refU;
+            refVFrame = dgobio.refV;
+            if (prevGN == instance->pictureParam.numGOBs - 1)
+               expectedDecodingPosition = EDP_END_OF_FRAME;
+            else
+               expectedDecodingPosition = EDP_START_OF_GOB_SEGMENT;
+         }
+      }
+   
+      /* Else if GOB segment starts as expected */
+      else if (expectedDecodingPosition == EDP_START_OF_GOB_SEGMENT &&
+         sncCode == SNC_GBSC) {
+
+         dgobGOBSegmentInParam_t dgobi;
+         dgobGOBSegmentInOutParam_t dgobio;
+
+         dgobi.numStuffBits = numStuffBits;
+         dgobi.pictParam = &instance->pictureParam;
+         dgobi.inBuffer = inBuffer;
+
+         dgobi.outBuffer = outBuffer;
+         dgobi.bufEdit = bufEdit;
+
+         dgobi.iColorEffect = aColorEffect; 
+         dgobi.iGetDecodedFrame= aGetDecodedFrame;
+         if(prevGN==-1)
+         {
+             dgobio.StartByteIndex=0;
+             dgobio.StartBitIndex=7;
+         }
+         else
+         {
+             dgobio.StartByteIndex=dgobi.inBuffer->getIndex;
+             dgobio.StartBitIndex=dgobi.inBuffer->bitIndex;
+         }
+
+
+         /* fGFIDShouldChange, see below */
+
+         dgobio.prevGNWithHeader = prevGNWithHeader;
+         dgobio.prevGN = prevGN;
+         /* dgobio.gfid, see below */
+         dgobio.fCodedMBs = fCodedMBs;
+         dgobio.numOfCodedMBs = numOfCodedMBs;
+         dgobio.quantParams = quantParams;
+         dgobio.mvcData = &instance->mvcData;
+         dgobio.imageStore = instance->imageStore;
+         dgobio.trp = trp;
+         dgobio.rtr = rtr;
+         dgobio.refY = refYFrame;
+         dgobio.refU = refUFrame;
+         dgobio.refV = refVFrame;
+         dgobio.currPY = currYFrame;
+         dgobio.currPU = currUFrame;
+         dgobio.currPV = currVFrame;
+
+         dgobi.fGFIDShouldChange = instance->fGFIDShouldChange;
+         dgobio.gfid = instance->gfid;
+
+         /* Get and decode GOB segment */
+         decStatus = dgobGetAndDecodeGOBSegment(&dgobi, &dgobio, hTranscoder);
+
+         if (decStatus == DGOB_ERR) {
+            retValue = VDC_ERR;
+            goto exitFunction;
+         }
+         if ( instance->fGFIDShouldChange ) {
+            instance->gfid = dgobio.gfid;
+            instance->fGFIDShouldChange = 0;
+         }
+
+         prevGNWithHeader = dgobio.prevGNWithHeader;
+         prevGN = dgobio.prevGN;
+         numOfCodedMBs = dgobio.numOfCodedMBs;
+         trp = dgobio.trp;
+
+
+         rtr = dgobio.rtr;
+
+         refYFrame = dgobio.refY;
+         refUFrame = dgobio.refU;
+         refVFrame = dgobio.refV;
+
+         if (prevGN == instance->pictureParam.numGOBs - 1)
+            expectedDecodingPosition = EDP_END_OF_FRAME;
+         else
+            expectedDecodingPosition = EDP_START_OF_GOB_SEGMENT;
+      }
+
+      /* Else if Slice segment starts as expected */
+      else if (expectedDecodingPosition == EDP_START_OF_SLICE_SEGMENT &&
+         sncCode == SNC_GBSC) {
+         /* slides not supported */
+         retValue = VDC_OK_BUT_FRAME_USELESS;
+         goto exitFunction;
+
+      }
+
+      /* Else decoding is out of sync */
+      else {
+         switch (expectedDecodingPosition) {
+
+            case EDP_START_OF_FRAME:
+               /* No PSC */
+               /* Check if GFID could be used to recover the picture header */
+               {
+                  dphInParam_t pichIn;
+                  dphInOutParam_t pichInOut;
+                  dphOutParam_t pichOut;
+
+                  pichIn.numStuffBits = numStuffBits;
+                  pichIn.fReadBits = 0;
+
+                  pichInOut.vdcInstance = instance;
+                  pichInOut.inBuffer = inBuffer;
+
+                  headerSuccess = dphGetPictureHeader(&pichIn, &pichInOut, &pichOut, &bitErrorIndication);
+                  if ( headerSuccess == DPH_OK) {
+                     /* Header recovery was successful, start decoding from the next GOB available */
+                     if ( instance->pictureParam.fSS ) {
+                        expectedDecodingPosition = EDP_START_OF_SLICE_SEGMENT;
+                        /* decSlice does not increment these */
+                        decodedSegments++;
+                        corruptedSegments++;
+                     }
+                     else
+                        expectedDecodingPosition = EDP_START_OF_GOB_SEGMENT;
+                     deb1p("vdcDecodeFrame: Header successfully recovered after PSC loss. FrameNum %d\n",instance->frameNum);
+                     currYFrame = pichOut.currYFrame;
+                     currUFrame = pichOut.currUFrame;
+                     currVFrame = pichOut.currVFrame;
+                     numMBsInFrame = renDriNumOfMBs(instance->currFrame->imb->drawItem);
+                     numOfCodedMBs = 0;
+                     numDecodedMBs = 0;
+                     fCodedMBs = renDriCodedMBs(instance->currFrame->imb->drawItem);
+                     memset(fCodedMBs, 0, numMBsInFrame * sizeof(u_char));
+
+                     /* Initialize quantization parameter array */
+                     quantParams = instance->currFrame->imb->yQuantParams;
+                     memset(quantParams, 0, numMBsInFrame * sizeof(int));
+
+                     /* If this is the first frame and callback function has been set, report frame size */ 
+                     if (instance->nOfDecodedFrames == 0 && instance->reportPictureSizeCallback) {
+                        h263dReportPictureSizeCallback_t cb = 
+                           (h263dReportPictureSizeCallback_t)instance->reportPictureSizeCallback;
+                        cb(instance->hParent, instance->pictureParam.lumWidth, instance->pictureParam.lumHeight);
+                     }
+
+                     continue;
+                  }
+                  else {
+                     retValue = VDC_OK_BUT_FRAME_USELESS;
+                     deb1p("vdcDecodeFrame: Header recovery unsuccessful after PSC loss. FrameNum %d\n",instance->frameNum);
+                     goto exitFunction;
+                  }
+               }
+            case EDP_START_OF_GOB_SEGMENT:
+               if ( sncCode == SNC_PSC ) {
+                  retValue = VDC_OK_BUT_BIT_ERROR;
+                  goto exitFunction;
+               }
+               else {
+                  /* 
+                   * Picture header recovery used next picture header 
+                   * => we are not at the position of GBSC => search the next one 
+                   * This is caused by a erdRestorePictureHeader that does not synchronize 
+                   * bit buffer to GOB headers that have bitErrorIndication != 0.
+                   * This may be considered as a , and it might be good to change it later on.
+                   * This seeking should solve the problem, although maybe not in the most elegant way
+                   */
+                  sncSeekSync( inBuffer, &error );
+                  continue;
+               }
+           default :
+            {
+            
+                retValue = VDC_OK_BUT_FRAME_USELESS;
+                 goto exitFunction;
+            }
+
+         }
+      }
+   }
+
+   exitFunction:
+
+
+   /* If frame(s) not useless */
+   if (retValue == VDC_OK || retValue == VDC_OK_BUT_BIT_ERROR) {
+
+      if (!corruptedSegments && (numDecodedMBs > 0 || prevGN > 0 || instance->pictureParam.numGOBs == 1))
+         retValue = VDC_OK;
+      else {
+         retValue = VDC_OK_BUT_FRAME_USELESS;
+         deb1p("vdcDecodeFrame: Frame useless, too many corrupted segments. FrameNum %d\n",instance->frameNum);
+      }
+   }
+
+   /* If decoding ok and frame not useless */
+   if ( retValue == VDC_OK || retValue == VDC_OK_BUT_BIT_ERROR ) {
+
+
+       /* stuff bits here 'END OF FRAME' -->*/
+         bibStuffBits(outBuffer); 
+       /* <-- */
+
+      if ( instance->nOfDecodedFrames < 0xffffffff )
+         instance->nOfDecodedFrames++;
+
+      if (vdcFillImageBuffers(
+         instance, 
+         numOfCodedMBs, 
+         instance->currFrame->imb) < 0)
+         retValue = VDC_ERR;
+
+
+
+   }
+   if ( retValue == VDC_OK_BUT_FRAME_USELESS ) {
+      /* GFID of the next frame can be whatever, since this frame was useless */
+      instance->gfid = -1; 
+   }
+   if ( instance->fGFIDShouldChange
+        && (    (instance->pictureParam.fSS && decodedSegments == 1) 
+             || (!instance->pictureParam.fSS && prevGNWithHeader <= 0) 
+           )
+      ) 
+   {
+      /* GFID of the next frame can be whatever, since this frame didn't have any GFID's and GFID was supposed to change */
+      instance->gfid = -1; 
+   }
+
+   /* If a fatal error occurred */
+   if (retValue < 0) {
+      /* Return frame buffers for decoded output images,
+         as they are useless for the caller and 
+         as the caller cannot get a handle to return them */
+      if (instance->currFrame)
+         vdeImsPutFree(instance->imageStore, instance->currFrame);
+   }
+
+   return retValue;
+}
+
+
+/* {{-output"vdcDecodePictureHeader.txt"}} */
+/*
+ * vdcDecodePictureHeader
+ *
+ * Parameters:
+ *    hInstance                  I: handle of instance data
+ *                               (May set instance->errorVar if bit errors.)
+ *
+ * Function:
+ *    
+ *
+ * Note:
+ *    This function does not recover corrupted picture headers (by means of
+ *    GFID or redundant picture header copies).
+ *
+ * Returns:
+ *    See above.
+ */
+
+int vdcDecodePictureHeader(
+   vdcHInstance_t hInstance,
+   bibBuffer_t *inBuffer,
+   vdxPictureHeader_t *header,
+   vdxSEI_t *sei)
+{
+   int
+      retValue = VDC_OK, 
+      sncCode,
+      numStuffBits,
+      bitErrorIndication = 0;
+
+   int16
+      error = 0;
+
+   u_int32
+      pictureStartPosition;
+
+   vdcInstance_t 
+      *instance = (vdcInstance_t *) hInstance;
+
+   /* The function is implemented by calling stateless Video Demultiplexer
+      (vdx) functions. Consequently, the function does not have sophisticated
+      logic to track illegal/corrupted parameters based on the previous
+      picture header. It cannot recover corrupted picture headers either.
+
+      Alternatively, the function could have been implemented by creating
+      an identical copy of the Video Decoder Core instance and by using
+      "Decode Picture Header" (dph) module functions. However, as there is
+      no instance copying functions implemented, the former alternative
+      was chosen.
+
+      This function was targeted for getting the picture type and 
+      Nokia-proprietary Annex N scalability layer information encapsulated
+      in Supplemental Enhancement Information in an error-free situation.
+      For this purpose, the former and simpler solution is more than 
+      adequate. */
+
+   pictureStartPosition = bibNumberOfFlushedBits(inBuffer);
+   sncCode = sncCheckSync(inBuffer, &numStuffBits, &error);
+
+   /* If sncCheckSync failed */
+   if (error) {
+      deb1p("vdcDecodeFrame: ERROR - sncCheckSync returned %d.\n", error);
+      retValue = VDC_ERR;
+      goto exitFunction;
+   }
+
+   /* Else if EOS was got */
+   else if (sncCode == SNC_EOS) {
+      retValue = VDC_OK_BUT_FRAME_USELESS;
+      goto exitFunction;
+   }
+
+   /* Else if frame starts as expected */
+   else if (sncCode == SNC_PSC) {
+      int
+         picHdrStatus,
+         seiStatus;
+
+      vdxGetPictureHeaderInputParam_t
+         picHdrIn;
+
+      picHdrIn.numStuffBits = numStuffBits;
+      picHdrIn.fCustomPCF = 0;
+      picHdrIn.fScalabilityMode = 0;
+      picHdrIn.fRPS = instance->fRPS;
+      picHdrIn.flushBits = bibFlushBits;
+      picHdrIn.getBits = bibGetBits;
+      picHdrIn.showBits = bibShowBits;
+
+      /* Get picture header */
+      picHdrStatus = vdxGetPictureHeader(
+         inBuffer, 
+         &picHdrIn,
+         header,
+         &bitErrorIndication);
+
+      /* If the header was not successfully retrieved */
+      if (picHdrStatus < 0) {
+         retValue = VDC_ERR;
+         goto exitFunction;
+      }
+      else if (picHdrStatus != VDX_OK) {
+         retValue = VDC_OK_BUT_BIT_ERROR;
+         goto exitFunction;
+      }
+
+      /* Get and decode Supplemental Enhancement Information */
+      seiStatus = vdxGetAndParseSEI(
+         inBuffer,
+         instance->pictureParam.fPLUSPTYPE,
+         instance->numAnnexNScalabilityLayers,
+         sei,
+         &bitErrorIndication);
+
+      /* If error while reading SEI */
+      if (seiStatus < 0) {
+         retValue = VDC_ERR;
+         goto exitFunction;
+      }
+      else if (seiStatus != VDX_OK) {
+         retValue = VDC_OK_BUT_BIT_ERROR;
+         goto exitFunction;
+      }
+   }
+
+   /* Else no valid frame start */
+   else
+      retValue = VDC_OK_BUT_FRAME_USELESS;
+
+   exitFunction:
+
+   /* Reset the bit buffer to its original position */
+   bibRewindBits(
+      bibNumberOfFlushedBits(inBuffer) - pictureStartPosition,
+      inBuffer, &error);
+
+   if (error)
+      retValue = VDC_ERR;
+
+   return retValue;
+}
+
+
+/* {{-output"vdcFree.txt"}} */
+/*
+ * vdcFree
+ *    
+ *
+ * Parameters:
+ *    None.
+ *
+ * Function:
+ *    This function deinitializes the Video Decoder Core module.
+ *    Any functions of this module must not be called after vdcFree (except 
+ *    vdcLoad).
+ *
+ * Returns:
+ *    >= 0  if succeeded
+ *    < 0   if failed
+ *
+ *    
+ */
+
+int vdcFree(void)
+/* {{-output"vdcFree.txt"}} */
+{
+   if (dblFree() < 0)
+      return VDC_ERR;
+
+   return VDC_OK;
+}
+
+
+/* {{-output"vdcGetImsItem.txt"}} */
+/*
+ * vdcGetImsItem
+ *    
+ *
+ * Parameters:
+ *    hInstance                  handle of instance data
+ *    index                      output frame number,
+ *                               should be 0 for I and P frames
+ *
+ * Function:
+ *    This function returns a pointer to the requested output frame.
+ *
+ * Returns:
+ *    a pointer to a image store item which corresponds to the passed output
+ *    frame index, or
+ *    NULL if the function fails
+ *
+ */
+
+vdeImsItem_t *vdcGetImsItem(vdcHInstance_t hInstance, int index)
+/* {{-output"vdcGetImsItem.txt"}} */
+{
+   vdcInstance_t *instance = (vdcInstance_t *) hInstance;
+   int numOutputFrames = vdcGetNumberOfOutputFrames(hInstance);
+
+   vdcAssert(instance);
+   vdcAssert(index >= 0);
+
+   if (index >= numOutputFrames)
+      return NULL;
+
+   return instance->currFrame;
+}
+
+   
+/* {{-output"vdcGetNumberOfAnnexNScalabilityLayers.txt"}} */
+/*
+ * vdcGetNumberOfAnnexNScalabilityLayers
+ *
+ * Parameters:
+ *    hInstance                  I: handle of instance data
+ *
+ * Function:
+ *    Returns the number of Nokia-proprietary Annex N temporal scalability
+ *    layers.
+ *
+ * Returns:
+ *    See above.
+ */
+
+int vdcGetNumberOfAnnexNScalabilityLayers(
+   vdcHInstance_t hInstance)
+/* {{-output"vdcGetNumberOfAnnexNScalabilityLayers.txt"}} */
+{
+   vdcInstance_t *instance = (vdcInstance_t *) hInstance;
+
+   vdcAssert(instance);
+
+   return instance->numAnnexNScalabilityLayers;
+}
+
+
+/* {{-output"vdcGetNumberOfOutputFrames.txt"}} */
+/*
+ * vdcGetNumberOfOutputFrames
+ *    
+ *
+ * Parameters:
+ *    hInstance                  handle of instance data
+ *
+ * Function:
+ *    This function returns the number of output frames which were produced
+ *    during the latest vdcDecodeFrame. 
+ *
+ * Returns:
+ *    0 if vdcDecodeFrame failed to produce any output frames
+ *    1 for I and P frames
+ *
+ */
+
+int vdcGetNumberOfOutputFrames(vdcHInstance_t hInstance)
+/* {{-output"vdcGetNumberOfOutputFrames.txt"}} */
+{
+   vdcInstance_t *instance = (vdcInstance_t *) hInstance;
+
+   vdcAssert(instance);
+
+   return ((instance->currFrame) ? 1 : 0);
+}
+
+
+/* {{-output"vdcGetTR.txt"}} */
+/*
+ * vdcGetTR
+ *    
+ *
+ * Parameters:
+ *    inpBuffer                  buffer containing the frame data,
+ *                               must start with a PSC
+ *    tr                         temporal reference
+ *
+ * Function:
+ *    Gets the temporal reference field from the input buffer.
+ *    Notice that the validity of the bitstream is not checked.
+ *    This function does not support enhanced temporal reference
+ *    (ETR) defined in section 5.1.8 of the H.263 recommendation.
+ *
+ * Returns:
+ *    Nothing
+ *
+ *    
+ */
+
+void vdcGetTR(void *inpBuffer, u_int8 *tr)
+/* {{-output"vdcGetTR.txt"}} */
+{
+   const u_char 
+      *tmpBuffer = (u_char *) inpBuffer;
+
+   *tr = (u_int8) (((tmpBuffer[2] & 2) << 6) | ((tmpBuffer[3] & 252) >> 2));
+}
+
+
+/* {{-output"vdcIsEOSReached.txt"}} */
+/*
+ * vdcIsEOSReached
+ *    
+ *
+ * Parameters:
+ *    hInstance                  handle of instance data
+ *
+ * Function:
+ *    This function returns 1 if the EOS code has been reached during
+ *    the decoding. Otherwise, it returns 0.
+ *
+ * Returns:
+ *    See above.
+ *
+ */
+
+int vdcIsEOSReached(vdcHInstance_t hInstance)
+/* {{-output"vdcIsEOSReached.txt"}} */
+{
+   vdcInstance_t *instance = (vdcInstance_t *) hInstance;
+
+   vdcAssert(instance);
+
+   return instance->fEOS;
+}
+
+
+/* {{-output"vdcIsINTRA.txt"}} */
+/*
+ * vdcIsINTRA
+ *    
+ *
+ * Parameters:
+ *    hInstance                  handle of instance data
+ *    frameStart                 pointer to memory chunk containing a frame
+ *    frameLength                number of bytes in frame
+ *
+ * Function:
+ *    This function returns 1 if the passed frame is an INTRA frame.
+ *    Otherwise the function returns 0.
+ *
+ * Returns:
+ *    See above.
+ *
+ *    
+ */
+
+int vdcIsINTRA(
+   vdcHInstance_t hInstance,
+   void *frameStart,
+   unsigned frameLength)
+/* {{-output"vdcIsINTRA.txt"}} */
+{
+   bibBuffer_t *tmpBitBuffer;
+   int fINTRA = 0, bitErrorIndication, syncCode, vdxStatus;
+   int16 error = 0;
+   vdcInstance_t *instance = (vdcInstance_t *) hInstance;
+   vdxGetPictureHeaderInputParam_t vdxIn;
+   vdxPictureHeader_t vdxOut;
+
+   vdcAssert(instance);
+
+   tmpBitBuffer = bibCreate(frameStart, frameLength, &error);
+   if (!tmpBitBuffer || error)
+      return 0;
+
+   syncCode = sncCheckSync(tmpBitBuffer, &(vdxIn.numStuffBits), &error);
+
+   if (syncCode == SNC_PSC && error == 0) {
+
+      /* Note: Needs to be changed when support for custom PCF or scalability mode
+         is added */
+      vdxIn.fCustomPCF = 0; 
+      vdxIn.fScalabilityMode = 0;
+      vdxIn.fRPS = instance->fRPS;
+      vdxIn.flushBits = bibFlushBits;
+      vdxIn.getBits = bibGetBits;
+      vdxIn.showBits = bibShowBits;
+
+      vdxStatus = vdxGetPictureHeader(tmpBitBuffer, &vdxIn, &vdxOut, 
+         &bitErrorIndication);
+
+      if (vdxStatus >= 0 && bitErrorIndication == 0)
+         fINTRA = (vdxOut.pictureType == VDX_PIC_TYPE_I);
+   }
+
+   bibDelete(tmpBitBuffer, &error);
+
+   return fINTRA;
+}
+
+
+/* {{-output"vdcIsINTRAGot.txt"}} */
+/*
+ * vdcIsINTRAGot
+ *    
+ *
+ * Parameters:
+ *    hInstance                  handle of instance data
+ *
+ * Function:
+ *    This function returns 1 if the an INTRA frame has been decoded
+ *    during the lifetime of the instance. Otherwise, it returns 0.
+ *
+ * Returns:
+ *    See above.
+ *
+ *    
+ */
+
+int vdcIsINTRAGot(vdcHInstance_t hInstance)
+/* {{-output"vdcIsEOSReached.txt"}} */
+{
+   vdcInstance_t *instance = (vdcInstance_t *) hInstance;
+
+   vdcAssert(instance);
+
+   return instance->fIntraGot;
+}
+
+
+/* {{-output"vdcLoad.txt"}} */
+/*
+ * vdcLoad
+ *    
+ *
+ * Parameters:
+ *    None.
+ *
+ * Function:
+ *    This function initializes the Video Decoder Core module meaning
+ *    all the data common to all Video Decoder Core instances.
+ *    vdcLoad has to be called before any other function of this module
+ *    is used.
+ *
+ * Returns:
+ *    >= 0  if succeeded
+ *    < 0   if failed
+ *
+ *    
+ */
+
+int vdcLoad(void)
+/* {{-output"vdcLoad.txt"}} */
+{
+   if (dblLoad() < 0)
+      return VDC_ERR;
+
+   return VDC_OK;
+}
+
+
+/* {{-output"vdcOpen.txt"}} */
+/*
+ * vdcOpen
+ *    
+ *
+ * Parameters:
+ *    imageStore                 pointer to image store instance
+ *    numReferenceFrames         1 if the Reference Picture Selection (RPS)
+ *                               mode (Annex N) should not be used,
+ *                               >1 tells how many reference images
+ *                               are stored in the RPS mode
+ *    fudInstance                pointer to Fast Update module instance
+ *    hParent                    handle of Video Decoder Engine instance
+ *                               that created this VDC instance
+ *
+ * Function:
+ *    This function creates and initializes a new Video Decoder Core instance.
+ *
+ * Returns:
+ *    a handle to the created instance,
+ *    or NULL if the function fails
+ *
+ *    
+ */
+
+vdcHInstance_t vdcOpen(
+   vdeIms_t *imageStore, 
+   int numReferenceFrames,
+   void *hParent)
+{
+   vdcInstance_t *instance;
+
+   vdcAssert(numReferenceFrames >= 1);
+
+   instance = (vdcInstance_t *) vdcMalloc(sizeof(vdcInstance_t));
+   if (!instance)
+      return NULL;
+   memset(instance, 0, sizeof(vdcInstance_t));
+
+   instance->prevPicHeader = (vdxPictureHeader_t *)vdcMalloc( sizeof( vdxPictureHeader_t ));
+   if ( instance->prevPicHeader == NULL ) {
+      deb("vdcOpen, MALLOC for prevPicHeader failed.\n");
+      goto errPHOpen;
+   }
+   instance->fPrevPicHeaderReliable = 1;
+
+   instance->imageStore = imageStore;
+
+   instance->numAnnexNScalabilityLayers = -1; /* Indicates no decoded frames */
+
+   instance->fGFIDShouldChange = 0;
+   instance->gfid = -1;
+
+   instance->nOfDecodedFrames = 0;
+
+   instance->hParent = hParent;
+   instance->snapshotStatus = -1;
+
+   return (vdcHInstance_t) instance;
+
+   /* Error cases: release everything in reverse order */
+   errPHOpen:
+
+   vdcDealloc(instance);
+   return NULL;
+}
+/* {{-output"vdcOpen.txt"}} */
+
+
+/* {{-output"vdcRestartVideo.txt"}} */
+/*
+ * vdcRestartVideo
+ *    
+ *
+ * Parameters:
+ *    hInstance                  handle of instance data
+ *
+ * Function:
+ *    Resets the instance data but does not deallocate the allocated buffers.
+ *    After this function vdcDecodeFrame can be called as if no data for this
+ *    instance has been decoded.
+ *
+ * Note:
+ *    This function is obsolete and not used anymore. If it is needed again,
+ *    it should be re-implemented.
+ *
+ * Returns:
+ *    Nothing
+ *
+ *    
+ */
+
+void vdcRestartVideo(vdcHInstance_t hInstance)
+/* {{-output"vdcRestartVideo.txt"}} */
+{
+   vdcInstance_t *instance = (vdcInstance_t *) hInstance;
+
+   if (instance)
+      memset(instance, 0, sizeof(vdcInstance_t));
+}
+
+
+
+
+
+/*
+ * Local functions
+ */
+
+/*
+ * vdcFillCommonPartsOfImb
+ *    
+ *
+ * Parameters:
+ *    instance                   instance data
+ *    numOfCodedMBs              number of coded macroblocks
+ *    imb                        pointer to image buffer to fill
+ *
+ * Function:
+ *    This function fills the passed image buffer according to the latest
+ *    decoding results. Only those parts of the image buffer are filled
+ *    which can be composed with the presence of another image buffer,
+ *    e.g. the P image buffer corresponding to the B image buffer.
+ *
+ * Returns:
+ *    Nothing
+ *
+ *    
+ */
+
+static void vdcFillCommonPartsOfImb(
+   vdcInstance_t *instance, 
+   int numOfCodedMBs,
+   vdeImb_t *imb)
+{
+   vdcAssert(imb);
+   vdcAssert(instance);
+
+   imb->drawItem->param.dwFlags = 0;
+   imb->drawItem->param.lTime = instance->frameNum;
+
+   /* Note: for now, convert whole frame */
+   imb->drawItem->extParam.flags = 0;
+   /* Else one could convert just coded MBs as follows: */
+      /* imb->drawItem->extParam.flags = (fBPart) ? 0 : REN_EXTDRAW_NEW_SOURCE; */
+
+   imb->drawItem->extParam.rate = 30000;
+   imb->drawItem->extParam.scale = 1001;
+   imb->drawItem->extParam.numOfCodedMBs = numOfCodedMBs;
+
+   /* imb->drawItem->retFrame and imb->drawItem->retFrameParam are set by
+      the caller */
+
+   imb->fReferenced = 1;
+   imb->tr = instance->pictureParam.tr;
+}
+
+
+/*
+ * vdcFillImageBuffers
+ *    
+ *
+ * Parameters:
+ *    instance                   instance data
+ *    numOfCodedMBs              number of coded macroblocks
+ *    imbP                       pointer to image buffer of P or I frame
+ *
+ * Function:
+ *    This function fills the passed image buffers according to the latest
+ *    decoding results.
+ *
+ * Returns:
+ *    >= 0                       if the function was successful
+ *    < 0                        if an error occured
+ *
+ *    
+ */
+
+/* Codec and renderer dependent */
+int vdcFillImageBuffers(
+   vdcInstance_t *instance, 
+   int numOfCodedMBs,
+   vdeImb_t *imbP)
+{
+   /* Table to convert from lumiance quantization parameter to chrominance
+      quantization parameter if Modified Quantization (Annex T) is in use. */
+   static const int yToUVQuantizer[32] = 
+      {0,1,2,3,4,5,6,6,7,8,9,9,10,10,11,11,12,
+       12,12,13,13,13,14,14,14,14,14,15,15,15,
+       15,15};
+
+   int
+      firstQPIndex,        /* the index of the first non-zero quantizer */
+
+      *yQuantParams = imbP->yQuantParams,
+                           /* array of Y quantizers in scan-order */
+
+      *uvQuantParams = imbP->uvQuantParams,
+                           /* array of UV quantizers in scan-order */
+
+      numMBsInPicture,     /* number of macroblocks in the image */
+
+      i;                   /* loop variable */
+
+   vdcAssert(imbP);
+   vdcAssert(instance);
+
+   /*
+    * Fill basic stuff
+    */
+
+   vdcFillCommonPartsOfImb(instance, numOfCodedMBs, imbP);
+
+   /*
+    * Calculate quantizer arrays for loop/post-filtering
+    */
+
+   numMBsInPicture = instance->pictureParam.lumMemWidth * 
+      instance->pictureParam.lumMemHeight / 256;
+
+   /* Get the index of the first non-zero quantizer in scan-order */
+   for (firstQPIndex = 0; firstQPIndex < numMBsInPicture; firstQPIndex++) {
+      if (yQuantParams[firstQPIndex] > 0)
+         break;
+   }
+
+   /* Assert that at least one macroblock is decoded successfully */
+   vdcAssert(firstQPIndex < numMBsInPicture);
+
+   /* Replace the first zero quantizers with the first non-zero quantizer
+      (in scan-order) */
+   for (i = 0; i < firstQPIndex; i++)
+      yQuantParams[i] = yQuantParams[firstQPIndex];
+
+   /* Replace all other zero quantizers with the predecessor (in scan-order) */
+   for (i = firstQPIndex; i < numMBsInPicture; i++) {
+      if (yQuantParams[i] == 0)
+         yQuantParams[i] = yQuantParams[i - 1];
+   }
+
+   /* If Modified Quantization is in use */
+   if (instance->pictureParam.fMQ) {
+      /* Convert Y quantizers to UV quantizers */
+      for (i = 0; i < numMBsInPicture; i++)
+         uvQuantParams[i] = yToUVQuantizer[yQuantParams[i]];
+   }
+   else
+      /* Copy Y quantizers to UV quantizers */
+      memcpy(uvQuantParams, yQuantParams, numMBsInPicture * sizeof(int));
+
+
+   return VDC_OK;
+}
+
+// End of File