diff -r 000000000000 -r 951a5db380a0 videoeditorengine/h263decoder/src/core_mpeg.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/videoeditorengine/h263decoder/src/core_mpeg.cpp Fri Jan 29 14:08:33 2010 +0200 @@ -0,0 +1,671 @@ +/* +* 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: +* MPEG-4 decoder core functions. +* +*/ + + +/* + * Includes + */ +#include "h263dConfig.h" +#include "vdc263.h" +#include "core.h" +#include "debug.h" +#include "decblock.h" /* for dblFree and dblLoad */ +#include "decvp_mpeg.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" +/* MVE */ +#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_VIDEO_PACKET, + EDP_END_OF_FRAME +} vdcExpectedDecodingPosition_t; + + +/* + * Local function prototypes + */ + +extern int vdcFillImageBuffers( + vdcInstance_t *instance, + int numOfCodedMBs, + vdeImb_t *imbP); + + +/* + * Global functions + */ + +/* {{-output"vdcDecodeMPEGVolHeader.txt"}} */ +/* + * vdcDecodeMPEGVolHeader + * + * + * Parameters: + * None. + * + * Function: + * This function reads the VOL Header and updates the instance data + * with the read parameters. + * + * Returns: + * >= 0 if succeeded + * < 0 if failed + * + */ + +int vdcDecodeMPEGVolHeader(vdcHInstance_t hInstance, bibBuffer_t *inBuffer, CMPEG4Transcoder *hTranscoder) +/* {{-output"vdcDecodeMPEGVolHeader.txt"}} */ +{ + dphInOutParam_t pichInOut; + int headerSuccess = 0; + + pichInOut.vdcInstance = (vdcInstance_t *) hInstance; + pichInOut.inBuffer = inBuffer; + + headerSuccess = dphGetMPEGVolHeader(&pichInOut, hTranscoder); + if (headerSuccess != 0) + return VDC_ERR; + else + return VDC_OK; +} + + +/* {{-output"vdcDecodeMPEGVop.txt"}} */ +/* + * vdcDecodeMPEGVop + * + * + * Parameters: + * hInstance handle of instance data + * + * inBuffer pointer to bit buffer, the current position + * of the buffer must start with a PSC + * + * Function: + * The vdcDecodeMPEGVop function implements the decoding process of the MPEG-4 + * Simple Video Object described in ISO/IEC 14496-2. + * + * The function decodes the next frame in the buffer (inBuffer) meaning that + * the decoding continues until the next VOP start code or EOB 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 vdcDecodeMPEGVop(vdcHInstance_t hInstance, bibBuffer_t *inBuffer, bibBuffer_t *outBuffer, + bibBufferEdit_t *bufEdit, int aColorEffect, TBool aGetDecodedFrame, + int aStartByteIndex, int aStartBitIndex, + CMPEG4Transcoder *hTranscoder) +/* {{-output"vdcDecodeMPEGVop.txt"}} */ +{ + int sncCode; /* the latest synchronization code, see + sncCheckSync for the possible values */ + + int retValue = VDC_OK; /* return value of this function */ + + int16 error = 0; + + 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 currMBNum = 0; /* Current macro block */ + + int decStatus = 0; + int corruptedVPs = 0; + int numberOfVPs = 1; + int headerSuccess = 0; + u_char fVOPHeaderCorrupted = 0, fVOPHeaderLost = 0; + + 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; + + /* Main loop */ + for (;;) { + int bitErrorIndication = 0; + + sncCode = sncCheckMpegSync(inBuffer, instance->pictureParam.fcode_forward, &error); + + /* If sncCheckSync failed */ + if (error && error != ERR_BIB_NOT_ENOUGH_DATA) { + deb1p("vdcDecodeMPEGVop: ERROR - sncCheckSync returned %d.\n", error); + retValue = VDC_ERR; + goto exitFunction; + } + + /* If EOS was got */ + if (sncCode == SNC_EOB) + instance->fEOS = 1; + + /* If frame ends appropriately */ + if (expectedDecodingPosition == EDP_END_OF_FRAME && + (sncCode == SNC_VOP || sncCode == SNC_GOV || sncCode == SNC_EOB || + 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_EOB) { + /* 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. */ + goto exitFunction; + } + + /* Else if frame starts as expected */ + else if (expectedDecodingPosition == EDP_START_OF_FRAME && + ((sncCode == SNC_GOV) || (sncCode == SNC_VOP) || fVOPHeaderLost)) { + + dphInParam_t pichIn; + dphInOutParam_t pichInOut; + dphOutParam_t pichOut; + + if (sncCode == SNC_GOV) { + vdxGovHeader_t govHeader; + + headerSuccess = vdxGetGovHeader(inBuffer, &govHeader, &bitErrorIndication); + if ( headerSuccess < 0) { + retValue = VDC_ERR; + goto exitFunction; + } else if (( headerSuccess > 0 ) || + (govHeader.time_stamp < instance->pictureParam.mod_time_base) || + (govHeader.time_stamp - instance->pictureParam.mod_time_base > 60)) { + + if(sncCheckMpegVOP(inBuffer, &error) != SNC_PSC) { + retValue = VDC_OK_BUT_FRAME_USELESS; + goto exitFunction; + } + + } else { + instance->pictureParam.mod_time_base = govHeader.time_stamp; + + /* copying the user data */ + if (govHeader.user_data != NULL) { + + if (!instance->user_data) + instance->user_data = (char *) vdcMalloc( + MAX_USER_DATA_LENGTH); + + govHeader.user_data_length = + ((instance->user_data_length + govHeader.user_data_length) >= MAX_USER_DATA_LENGTH) ? + (MAX_USER_DATA_LENGTH - instance->user_data_length) : govHeader.user_data_length; + memcpy( + instance->user_data + instance->user_data_length, + govHeader.user_data, + govHeader.user_data_length); + instance->user_data_length += govHeader.user_data_length; + + vdcDealloc(govHeader.user_data); + } + + } + } + + /* Start VOP decoding */ + pichIn.fReadBits = (fVOPHeaderLost ? 0 : 1); + pichIn.fNeedDecodedFrame = aGetDecodedFrame | hTranscoder->NeedDecodedYUVFrame(); + pichInOut.vdcInstance = instance; + pichInOut.inBuffer = inBuffer; + + /* Get VOP header */ + headerSuccess = dphGetMPEGVopHeader(&pichIn, &pichInOut, &pichOut, &bitErrorIndication); + + deb1p("vdcDecodeMPEGVop: frameNum %d.\n", instance->frameNum); + if ( headerSuccess < 0) { + retValue = VDC_ERR; + goto exitFunction; + } else if ( headerSuccess > 0 ) { + + if (headerSuccess == DPH_OK_BUT_BIT_ERROR) { + /* find the next resync marker, to get the number of MBs in the current VP */ + sncCode = sncRewindAndSeekNewMPEGSync(-1, inBuffer, instance->pictureParam.fcode_forward, &error); + if (error && error != ERR_BIB_NOT_ENOUGH_DATA) { + retValue = VDC_ERR; + goto exitFunction; + } + + if (sncCode == SNC_VIDPACK) { + fVOPHeaderCorrupted = 1; + } else { + retValue = VDC_OK_BUT_FRAME_USELESS; + goto exitFunction; + } + + } else if (headerSuccess == DPH_OK_BUT_NOT_CODED) { + + /* MVE */ + /* copy VOP header to output buffer in case VOP is not coded, including the GOV */ + bufEdit->copyMode = CopyWhole; /* copyWhole */ + CopyStream(inBuffer,outBuffer,bufEdit, aStartByteIndex, aStartBitIndex); + + /* behaves the same as if the frame was useless, but it's just not coded */ + retValue = VDC_OK_BUT_NOT_CODED; + goto exitFunction; + } + } + + + currYFrame = pichOut.currYFrame; + currUFrame = pichOut.currUFrame; + currVFrame = pichOut.currVFrame; + + currMBNum = 0; + + numOfCodedMBs = 0; + fCodedMBs = renDriCodedMBs(instance->currFrame->imb->drawItem); + memset(fCodedMBs, 0, renDriNumOfMBs( + instance->currFrame->imb->drawItem) * sizeof(u_char)); + + /* Initialize quantization parameter array */ + quantParams = instance->currFrame->imb->yQuantParams; + memset(quantParams, 0, renDriNumOfMBs( + instance->currFrame->imb->drawItem) * 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); + } + + /* Decode the 1st VP segment */ + { + dvpVPInParam_t dvpi; + dvpVPInOutParam_t dvpio; + + dvpi.pictParam = &instance->pictureParam; + dvpi.inBuffer = inBuffer; + dvpi.outBuffer = outBuffer; + dvpi.bufEdit = bufEdit; + dvpi.iColorEffect = aColorEffect; + dvpi.iGetDecodedFrame = aGetDecodedFrame; + + if (fVOPHeaderLost) fVOPHeaderCorrupted = 1; + dvpi.fVOPHeaderCorrupted = fVOPHeaderCorrupted; + + dvpio.currMBNum = 0; + dvpio.quant = pichOut.pquant; + dvpio.fCodedMBs = fCodedMBs; + dvpio.numOfCodedMBs = numOfCodedMBs; + dvpio.quantParams = quantParams; + dvpio.mvcData = &instance->mvcData; + dvpio.aicData = &instance->aicData; + dvpio.imageStore = instance->imageStore; + dvpio.frameNum = instance->frameNum; + + dvpio.refY = refYFrame; + dvpio.refU = refUFrame; + dvpio.refV = refVFrame; + dvpio.currPY = currYFrame; + dvpio.currPU = currUFrame; + dvpio.currPV = currVFrame; + + /* MVE */ + hTranscoder->VOPHeaderEnded(aStartByteIndex, aStartBitIndex, + pichOut.pquant, instance->pictureParam.pictureType, + instance->frameNum, headerSuccess == DPH_OK_BUT_NOT_CODED); + /* VOP header parsing success, begin on VP */ + hTranscoder->BeginOneVideoPacket(&dvpi); + hTranscoder->AfterVideoPacketHeader(&dvpio); // the first VP does not have VPHeader + + decStatus = dvpGetAndDecodeVideoPacketContents(&dvpi, + instance->pictureParam.pictureType != VDX_PIC_TYPE_I, + &dvpio, hTranscoder); + + if (decStatus < 0) { + retValue = VDC_ERR; + goto exitFunction; + } else if (decStatus > 0 ) { + if (decStatus == DGOB_OK_BUT_FRAME_USELESS) { + retValue = VDC_OK_BUT_FRAME_USELESS; + goto exitFunction; + } + corruptedVPs ++; + } + + /* MVE */ + /* the first VP ends */ + hTranscoder->OneVPEnded(); + + currMBNum = dvpio.currMBNum; + numOfCodedMBs = dvpio.numOfCodedMBs; + refYFrame = dvpio.refY; + refUFrame = dvpio.refU; + refVFrame = dvpio.refV; + + + if ((decStatus == DGOB_OK && currMBNum == instance->pictureParam.numMBsInGOB) || + (decStatus == DGOB_OK_BUT_BIT_ERROR && sncCheckMpegVOP(inBuffer, &error) == SNC_PSC)) + expectedDecodingPosition = EDP_END_OF_FRAME; + else + expectedDecodingPosition = EDP_START_OF_VIDEO_PACKET; + } + } + + /* Else if Video Packet starts as expected */ + else if (expectedDecodingPosition == EDP_START_OF_VIDEO_PACKET && + sncCode == SNC_VIDPACK) { + + dvpVPInParam_t dvpi; + dvpVPInOutParam_t dvpio; + + dvpi.pictParam = &instance->pictureParam; + dvpi.inBuffer = inBuffer; + dvpi.outBuffer = outBuffer; + dvpi.bufEdit = bufEdit; + dvpi.iColorEffect = aColorEffect; + dvpi.iGetDecodedFrame = aGetDecodedFrame; + dvpi.fVOPHeaderCorrupted = fVOPHeaderCorrupted; + + dvpio.currMBNum = currMBNum; + dvpio.fCodedMBs = fCodedMBs; + dvpio.numOfCodedMBs = numOfCodedMBs; + dvpio.quantParams = quantParams; + dvpio.mvcData = &instance->mvcData; + dvpio.aicData = &instance->aicData; + dvpio.imageStore = instance->imageStore; + + dvpio.refY = refYFrame; + dvpio.refU = refUFrame; + dvpio.refV = refVFrame; + dvpio.currPY = currYFrame; + dvpio.currPU = currUFrame; + dvpio.currPV = currVFrame; + + /* MVE */ + /* VOP header parsing success, begin on VP */ + hTranscoder->BeginOneVideoPacket(&dvpi); + + /* if the VOP header data needs to be corrected from the HEC codes set + inParam->fVOPHeaderCorrupted and pictParam values will be set + read + inOutParam->frameNum into instance->frameNum */ + decStatus = dvpGetAndDecodeVideoPacketHeader(&dvpi, &dvpio); + + /* MVE */ + /* After parsing the VP header */ + hTranscoder->AfterVideoPacketHeader(&dvpio); + + if (decStatus < 0) { + retValue = VDC_ERR; + goto exitFunction; + } else if (decStatus > 0) { + + if (fVOPHeaderCorrupted) { + /* this is also true when the whole packet with the VOP header is lost */ + + if (dvpio.frameNum <= instance->frameNum) { + /* VOP header could not be recovered from HEC (there was no HEC) + or there was an error in the VP header: in this case should we try to recover + VOP header from the next VP instead of the exiting here? */ + retValue = VDC_OK_BUT_FRAME_USELESS; + goto exitFunction; + + } else { + /* VOP header was succesfully recovered from HEC, + the first VP is treated as corrupted or lost */ + instance->frameNum = dvpio.frameNum; + + } + } else if (currMBNum < dvpio.currMBNum) { + /* when there was no bit-error in the VP header and the MB counter shows difference + we know, that a whole VP was lost */ + + corruptedVPs++; + numberOfVPs++; + + + } + } + + numberOfVPs++; + + if (!decStatus) { + + + decStatus = dvpGetAndDecodeVideoPacketContents(&dvpi,0,&dvpio, hTranscoder); + if (decStatus < 0) { + retValue = VDC_ERR; + goto exitFunction; + } else if (decStatus > 0 ) { + if (decStatus == DGOB_OK_BUT_FRAME_USELESS) { + retValue = VDC_OK_BUT_FRAME_USELESS; + goto exitFunction; + } + corruptedVPs++; + } + + } + + /* MVE */ + hTranscoder->OneVPEnded(); + + currMBNum = dvpio.currMBNum; + numOfCodedMBs = dvpio.numOfCodedMBs; + + if ((decStatus == DGOB_OK && currMBNum == instance->pictureParam.numMBsInGOB) || + (decStatus == DGOB_OK_BUT_BIT_ERROR && sncCheckMpegVOP(inBuffer, &error) == SNC_PSC)) + expectedDecodingPosition = EDP_END_OF_FRAME; + else { + expectedDecodingPosition = EDP_START_OF_VIDEO_PACKET; + if (fVOPHeaderCorrupted) fVOPHeaderCorrupted=0; + } + } + + /* Else decoding is out of sync */ + else { + switch (expectedDecodingPosition) { + + case EDP_START_OF_FRAME: + if (sncCode == SNC_VIDPACK) { + /* VP start code instead of VOP start code -> + packet including VOP header is lost */ + fVOPHeaderLost = 1; + continue; + } else { + /* No start code */ + retValue = VDC_OK_BUT_FRAME_USELESS; + goto exitFunction; + } + + case EDP_START_OF_VIDEO_PACKET: + /* If the decoding gets out of sync, the next sync code is + seeked in dvpGetAndDecodeVideoPacketContents. Then, if + the frame ends instead of a new VP header, we are here. */ + + /* Mark the missing VP corrupted */ + { + numberOfVPs++; + corruptedVPs++; + + } + + retValue = VDC_OK_BUT_BIT_ERROR; + goto exitFunction; + + case EDP_END_OF_FRAME: + /* Too much data */ + retValue = VDC_OK_BUT_BIT_ERROR; + goto exitFunction; + } + } + } + + + +exitFunction: + + /* MVE */ + hTranscoder->VOPEnded(); + + if (sncCheckMpegSync(inBuffer, instance->pictureParam.fcode_forward, &error) == SNC_EOB) { + instance->fEOS = 1; + } + + /* If frame(s) not useless */ + if (retValue == VDC_OK || retValue == VDC_OK_BUT_BIT_ERROR) { + + /* If bit errors */ + if (corruptedVPs) { + retValue = VDC_OK_BUT_FRAME_USELESS; + } + + if ( retValue != VDC_OK_BUT_FRAME_USELESS ) { + + if ( instance->nOfDecodedFrames < 0xffffffff ) + instance->nOfDecodedFrames++; + if (vdcFillImageBuffers(instance, numOfCodedMBs, + instance->currFrame->imb) < 0) + retValue = VDC_ERR; + + } + } + + /* 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"vdcIsMPEGINTRA.txt"}} */ +/* + * vdcIsMPEGINTRA + * + * + * 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 vdcIsMPEGINTRA( + 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; + vdxGovHeader_t govHeader; + + vdcAssert(instance); + + tmpBitBuffer = bibCreate(frameStart, frameLength, &error); + if (!tmpBitBuffer || error) + return 0; + + syncCode = sncCheckMpegSync(tmpBitBuffer, instance->pictureParam.fcode_forward, &error); + + if ((syncCode == SNC_GOV || syncCode == SNC_VOP) && error == 0) { + vdxGetVopHeaderInputParam_t vopIn; + vdxVopHeader_t vopOut; + + if (syncCode == SNC_GOV) { + vdxStatus = vdxGetGovHeader(tmpBitBuffer, &govHeader, + &bitErrorIndication); + + if (vdxStatus < 0 || bitErrorIndication != 0) + return fINTRA; + } + + /* MVE */ + int dummy1, dummy2, dummy3, dummy4; /* not used for any processing */ + /* Get VOP header */ + vopIn.time_increment_resolution = instance->pictureParam.time_increment_resolution; + vdxStatus = vdxGetVopHeader(tmpBitBuffer, &vopIn, &vopOut, + &dummy1, &dummy2, &dummy3, &dummy4, + &bitErrorIndication); + + + if (vdxStatus >= 0 && bitErrorIndication == 0) + fINTRA = (vopOut.coding_type == VDX_VOP_TYPE_I); + } + + bibDelete(tmpBitBuffer, &error); + + return fINTRA; +} +// End of File