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