diff -r 000000000000 -r 951a5db380a0 videoeditorengine/h263decoder/src/core.cpp --- /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