diff -r 000000000000 -r 951a5db380a0 videoeditorengine/h263decoder/src/decvp_mpeg.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/videoeditorengine/h263decoder/src/decvp_mpeg.cpp Fri Jan 29 14:08:33 2010 +0200 @@ -0,0 +1,653 @@ +/* +* 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: +* Video packet decoding module (MPEG-4). +* +*/ + + +/* + * Includes + */ +#include "h263dConfig.h" +#include "decvp_mpeg.h" +#include "block.h" +#include "debug.h" +#include "decmbs.h" +#include "stckheap.h" +#include "sync.h" +#include "viddemux.h" +#include "biblin.h" +/* MVE */ +#include "MPEG4Transcoder.h" + +/* + * Global functions + */ + +/* {{-output"dvpGetAndDecodeVideoPacketHeader.txt"}} */ +/* + * dvpGetAndDecodeVideoPacketHeader + * + * + * Parameters: + * inParam input parameters + * inOutParam input/output parameters, these parameters + * may be modified in the function + * + * Function: + * This function gets and decodes a Video Packet header at the + * current position of the bit buffer. It checks its correctness and + * if it fits to the sequence of VPs, and does the necessary actions for + * correction. + * + * Returns: + * >= 0 the function was successful + * < 0 an error occured + * + */ + +int dvpGetAndDecodeVideoPacketHeader( + const dvpVPInParam_t *inParam, + dvpVPInOutParam_t *inOutParam) +/* {{-output"dvpGetAndDecodeVideoPacketHeader.txt"}} */ +{ + int16 error = 0; + vdxGetVideoPacketHeaderInputParam_t vdxParam; + vdxVideoPacketHeader_t header; + bibBuffer_t *inBuffer = inParam->inBuffer; + int bitErrorIndication = 0, retVal, fLostSegment = FALSE; + + /* + * Get VP header + */ + + vdxParam.fcode_forward = inParam->pictParam->fcode_forward; + vdxParam.time_increment_resolution = inParam->pictParam->time_increment_resolution; + vdxParam.numOfMBs = inParam->pictParam->numMBsInGOB; + + retVal = vdxGetVideoPacketHeader(inBuffer, &vdxParam, &header, &bitErrorIndication); + if (retVal < 0) { + return DGOB_ERR; + } else if (retVal > 0) { + deb("dvpGetAndDecodeVideoPacketHeader: ERROR - vdxGetVideoPacketHeader failed.\n"); + goto headerFailure; + } + + + /* + * Check header validity + */ + + if (header.currMBNum == 0 || header.currMBNum >= inParam->pictParam->numMBsInGOB) { + deb("dvpGetAndDecodeVideoPacketHeader: ERROR - too big currMBNum.\n"); + goto headerFailure; + } + + /* quant can not be zero */ + if(header.quant == 0) { + goto headerFailure; + } + + if (header.fHEC) { + + if (header.time_base_incr < 0 || header.time_base_incr > 60) { + if (bitErrorIndication) { + goto headerFailure; + } + } + + /* fcode can have only the valid values 1..7 */ + if (header.coding_type == VDX_VOP_TYPE_P) + if (header.fcode_forward == 0) { + goto headerFailure; + } + + if (!inParam->fVOPHeaderCorrupted) { + + if ((inParam->pictParam->pictureType != header.coding_type) || + (inParam->pictParam->time_base_incr != header.time_base_incr) || + (inParam->pictParam->time_inc != header.time_inc)) { + deb("dvpGetAndDecodeVideoPacketHeader: ERROR - Parameter change VOP<->VP header.\n"); + goto headerFailure; + } + } + } + if (inParam->fVOPHeaderCorrupted) { + /* Get the coding type parameter since it is needed in the concealment before the other updates */ + if (header.fHEC) { + inParam->pictParam->pictureType = header.coding_type; + } + } + if (header.currMBNum != inOutParam->currMBNum) { + if ( header.currMBNum > inOutParam->currMBNum && bitErrorIndication == 0) { + + fLostSegment = TRUE; + goto headerFailure; + + } else if (header.currMBNum < inOutParam->currMBNum) { + deb("dvpGetAndDecodeVideoPacketHeader: ERROR - MB counting is out of sync.\n"); + goto headerFailure; + } + } + + /* + * Update parameters + */ + + inOutParam->currMBNum = header.currMBNum; + inOutParam->quant = header.quant; + + if (inParam->fVOPHeaderCorrupted) { + if (header.fHEC) { + inParam->pictParam->mod_time_base += inParam->pictParam->time_base_incr = header.time_base_incr; + + inParam->pictParam->time_inc = header.time_inc; + + inOutParam->frameNum = (int) ((inParam->pictParam->mod_time_base + + ((double) header.time_inc) / ((double) inParam->pictParam->time_increment_resolution)) * + 30.0 + 0.001); + + inParam->pictParam->tr = inOutParam->frameNum % 256; + inParam->pictParam->pictureType = header.coding_type; + + inParam->pictParam->intra_dc_vlc_thr = header.intra_dc_vlc_thr; + + if (header.coding_type == VDX_VOP_TYPE_P) + if (inParam->pictParam->fcode_forward != header.fcode_forward) { + /* Initialize once to count parameters for the mvc module */ + int r_size, scale_factor; + + inParam->pictParam->fcode_forward = header.fcode_forward; + + inOutParam->mvcData->f_code = inParam->pictParam->fcode_forward; + r_size = inParam->pictParam->fcode_forward - 1; + scale_factor = (1 << r_size); + inOutParam->mvcData->range = 160 * scale_factor; + } + } else { + /* seek next PSC, VP start code is not good enough */ + sncRewindAndSeekNewMPEGSync(-1, inBuffer, 0, &error); + return DGOB_OK_BUT_BIT_ERROR; + } + } + + if (fLostSegment) + return DGOB_OK_BUT_BIT_ERROR; + else + return DGOB_OK; + + headerFailure: + sncRewindAndSeekNewMPEGSync(-1, inBuffer, inParam->pictParam->fcode_forward, &error); + + if (error && error != ERR_BIB_NOT_ENOUGH_DATA) + return DGOB_ERR; + return DGOB_OK_BUT_BIT_ERROR; +} + + +/* {{-output"dvpGetAndDecodeVideoPacketContents.txt"}} */ +/* + * dvpGetAndDecodeVideoPacketContents + * + * + * Parameters: + * inParam input parameters + * fGetNewReferenceFrame non-zero if a new reference frame must be + * requested from the image store, otherwise 0 + * inOutParam input/output parameters, these parameters + * may be modified in the function + * + * Function: + * This function gets and decodes the contents of a Video Packet + * after the header of the VP (either VP header or picture + * header) is already got and processed. It works MB-by-MB or if VP + * is data partitioned calls the corresponding decoding functions. + * Error concealment for the missing (not decodable) MBs in a P-frame + * is called. + * + * Returns: + * >= 0 the function was successful + * < 0 an error occured + * + */ + +int dvpGetAndDecodeVideoPacketContents( + const dvpVPInParam_t *inParam, + int fGetNewReferenceFrame, + dvpVPInOutParam_t *inOutParam, CMPEG4Transcoder *hTranscoder) +/* {{-output"dvpGetAndDecodeVideoPacketContents.txt"}} */ +{ + int16 error = 0; + int bitErrorIndication = 0; + dmbPFrameMBInParam_t dpmbi; + dmbPFrameMBInOutParam_t dpmbio; + dmbIFrameMBInParam_t dimbi; + dmbIFrameMBInOutParam_t dimbio; + int yPosInMBs, xPosInMBs = 0; + bibBuffer_t *inBuffer; + bibBuffer_t + *outBuffer; /* Output bit buffer instance */ + + bibBufferEdit_t + *bufEdit; + + int colorEffect; + TBool getDecodedFrame; + + + int fSegmentCorrupted = 0; + + int dmbRetValue; + int sncCode = SNC_NO_SYNC; + int lastMBNumInVP = 0; + int startMB = inOutParam->currMBNum; + + SOH_DEFINE(blcDiffMB_t, pDiffMB); /* Storage for the previous difference blocks */ + + SOH_ALLOC(blcDiffMB_t, pDiffMB); + + if (pDiffMB == NULL) { + deb("dvpGetAndDecodeVideoPacketContents: SOH_ALLOC failed.\n"); + goto unexpectedError; + } + + pDiffMB->cbpy = 0; + + inBuffer = inParam->inBuffer; + outBuffer = inParam->outBuffer; + bufEdit = inParam->bufEdit; + colorEffect = inParam->iColorEffect; + getDecodedFrame = inParam->iGetDecodedFrame; + + /* If the reference frame changed */ + if (fGetNewReferenceFrame) { + vdeIms_t *store = inOutParam->imageStore; + vdeImsItem_t *imsItem; + vdeImb_t *imb; + int width, height; + + if (vdeImsGetReference(store, VDEIMS_REF_LATEST, 0, &imsItem) < 0) { + deb("dvpGetAndDecodeVideoPacketContents: ERROR - vdeImsGetReference " + "failed.\n"); + goto unexpectedError; + } + + /* If no reference frame available */ + if (!imsItem) { + /* Treat the situation like a decoding error.*/ + deb("dvpGetAndDecodeVideoPacketContents: Warning - no reference frame " + "available.\n"); + goto headerFailure; + } + + if (vdeImsStoreItemToImageBuffer(imsItem, &imb) < 0) { + deb("dvpGetAndDecodeVideoPacketContents: ERROR - vdeImsStoreItemToImageBuffer " + "failed.\n"); + goto unexpectedError; + } + + if (vdeImbYUV(imb, &inOutParam->refY, &inOutParam->refU, + &inOutParam->refV, &width, &height) < 0) { + deb("dvpGetAndDecodeVideoPacketContents: ERROR - vdeImbYUV " + "failed.\n"); + goto unexpectedError; + } + } + + xPosInMBs = (inOutParam->currMBNum % inParam->pictParam->numMBsInMBLine); + yPosInMBs = (inOutParam->currMBNum / inParam->pictParam->numMBsInMBLine); + + /* if VOP header corrupted and first VP -> exit */ + if(inParam->fVOPHeaderCorrupted && inOutParam->currMBNum==0) { + fSegmentCorrupted = 1; + goto exitWhenVOPHeaderCorrupted; + } + + /* in case of an I-VOP */ + if (inParam->pictParam->pictureType == VDX_VOP_TYPE_I) { + dimbi.inBuffer = inBuffer; + dimbi.outBuffer = outBuffer; + dimbi.bufEdit = bufEdit; + dimbi.iColorEffect = colorEffect; + dimbi.iGetDecodedFrame = getDecodedFrame; + + dimbi.pictParam = inParam->pictParam; + + dimbi.xPosInMBs = xPosInMBs; + dimbi.yPosInMBs = yPosInMBs; + + dimbio.currMBNum = inOutParam->currMBNum; + dimbio.currMBNumInVP = 0; + + dimbio.aicData = inOutParam->aicData; + + dimbio.fCodedMBs = inOutParam->fCodedMBs; + dimbio.numOfCodedMBs = inOutParam->numOfCodedMBs; + dimbio.quant = inOutParam->quant; + + /* YUV pointers */ + { + int32 yOffset, uvOffset; + + yOffset = inParam->pictParam->lumMemWidth * dimbi.yPosInMBs + dimbi.xPosInMBs; + uvOffset = (inParam->pictParam->lumMemWidth >> 1) * dimbi.yPosInMBs + dimbi.xPosInMBs; + + if ( inOutParam->currPY != NULL ) + { + dimbio.yMBInFrame = inOutParam->currPY + (yOffset << 4); + dimbio.uBlockInFrame = inOutParam->currPU + (uvOffset << 3); + dimbio.vBlockInFrame = inOutParam->currPV + (uvOffset << 3); + } + else + { + dimbio.yMBInFrame = NULL; + dimbio.uBlockInFrame = NULL; + dimbio.vBlockInFrame = NULL; + } + } + } + /* in case of a P-VOP */ + else { + dpmbi.inBuffer = inBuffer; + dpmbi.outBuffer = outBuffer; + dpmbi.bufEdit = bufEdit; + dpmbi.iColorEffect = colorEffect; + dpmbi.iGetDecodedFrame = getDecodedFrame; + + dpmbi.pictParam = inParam->pictParam; + + dpmbi.xPosInMBs = xPosInMBs; + dpmbi.yPosInMBs = yPosInMBs; + + dpmbi.refY = inOutParam->refY; + dpmbi.refU = inOutParam->refU; + dpmbi.refV = inOutParam->refV; + dpmbi.currPY = inOutParam->currPY; + dpmbi.currPU = inOutParam->currPU; + dpmbi.currPV = inOutParam->currPV; + + dpmbio.currMBNum = inOutParam->currMBNum; + dpmbio.currMBNumInVP = 0; + + dpmbio.fCodedMBs = inOutParam->fCodedMBs; + dpmbio.numOfCodedMBs = inOutParam->numOfCodedMBs; + dpmbio.quant = inOutParam->quant; + + dpmbio.aicData = inOutParam->aicData; + + dpmbio.mvcData = inOutParam->mvcData; + dpmbio.diffMB = pDiffMB; + + /* YUV pointers */ + { + int32 yOffset, uvOffset; + + yOffset = inParam->pictParam->lumMemWidth * dpmbi.yPosInMBs + dpmbi.xPosInMBs; + uvOffset = (inParam->pictParam->lumMemWidth >> 1) * dpmbi.yPosInMBs + dpmbi.xPosInMBs; + + if ( inOutParam->currPY != NULL ) + { + dpmbio.yMBInFrame = inOutParam->currPY + (yOffset << 4); + dpmbio.uBlockInFrame = inOutParam->currPU + (uvOffset << 3); + dpmbio.vBlockInFrame = inOutParam->currPV + (uvOffset << 3); + } + else + { + dimbio.yMBInFrame = NULL; + dimbio.uBlockInFrame = NULL; + dimbio.vBlockInFrame = NULL; + } + } + } + + /* Decode multiple Macroblocks until a resync_marker is found or error occurs */ + while (inParam->pictParam->numMBsInGOB != inOutParam->currMBNum && + sncCode != SNC_VIDPACK && sncCode != SNC_VOP) { + + /* MVE */ + hTranscoder->BeginOneMB((inParam->pictParam->pictureType == VDX_VOP_TYPE_I) ? dimbio.currMBNum : dpmbio.currMBNum ); + + /* decode an I-frame MB */ + if (inParam->pictParam->pictureType == VDX_VOP_TYPE_I) { + + if(inParam->pictParam->data_partitioned) { + + dmbRetValue = dmbsGetAndDecodeIMBsDataPartitioned(&dimbi, &dimbio, + inOutParam->quantParams, hTranscoder); + + if (dmbRetValue < 0) + goto unexpectedError; + + inOutParam->currMBNum = dimbio.currMBNum; + + /* Video Packet corrupted */ + if ( fSegmentCorrupted ) + break; + + } else { + + dmbRetValue = dmbGetAndDecodeIFrameMB(&dimbi, &dimbio, 1, hTranscoder); + + if (dmbRetValue < 0) + goto unexpectedError; + else if (dmbRetValue == DMB_BIT_ERR ) { + /* Video Packet corrupted */ + fSegmentCorrupted = 1; + break; + } + + /* Store quantizer */ + inOutParam->quantParams[dimbio.currMBNum] = dimbio.quant; + + /* increment the frame pointers and MB counters */ + dimbio.currMBNum++; + dimbio.currMBNumInVP++; + + if ( dimbio.yMBInFrame != NULL ) + { + dimbio.yMBInFrame += 16; + dimbio.uBlockInFrame += 8; + dimbio.vBlockInFrame += 8; + } + dimbi.xPosInMBs++; + + if (dimbi.xPosInMBs == inParam->pictParam->numMBsInMBLine) { + if ( dimbio.yMBInFrame != NULL ) + { + dimbio.yMBInFrame += 15 * inParam->pictParam->lumMemWidth; + dimbio.uBlockInFrame += 7 * (inParam->pictParam->lumMemWidth >> 1); + dimbio.vBlockInFrame += 7 * (inParam->pictParam->lumMemWidth >> 1); + } + dimbi.xPosInMBs = 0; + dimbi.yPosInMBs++; + } + + inOutParam->currMBNum = dimbio.currMBNum; + } + + /* decode a P-frame MB */ + } else { + + if(inParam->pictParam->data_partitioned) { + + dmbRetValue = dmbsGetAndDecodePMBsDataPartitioned(&dpmbi, &dpmbio, + inOutParam->quantParams, hTranscoder); + + if (dmbRetValue < 0) + goto unexpectedError; + + inOutParam->currMBNum = dpmbio.currMBNum; + lastMBNumInVP = dpmbio.currMBNumInVP; + + /* Video Packet corrupted */ + if ( fSegmentCorrupted ) + break; + + } else { + + dmbRetValue = dmbGetAndDecodePFrameMB(&dpmbi, &dpmbio, 1, hTranscoder); + + if (dmbRetValue < 0) + goto unexpectedError; + else if (dmbRetValue == DMB_BIT_ERR ) { + /* Video Packet corrupted */ + fSegmentCorrupted = 1; + break; + } + + /* Store quantizer */ + inOutParam->quantParams[dpmbio.currMBNum] = dpmbio.quant; + + /* increment the frame pointers and MB counters */ + dpmbio.currMBNum++; + dpmbio.currMBNumInVP++; + + if ( dpmbio.yMBInFrame != NULL ) + { + dpmbio.yMBInFrame += 16; + dpmbio.uBlockInFrame += 8; + dpmbio.vBlockInFrame += 8; + } + dpmbi.xPosInMBs++; + + if (dpmbi.xPosInMBs == inParam->pictParam->numMBsInMBLine) { + if ( dpmbio.yMBInFrame != NULL ) + { + dpmbio.yMBInFrame += 15 * inParam->pictParam->lumMemWidth; + dpmbio.uBlockInFrame += 7 * (inParam->pictParam->lumMemWidth >> 1); + dpmbio.vBlockInFrame += 7 * (inParam->pictParam->lumMemWidth >> 1); + } + dpmbi.xPosInMBs = 0; + dpmbi.yPosInMBs++; + } + + inOutParam->currMBNum = dpmbio.currMBNum; + } + } + + /* check for a resync_marker */ + sncCode = sncCheckMpegSync(inBuffer, inParam->pictParam->fcode_forward, &error); + + /* If sncCheckMpegSync failed */ + if (error && error != ERR_BIB_NOT_ENOUGH_DATA) { + deb1p("dvpGetAndDecodeVideoPacketContents: ERROR - sncCheckSync returned %d.\n", error); + goto unexpectedError; + + } else + /* If buffer ends (in one-frame-per-one-buffer case) */ + if (sncCode == SNC_EOB || + sncCode == SNC_STUFFING || + error == ERR_BIB_NOT_ENOUGH_DATA) { + break; + } + + } + + +// <-- + + inOutParam->numOfCodedMBs = (inParam->pictParam->pictureType != VDX_VOP_TYPE_I) ? + dpmbio.numOfCodedMBs : dimbio.numOfCodedMBs; + + if (fSegmentCorrupted) { + u_int32 nextVPBitPos; + + /* find the next resync marker, to get the number of MBs in the current VP */ + sncCode = sncRewindAndSeekNewMPEGSync(-1, inBuffer, inParam->pictParam->fcode_forward, &error); + if (error && error != ERR_BIB_NOT_ENOUGH_DATA) { + goto unexpectedError; + } else if (sncCode == SNC_EOB) { + goto exitFunction; + } + + nextVPBitPos = bibNumberOfFlushedBits(inParam->inBuffer); + + /* if the lastMBNumInVP was not yet read */ + if (inParam->pictParam->pictureType == VDX_VOP_TYPE_I || + !inParam->pictParam->data_partitioned || + lastMBNumInVP == 0) { + + /* if VP header is found: read it, and get last MB number in current vop */ + if (sncCode == SNC_VIDPACK) { + vdxVideoPacketHeader_t header; + vdxGetVideoPacketHeaderInputParam_t vdxParam; + int retValue; + + vdxParam.fcode_forward = inParam->pictParam->fcode_forward; + vdxParam.time_increment_resolution = inParam->pictParam->time_increment_resolution; + vdxParam.numOfMBs = inParam->pictParam->numMBsInGOB; + + retValue = vdxGetVideoPacketHeader(inParam->inBuffer, &vdxParam, &header, &bitErrorIndication); + if (retValue < 0) { + goto unexpectedError; + } else if (retValue == VDX_OK_BUT_BIT_ERROR) { + /* If bit error occurred */ + goto headerFailure; + } + + /* rewind the bits to the beginning of the VP header */ + bibRewindBits(bibNumberOfFlushedBits(inParam->inBuffer) - nextVPBitPos, + inParam->inBuffer, &error); + + lastMBNumInVP = header.currMBNum; + + } else { + lastMBNumInVP = inParam->pictParam->numMBsInGOB; + } + } + + /* if possibly the next VP header is damaged (it gives MB index which is smaller than the start of the current one */ + if (lastMBNumInVP <= startMB || lastMBNumInVP > inParam->pictParam->numMBsInGOB) + goto exitFunction; + + /* if the MB counting due to error overran the next VP header's value */ + if (inOutParam->currMBNum > lastMBNumInVP) + inOutParam->currMBNum = VDC_MAX(lastMBNumInVP-3,startMB); + + /* if not all the MBs have been predicted due to error */ + else if (inOutParam->currMBNum < lastMBNumInVP) + inOutParam->currMBNum = VDC_MAX(inOutParam->currMBNum-1,startMB); + + + inOutParam->currMBNum = lastMBNumInVP; + } + + exitFunction: + + + exitWhenVOPHeaderCorrupted: + + if (!fSegmentCorrupted) { + SOH_DEALLOC(pDiffMB); + return DGOB_OK; + } + else { + SOH_DEALLOC(pDiffMB); + return DGOB_OK_BUT_BIT_ERROR; + } + + headerFailure: + SOH_DEALLOC(pDiffMB); + sncRewindAndSeekNewMPEGSync(-1, inBuffer, 0, &error); + if (error && error != ERR_BIB_NOT_ENOUGH_DATA) + return DGOB_ERR; + return DGOB_OK_BUT_BIT_ERROR; + + unexpectedError: + SOH_DEALLOC(pDiffMB); + return DGOB_ERR; +} +// End of File