diff -r 000000000000 -r 951a5db380a0 videoeditorengine/h263decoder/src/decpich.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/videoeditorengine/h263decoder/src/decpich.cpp Fri Jan 29 14:08:33 2010 +0200 @@ -0,0 +1,699 @@ +/* +* 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: +* Picture header decoding functions. +* +*/ + + + +#include "h263dConfig.h" + +#include "decpich.h" +#include "debug.h" +#include "vdeims.h" +#include "vdeimb.h" +#include "viddemux.h" +#include "sync.h" + + +/* + * Global functions + */ + +/* {{-output"dphGetPictureHeader.txt"}} */ +/* + * dphGetPictureHeader + * + * + * Parameters: + * inParam input parameters + * inOutParam input/output parameters, these parameters + * may be modified in the function + * outParam output parameters + * bitErrorIndication bit error indication, see biterr.h for + * the possible values + * + * Function: + * This function gets and decodes a picture header which should start + * with a PSC at the current position of the bit buffer. At first, + * the function reads the picture header fields from the bitstream. + * Then, it checks whether the values of the fields are supported. + * An unsupported value is interpreted as a bit error. Finally, + * the function updates VDC instance data and output parameters + * (according to the new picture header). + * + * Returns: + * DPH_OK + * DPH_OK_BUT_BIT_ERROR + * DPH_ERR + * DPH_ERR_NO_INTRA + * DPH_ERR_FORMAT_CHANGE + * + */ + +int dphGetPictureHeader( + const dphInParam_t *inParam, + dphInOutParam_t *inOutParam, + dphOutParam_t *outParam, + int *bitErrorIndication) +/* {{-output"dphGetPictureHeader.txt"}} */ +{ + bibBuffer_t *inBuffer = inOutParam->inBuffer; + u_char fPrevIntraGot; /* Non-zero if an INTRA frame has been decoded + before the current frame */ + vdxGetPictureHeaderInputParam_t picHdrIn; + vdxPictureHeader_t picHeader; + vdcInstance_t *instance = inOutParam->vdcInstance; + vdcPictureParam_t *pictureParam = &instance->pictureParam; + vdcPictureParam_t prevPictParam; + int trd; /* Difference between present and previous tr */ + int fInterFrame; /* non-zero = INTER frame, 0 = INTRA frame */ + int fPBFrame; /* Flag indicating a PB-frame */ + int fRPS; /* 1 = RPS used, 0 = RPS not used */ + int ret = 0; /* temporary variable to carry return values */ + int retVal = DPH_OK; /* return value if everything as expected, + either DPH_OK or DPH_OK_BUT_SKIP */ + int16 error = 0; /* snc and mvc module error code */ + + + /* + * Get picture header + */ + + picHdrIn.numStuffBits = inParam->numStuffBits; + picHdrIn.fCustomPCF = 0; + picHdrIn.fScalabilityMode = 0; + picHdrIn.fRPS = instance->fRPS; + picHdrIn.flushBits = bibFlushBits; + picHdrIn.getBits = bibGetBits; + picHdrIn.showBits = bibShowBits; + + /* Used to recover the 1st picture segment */ + u_int32 picHeaderStartPos = bibNumberOfFlushedBits(inBuffer); + + if ( inParam->numStuffBits ) { + bibFlushBits(inParam->numStuffBits, inBuffer, &picHdrIn.numStuffBits, bitErrorIndication, &error); + picHdrIn.numStuffBits = 0; + } + + // Read header bits normally from the bitstream + ret = vdxGetPictureHeader(inBuffer, &picHdrIn, &picHeader, + bitErrorIndication); + + if ( ret < 0 ) + return DPH_ERR; + else if ( ret == VDX_OK_BUT_BIT_ERROR ) + { + // Bit error exists. + return DPH_OK_BUT_BIT_ERROR; + } // end of if ( ret == VDX_OK_BUT_BIT_ERROR ) + + + /* + * Check picture header validity + */ + + /* Local parameters needed in validity check (and possibly afterwards) */ + fPrevIntraGot = instance->fIntraGot; + fInterFrame = (picHeader.pictureType == VDX_PIC_TYPE_P || + picHeader.pictureType == VDX_PIC_TYPE_PB || + picHeader.pictureType == VDX_PIC_TYPE_IPB); + fPBFrame = ((picHeader.pictureType == VDX_PIC_TYPE_PB)|| + (picHeader.pictureType == VDX_PIC_TYPE_IPB)); + + /* TR with the same value as in the previous picture can be interpreted + two ways: + - if Reference Picture Selection is enabled, it means + a synchronization frame + - if Reference Picture Selection is not used, it means the maximum + difference between two frames. + However, at least VDOPhone uses TR equal to zero always, which + in practice should be interpreted that TR field is not used in + display timing. */ + + /* At first, check if RPS is used */ + if (picHeader.fPLUSPTYPE && picHeader.ufep) + fRPS = picHeader.fRPS; + else + fRPS = instance->fRPS; + + /* Calculate temporal reference difference (from the previous frame) */ + trd = picHeader.tr - instance->pictureParam.tr; + if (trd < 0) + trd += 256; /* Note: Add ETR support */ + + /* If TR is the same as in the previous frame and Reference Picture Selection + is not used and not the very first frame (in which case previous tr == 0), + the temporal reference difference is the maximum one. */ + if (trd == 0 && !fRPS && instance->frameNum > 0) + trd = 256; /* Note: Add ETR support */ + + /* If unsupported picture type */ + if (picHeader.pictureType != VDX_PIC_TYPE_I + && picHeader.pictureType != VDX_PIC_TYPE_P + && picHeader.pictureType != VDX_PIC_TYPE_PB + && picHeader.pictureType != VDX_PIC_TYPE_IPB + ) { + return DPH_OK_BUT_BIT_ERROR; + } + + if (picHeader.pictureType == VDX_PIC_TYPE_PB || + picHeader.pictureType == VDX_PIC_TYPE_IPB) { + return DPH_OK_BUT_BIT_ERROR; + } + + if (picHeader.cpm) { + /* No CPM support */ + return DPH_OK_BUT_BIT_ERROR; + } + + if (picHeader.fPLUSPTYPE) { + /* If unsupported modes (and UFEP is whatever) */ + if (picHeader.fRPR || + picHeader.fRRU) { + return DPH_OK_BUT_BIT_ERROR; + } + + if (picHeader.ufep == 1) { + /* If unsupported mode */ + if (picHeader.fISD || + picHeader.fSAC || + picHeader.fAIV || + picHeader.fCustomPCF) { + return DPH_OK_BUT_BIT_ERROR; + } + + if (picHeader.fUMV) { + return DPH_OK_BUT_BIT_ERROR; + } + + if (picHeader.fAP) { + return DPH_OK_BUT_BIT_ERROR; + } + + if (picHeader.fAIC) { + return DPH_OK_BUT_BIT_ERROR; + } + + + + if (picHeader.fDF) { + return DPH_OK_BUT_BIT_ERROR; + } + + + + if (picHeader.fSS) { + return DPH_OK_BUT_BIT_ERROR; + } + + + + if (picHeader.fMQ) { + return DPH_OK_BUT_BIT_ERROR; + } + + } + + /* Note: Add check for "The Indenpenent Segment Decoding mode shall not + be used with the Reference Picture Resampling mode" + from section 5.1.4.6 of the H.263 recommendation whenever both of + the modes in question are supported. + Note that this check cannot reside in vdxGetPictureHeader since + ISD and RPR can be turned on in different pictures. */ + } + + /* Else no PLUSPTYPE */ + else { + /* If unsupported modes */ + if (picHeader.fSAC) { + return DPH_OK_BUT_BIT_ERROR; + } + + if (picHeader.fUMV) { + return DPH_OK_BUT_BIT_ERROR; + } + + if (picHeader.fAP) { + return DPH_OK_BUT_BIT_ERROR; + } + } + + /* If no INTRA frame has ever been decoded and the current frame is INTER */ + if (!fPrevIntraGot && fInterFrame) + return DPH_ERR_NO_INTRA; + + if (fPrevIntraGot) { + + /* If width and height are indicated in the header and + they are different from the previous */ + if ((picHeader.fPLUSPTYPE == 0 || picHeader.ufep == 1) && + (instance->pictureParam.lumWidth != picHeader.lumWidth || + instance->pictureParam.lumHeight != picHeader.lumHeight)) { + + if (fInterFrame) { + /* INTER frame, check that the source format has not changed */ + deb("vdcDecodeFrame: ERROR - Source format has changed " + "(INTER frame)\n"); + return DPH_OK_BUT_BIT_ERROR; + } + else if ( *bitErrorIndication ) { + deb("vdcDecodeFrame: ERROR - Frame size changing during " + "the sequence, cause: bitError\n"); + return DPH_OK_BUT_BIT_ERROR; + } + else { + /* At the moment do NOT allow source format changes during + the sequence. */ + deb("vdcDecodeFrame: ERROR - Frame size changing during " + "the sequence\n"); + return DPH_ERR_FORMAT_CHANGE; + } + } + } + + /* If the temporal reference of B points after P */ + if (fPBFrame && trd <= picHeader.trb) { + deb("vdcDecodeFrame: ERROR - TRB illegal.\n"); + return DPH_OK_BUT_BIT_ERROR; + } + + + /* Now, the picture header is considered to be error-free, + and its contents are used to manipulate instance data */ + + /* + * Update instance data and output parameters + */ + + /* Update frame numbers */ + { + int32 oldFrameNum = instance->frameNum; + + instance->frameNum += trd; + if (instance->frameNum < 0) + /* Wrap from 0x7fffffff to 0 instead of the largest negative number */ + instance->frameNum += 0x80000000; + + if (fPBFrame) { + instance->frameNumForBFrame = oldFrameNum + picHeader.trb; + if (instance->frameNumForBFrame < 0) + /* Wrap from 0x7fffffff to 0 instead of the largest negative number */ + instance->frameNumForBFrame += 0x80000000; + } + else + instance->frameNumForBFrame = -1; + } + + /* Note: If no INTRA has been got the function has already returned */ + instance->fIntraGot = 1; + + outParam->pquant = picHeader.pquant; + + instance->fRPS = fRPS; + + if (instance->fRPS && picHeader.trpi) + outParam->trp = picHeader.trp; + else + outParam->trp = -1; + + if (instance->fRPS && picHeader.fPLUSPTYPE && picHeader.ufep) + instance->rpsMode = picHeader.rpsMode; + + /* Store previous picture parameters temporarily */ + memcpy(&prevPictParam, pictureParam, sizeof(vdcPictureParam_t)); + + /* Update picture parameters */ + pictureParam->tr = picHeader.tr; + pictureParam->trd = trd; + pictureParam->fSplitScreenIndicator = picHeader.fSplitScreen; + pictureParam->fDocumentCameraIndicator = picHeader.fDocumentCamera; + pictureParam->fFullPictureFreezeRelease = picHeader.fFreezePictureRelease; + pictureParam->pictureType = picHeader.pictureType; + pictureParam->fPLUSPTYPE = picHeader.fPLUSPTYPE; + pictureParam->cpm = picHeader.cpm; + pictureParam->psbi = picHeader.psbi; + + if (fPBFrame) { + pictureParam->trb = picHeader.trb; + pictureParam->dbquant = picHeader.dbquant; + } + + if (!picHeader.fPLUSPTYPE || picHeader.ufep) { + pictureParam->lumWidth = picHeader.lumWidth; + pictureParam->lumHeight = picHeader.lumHeight; + pictureParam->fUMV = picHeader.fUMV; + pictureParam->fSAC = picHeader.fSAC; + pictureParam->fAP = picHeader.fAP; + + if (pictureParam->lumWidth % 16) + pictureParam->lumMemWidth = + (pictureParam->lumWidth / 16 + 1) * 16; + else + pictureParam->lumMemWidth = pictureParam->lumWidth; + + if (pictureParam->lumHeight % 16) + pictureParam->lumMemHeight = (pictureParam->lumHeight / 16 + 1) * 16; + else + pictureParam->lumMemHeight = pictureParam->lumHeight; + + if (picHeader.lumHeight <= 400) + pictureParam->numMBLinesInGOB = 1; + else if (picHeader.lumHeight <= 800) + pictureParam->numMBLinesInGOB = 2; + else + pictureParam->numMBLinesInGOB = 4; + + pictureParam->numMBsInMBLine = pictureParam->lumMemWidth / 16; + + { + int + numMBLines = pictureParam->lumMemHeight / 16, + numMBLinesInLastGOB = + numMBLines % pictureParam->numMBLinesInGOB; + + if (numMBLinesInLastGOB) { + pictureParam->numGOBs = + numMBLines / pictureParam->numMBLinesInGOB + 1; + pictureParam->fLastGOBSizeDifferent = 1; + pictureParam->numMBsInLastGOB = + numMBLinesInLastGOB * pictureParam->numMBsInMBLine; + } + else { + pictureParam->numGOBs = + numMBLines / pictureParam->numMBLinesInGOB ; + pictureParam->fLastGOBSizeDifferent = 0; + pictureParam->numMBsInLastGOB = + pictureParam->numMBLinesInGOB * pictureParam->numMBsInMBLine; + } + } + + pictureParam->numMBsInGOB = + pictureParam->numMBsInMBLine * pictureParam->numMBLinesInGOB; + } + + else { + pictureParam->lumWidth = prevPictParam.lumWidth; + pictureParam->lumHeight = prevPictParam.lumHeight; + pictureParam->lumMemWidth = prevPictParam.lumMemWidth; + pictureParam->lumMemHeight = prevPictParam.lumMemHeight; + pictureParam->fUMV = prevPictParam.fUMV; + pictureParam->fSAC = prevPictParam.fSAC; + pictureParam->fAP = prevPictParam.fAP; + } + + /* Note: Mode inference rules defined in section 5.1.4.5 of + the H.263 recommendation are (in most cases) not reflected to members + of pictureParam due to the fact that they are implicitly turned + off or irrelevant in the current implementation. (This is particularly + true when assigning inferred state "off".) */ + + if (picHeader.fPLUSPTYPE) { + pictureParam->fRPR = picHeader.fRPR; + pictureParam->fRRU = picHeader.fRRU; + pictureParam->rtype = picHeader.rtype; + + /* Note: irrelevant if Annex O is not in use */ + pictureParam->elnum = picHeader.elnum; + + if (picHeader.ufep) { + pictureParam->fCustomSourceFormat = picHeader.fCustomSourceFormat; + pictureParam->fAIC = picHeader.fAIC; + pictureParam->fDF = picHeader.fDF; + pictureParam->fSS = picHeader.fSS; + pictureParam->fRPS = picHeader.fRPS; + pictureParam->fISD = picHeader.fISD; + pictureParam->fAIV = picHeader.fAIV; + pictureParam->fMQ = picHeader.fMQ; + + pictureParam->fUMVLimited = picHeader.fUMVLimited; + + } + + /* Else no UFEP */ + else { + pictureParam->fCustomSourceFormat = + prevPictParam.fCustomSourceFormat; + pictureParam->fAIC = prevPictParam.fAIC; + pictureParam->fDF = prevPictParam.fDF; + pictureParam->fSS = prevPictParam.fSS; + pictureParam->fRPS = prevPictParam.fRPS; + pictureParam->fISD = prevPictParam.fISD; + pictureParam->fAIV = prevPictParam.fAIV; + pictureParam->fMQ = prevPictParam.fMQ; + + pictureParam->fUMVLimited = prevPictParam.fUMVLimited; + + } + } + + /* Else no PLUSPTYPE */ + else { + /* Section 5.1.4.5 of the H.263 recommendation states: + "If a picture is sent which does not contain (PLUSPTYPE), + a state "off" shall be assigned to all modes not explicitly set to + "on" in the PTYPE filed, and all modes shall continue to have + an inferred state of "off" until a new picture containing + the optional part of PLUSPTYPE is sent." */ + + /* Fields occuring in mandatory part of PLUSPTYPE are copied from + the previous picture. */ + pictureParam->fRPR = prevPictParam.fRPR; + pictureParam->fRRU = prevPictParam.fRRU; + + /* RTYPE is set to zero according to section 6.1.2 of + the H.263 recommendation */ + pictureParam->rtype = 0; + + /* Modes occuring in the optional part of PLUSPTYPE are turned off + (unless occuring in PTYPE field too, like Advanced Prediction). */ + pictureParam->fCustomSourceFormat = 0; + pictureParam->fCustomPCF = 0; + pictureParam->fAIC = 0; + pictureParam->fDF = 0; + pictureParam->fSS = 0; + pictureParam->fRPS = 0; + pictureParam->fISD = 0; + pictureParam->fAIV = 0; + pictureParam->fMQ = 0; + + /* Other related settings turned off just to be sure that they are + not misused. */ + pictureParam->fUMVLimited = 0; + } + + pictureParam->fMVsOverPictureBoundaries = + (pictureParam->fUMV || pictureParam->fAP || + pictureParam->fDF); + + /* Initialize motion vector count module */ + mvcStart( &instance->mvcData, + instance->pictureParam.lumMemWidth / 16 - 1, + pictureParam->lumMemWidth, + pictureParam->lumMemHeight, &error); + /* Note: This assumes that the memory for frame->mvcData is filled with 0 + in the first time the function is called. + (This is ensured by setting the instance data to zero when it is + initialized in vdcOpen.) */ + instance->mvcData.fSS = pictureParam->fSS; + + if (error) { + deb("mvcStart failed.\n"); + return DPH_ERR; + } + + /* Get image buffers */ + { + vdeIms_t *store = instance->imageStore; + vdeImsItem_t *imsItem; + vdeImb_t *imb; + int width, height; + + vdeImsSetYUVNeed(store, inParam->fNeedDecodedFrame); + + if (vdeImsGetFree(store, instance->pictureParam.lumMemWidth, + instance->pictureParam.lumMemHeight, + &instance->currFrame) < 0) + goto errGetFreeP; + imsItem = instance->currFrame; + + + if (vdeImsStoreItemToImageBuffer(imsItem, &imb) < 0) + goto errAfterGetFreeP; + + if (vdeImbYUV(imb, &outParam->currYFrame, + &outParam->currUFrame, &outParam->currVFrame, + &width, &height) < 0) + goto errAfterGetFreeP; + + } + + /* Initialize the parameters for the advanced intra coding structure. */ + if (pictureParam->fAIC) + { + // not supported + } + + /* Initialize the parameters for Slice Structured Mode. */ + if (pictureParam->fSS) + { + // not supported + } + + + /* If picture header successfully decoded or reliably recovered */ + if ( inParam->fReadBits && ret == VDX_OK ) { + + /* In the beginning, tr is set to -1 */ + if ( instance->fPrevPicHeaderReliable + && instance->prevPicHeader->tr >= 0 + && ( picHeader.pictureType != instance->prevPicHeader->pictureType + || picHeader.fUMV != instance->prevPicHeader->fUMV + || picHeader.fAP != instance->prevPicHeader->fAP + || picHeader.fPLUSPTYPE != instance->prevPicHeader->fPLUSPTYPE + || ( ( picHeader.fPLUSPTYPE == 0 || picHeader.ufep == 1 ) + && ( picHeader.lumWidth != instance->prevPicHeader->lumWidth + || picHeader.lumHeight != instance->prevPicHeader->lumHeight ) + ) + || ( picHeader.fPLUSPTYPE == 1 && picHeader.ufep == 1 + && ( picHeader.fAIC != instance->prevPicHeader->fAIC + || picHeader.fDF != instance->prevPicHeader->fDF + || picHeader.fMQ != instance->prevPicHeader->fMQ + || picHeader.fUMVLimited != instance->prevPicHeader->fUMVLimited + ) + ) + ) + || ( picHeader.fPLUSPTYPE == 1 + && picHeader.rtype != instance->prevPicHeader->rtype ) + ) { + + /* Some parameter in PTYPE/PLUSPTYPE has changed, GFID should change also */ + /* Note that some parameters, such as SAC, are not checked since they have not been implemented */ + + instance->fGFIDShouldChange = 1; + } + else if ( !instance->fPrevPicHeaderReliable ) { + /* Previous picture header was not reliable, don't check GFID */ + instance->fGFIDShouldChange = 1; + instance->gfid = -1; + } + else if ( instance->gfid == -1 ) { + /* The very first frame, or a frame after a lost frame, GFID can be whatever */ + /* Note: instance->gfid == -1 is used to indicate that previous GFID + is not available as in the first picture in first GOB header. + If there is a picture without GOB headers and having a different + picture header than the surrounding pictures, instance->gfid is + reset to -1 in vdcDecodeFrame()! (Otherwise, a wrong GFID may be + used in GFID correctness check.) */ + instance->fGFIDShouldChange = 1; + } + else { + /* No changes in PTYPE => the same GFID. + * It is better not to change the value of this flag here, since + * if there are no GOB or slice headers where GFID can change, the next + * read GFID in some other frame than the one with the different PTYPE + * will be considered illegal + */ + /* instance->fGFIDShouldChange = 0; */ + } + + /* Header was reliable and can be used when checking the next header */ + instance->fPrevPicHeaderReliable = 1; + + /* Copy the read header to be used if the next header is corrupted or lost */ + memcpy( instance->prevPicHeader, &picHeader, sizeof( vdxPictureHeader_t ) ); + } + + /* Else picture header unreliable */ + else { + /* Since we cannot trust that picture header is reliable, + we cannot detect errors based on GFID. + Thus, let's disable GFID checking in GOB level. */ + instance->fPrevPicHeaderReliable = 0; + instance->fGFIDShouldChange = 1; + instance->gfid = -1; + } + + return retVal; + + /* Error condition handling, + release everything in reverse order */ +// errAfterGetFreeB: + +// vdeImsPutFree(instance->imageStore, instance->bFrame); +// errGetFreeB: + + errAfterGetFreeP: + + vdeImsPutFree(instance->imageStore, instance->currFrame); + errGetFreeP: + + instance->currFrame = NULL; + instance->bFrame = NULL; + + return DPH_ERR; +} + + +/* {{-output"dphGetSEI.txt"}} */ +/* + * dphGetSEI + * + * + * Parameters: + * vdcInstance Video Decoder Core instance + * inBuffer Bit Buffer instance + * bitErrorIndication bit error indication, see biterr.h for + * the possible values + * + * Function: + * This function gets and decodes Supplemental Enhancement + * Information. + * + * Returns: + * >= 0 the function was successful + * < 0 an error occured + * + */ + +int dphGetSEI( + vdcInstance_t *vdcInstance, /* Video Decoder Core instance */ + bibBuffer_t *inBuffer, /* Bit Buffer instance */ + int *bitErrorIndication) +{ +/* {{-output"dphGetSEI.txt"}} */ + int + vdxStatus; + + vdxSEI_t + sei; + + vdxStatus = vdxGetAndParseSEI( + inBuffer, + vdcInstance->pictureParam.fPLUSPTYPE, + vdcInstance->numAnnexNScalabilityLayers, + &sei, + bitErrorIndication); + + if (vdxStatus < 0) + return DPH_ERR; + else if (vdxStatus == VDX_OK_BUT_BIT_ERROR) + return DPH_OK_BUT_BIT_ERROR; + + + return DPH_OK; +} +// End of File