diff -r 000000000000 -r 951a5db380a0 videoeditorengine/h263decoder/src/MPEG4Transcoder.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/videoeditorengine/h263decoder/src/MPEG4Transcoder.cpp Fri Jan 29 14:08:33 2010 +0200 @@ -0,0 +1,4335 @@ +/* +* 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: +* Implementation for MPEG4(H263) video transcoder. Operations may include: +* 1. Bitstream Copying +* 2. BlackAndWhite Effect +* 3. MPEG4 to VDT_RESYN (Simple profile) +* 4. H.263 -> MPEG4 (Open Loop structure, no MV refinement) +* 5. MPEG4 -> H263, partial implemented +* +* We call functions 2~5 as transcoding functions since they involve MB level data processing +* +* Note: +* When RVLC is used and errors occur during forward decoding, +* We don't do backward transcoding, the rest of the data is discarded, +* +*/ + + + +/* +* Includes +*/ +#include "MPEG4Transcoder.h" +#include "debug.h" + +/* Print macro */ +#ifdef _DEBUG +#include +#define PRINT(x) RDebug::Print x +#else +#define PRINT(x) +#endif + +/* +* Defines and Typedefs +*/ +typedef unsigned int uint32; + +#define EInternalAssertionFailure 1000 +#define VDT_NO_DATA(a, b, c, d) ((a) == (c) && (b) == (d)) + +const int KDataNotValid = -1; +const int KMpeg4VopTimeIncrementResolutionLength = 16; +const int KOutputMpeg4TimeIncResolution = 30000; +const int KShortHeaderMpeg4VosSize = 14; +const int KH263ToMpeg4VosSize = 28; + + + +/*Bit stream formating*/ +#define WRITE32(op, x) sPutBits((op), 16, ((uint32)(x)) >> 16); \ +sPutBits((op), 16, (x) & 0x0000ffff) + +/* +* Constants +*/ +#ifdef _DEBUG +const TUint KInitialBufferSize = 200000; /* MPEG4 Simple Visual Profile (Levels 0,1,2,3) initial frame data buffer size vga support */ +#endif + /* + * Function Declarations +*/ + +//Static Functions + +static void sStuffBitsH263(bibBuffer_t *outBuffer); +static TVedVideoBitstreamMode sGetMPEG4Mode(int error_resilience_disable, int dp, int rvlc); +static int sFindCBP(int *mbdata, int fUseIntraDCVLC); + + + +void vdtPutInterMBCMT(bibBuffer_t *outBuffer, int coeffStart, int *coeff, int *numTextureBits, int svh); +void vdtPutIntraMBCMT(bibBuffer_t *outBuffer, int *coeff, int *numTextureBits, int index, int skipDC, int skipAC); +void vbmEncodeMVDifferential(int32 mvdx, int32 mvdy, int32 fCode, bibBuffer_t *outBuffer); +void vbmGetH263IMCBPC(int lDQuant, int vopCodingType, int colorEffect, int cbpy, int& mcbpcVal, int& len); +void vbmGetH263PMCBPC(int lDQuant, int colorEffect, int cbpy, int& mcbpcVal, int& len); +tBool vbmMVOutsideBound(tMBPosition *mbPos, tMotionVector* bestMV, tBool halfPixel); +void vbmMvPrediction(tMBInfo *mbi, int32 mBCnt, tMotionVector *predMV, int32 mbinWidth); +void vbmPutInterMB(tMBPosition* mbPos, bibBuffer_t *outBuf, dmdPParam_t *paramMB, tMotionVector *initPred, + int32 noOfPredictors, u_int32 vopWidth, u_int32 vopHeight, int32 searchRange, + int32 mbNo, int32* numTextureBits, int16 colorEffect, tMBInfo *mbsinfo); + +void sPutBits (bibBuffer_t *buf, int numBits, unsigned int value); //forward decl + +/* +* Function Definitions +*/ + +/* +* sStuffBitsH263 +* +* Parameters: +* outBuffer output buffer +* +* Function: +* This function stuffs bits for H.263 format +* Returns: +* None +* Error codes: +* None. +* +*/ +static void sStuffBitsH263(bibBuffer_t *outBuffer) +{ + const int stuffingBits[8][2] = { {1,0}, {2,0}, {3,0}, {4,0}, {5,0}, {6,0}, {7,0}, {0,0} }; + + VDTASSERT(outBuffer->baseAddr); + + /* find the number of stuffing bits to insert in the output buffer */ + int bi = outBuffer->bitIndex; + int newNumBits = stuffingBits[bi][0]; + int newValue = stuffingBits[bi][1]; + sPutBits(outBuffer, newNumBits, newValue); + + return; +} + + + +/* +* sGetMPEG4Mode +* +* Parameters: +* +* +* Function: +* This function gets the mode of the MPEG-4 bitstream +* Returns: +* Nothing +* Error codes: +* None. +* +*/ +static TVedVideoBitstreamMode sGetMPEG4Mode(int error_resilience_disable, int dp, int rvlc) +{ + TVedVideoBitstreamMode mode = EVedVideoBitstreamModeUnknown; + int combination = ((!error_resilience_disable) << 2) | (dp << 1) | rvlc; + switch (combination) + { + case 0: + mode = EVedVideoBitstreamModeMPEG4Regular; + break; + case 2: + mode = EVedVideoBitstreamModeMPEG4DP; + break; + case 3: + mode = EVedVideoBitstreamModeMPEG4DP_RVLC; + break; + case 4: + mode = EVedVideoBitstreamModeMPEG4Resyn; + break; + case 6: + mode = EVedVideoBitstreamModeMPEG4Resyn_DP; + break; + case 7: + mode = EVedVideoBitstreamModeMPEG4Resyn_DP_RVLC; + break; + default: + mode = EVedVideoBitstreamModeUnknown; + } + + return mode; +} + + +/* {{-output"vdtGetVideoBitstreamInfo.txt"}} */ +/* +* sFindCBP +* +* Parameters: +* mbdata Contains the actual MB data to be quantized +* fUseIntraDCVLC ON for INTRA, OFF for INTER +* +* Function: +* This function finds the coded bit pattern of the MB +* Returns: +* Coded Block Pattern. +* Error codes: +* None. +* +*/ +static int sFindCBP(int *mbdata, int fUseIntraDCVLC) +{ + int coeffCnt; + int *block; + int blkCnt; + int cbpFlag = 0; + int codedBlockPattern = 0; + + for (blkCnt = 0; blkCnt < 6; blkCnt++) + { + cbpFlag = 0; + codedBlockPattern <<= 1; + block = &mbdata[blkCnt * BLOCK_COEFF_SIZE]; + for (coeffCnt = fUseIntraDCVLC; coeffCnt < BLOCK_COEFF_SIZE; + coeffCnt++) + { + if (block[coeffCnt]) + { + cbpFlag = 1; + codedBlockPattern |= cbpFlag; + break; + } + } + } + + return codedBlockPattern; +} + + + + + + +/* {{-output"sPutBits.txt"}} */ +/* +* sPutBits +* +* Parameters: +* outBuf output buffer +* numBits number of bits to output +* value new value +* +* Function: +* This function puts some bits to the output buffer +* Returns: +* Nothing. +* Error codes: +* None. +* +*/ +void sPutBits (bibBuffer_t *buf, int numBits, unsigned int value) +{ + + bibEditParams_t edParam; + + edParam.curNumBits = edParam.newNumBits = numBits; + edParam.StartByteIndex = edParam.StartBitIndex = 0; /* used for source buffer only */ + edParam.newValue = value; /* use value 128, encoded as codeword "1111 1111" = 255 */ + + CopyBufferEdit((bibBuffer_t*)NULL, buf, &edParam, 0); +} + + + +/* +* GetTimeIncPosition +* +* +* Parameters: +* hInstance instance handle +* +* Function: +* Calculates the time increment position for the current VOP. +* +* Returns: +* VDX error codes +* +*/ + +int GetTimeIncPosition( + bibBuffer_t *inBuffer, + const vdxGetVopHeaderInputParam_t *inpParam, + vdxVopHeader_t *header, + int * ModuloByteIndex, + int * ModuloBitIndex, + int * ByteIndex, + int * BitIndex, + int *bitErrorIndication) +/* {{-output"vdxGetVopHeader.txt"}} */ +{ + /* Get VOP header */ + int ret = vdxGetVopHeader(inBuffer, inpParam, header, + ModuloByteIndex, ModuloBitIndex, ByteIndex, BitIndex, + bitErrorIndication); + + return ret; + +} + + + +/* +* CopyEditVop +* +* +* Parameters: +* hInstance instance handle +* +* Function: +* This function copies the VOP header with edited time stamps of the VOP. +* +* Returns: +* TX error codes +*/ + +int CopyEditVop(vdeHInstance_t hInstance, int aNrOfBytesToSkip, bibBuffer_t * inBuffer, + vdeDecodeParamters_t *aDecoderInfo) +{ + PRINT((_L("CopyEditVop() begin"))); + int StartByteIndex = 0; + int StartBitIndex = 7; + int16 error; + int sncCode; + int timeIncByteIndex, timeIncBitIndex; + int moduloBaseByteIndex, moduloBaseBitIndex; + int vopheaderBitLeft; + int numBitChange = 0; + int increaseBytes = 0; + int stuffingLength = 0; + + tMPEG4TimeParameter * timeStamp = aDecoderInfo->aMPEG4TimeStamp; + MPEG4TimeParameter CurNewTimeCode; + + int outTirDecreased = 0; + int outputTimeResolution = *aDecoderInfo->aMPEG4TargetTimeResolution; + int numOutputTrBits; + for (numOutputTrBits = 1; ((outputTimeResolution-1) >> numOutputTrBits) != 0; numOutputTrBits++) + { + } + + int num_bits; + vdxGetVopHeaderInputParam_t inpParam; + vdxVopHeader_t vopheader; + int bitErrorIndication; + vdeInstance_t * vdeTemp = (vdeInstance_t *)hInstance; + bibBuffer_t *outBuffer = vdeTemp->outBuffer; + bibBufferEdit_t * bufEdit = vdeTemp->bufEdit; + + int FrameSizeInByte = outBuffer->numBytesRead; + bibRewindBits(bibNumberOfFlushedBits(inBuffer),inBuffer,&error); + bibRewindBits(bibNumberOfFlushedBits(outBuffer),outBuffer,&error); + if ( aNrOfBytesToSkip > 0 ) + { + // VOS header is already in the beginning of the output buffer + bibForwardBits(aNrOfBytesToSkip<<3, outBuffer); + // need to also skip the VOS header from input + } + bufEdit->copyMode = CopyWhole; /* CopyWhole - default */ + + /* record position */ + StartByteIndex = inBuffer->numBytesRead; + StartBitIndex = inBuffer->bitIndex; + + /* get time increment resolution */ + vdcInstance_t * vdcTemp = (vdcInstance_t *)(vdeTemp->vdcHInstance); + int currentTimeIncResolution = vdcTemp->pictureParam.time_increment_resolution > 0? vdcTemp->pictureParam.time_increment_resolution : outputTimeResolution; + inpParam.time_increment_resolution = currentTimeIncResolution; + + /* find the next vop start code */ + do + { + sncCode = sncSeekMPEGStartCode(inBuffer, vdcTemp->pictureParam.fcode_forward, vdcTemp->pictureParam.error_res_disable, 0, &error); + bibForwardBits(32,inBuffer); // one start code is found, move on + if(inBuffer->bitsLeft <= 0) + { + return TX_ERR; // did not find any sync code --- vop is corrupted + } + } + while (sncCode != SNC_VOP); + bibRewindBits(32,inBuffer, &error); // go back + + // if we have VOS header in the input, we are now just after it. If aNrOfBytesToSkip > 0, we should not copy it + // however, aNrOfBytesToSkip refers to output buffer, so we should not use it when skipping the input + if ( aNrOfBytesToSkip > 0 ) + { + StartByteIndex = inBuffer->numBytesRead; + StartBitIndex = inBuffer->bitIndex; + } + + /* read vop header */ + GetTimeIncPosition(inBuffer, &inpParam, &vopheader, + &moduloBaseByteIndex, &moduloBaseBitIndex, &timeIncByteIndex, + &timeIncBitIndex, &bitErrorIndication); + + /* record the header end; */ + vopheaderBitLeft = inBuffer->bitsLeft; + + /* copy-edit the part from the begin to the end of modulo base */ + CurNewTimeCode = *timeStamp; + + if (CurNewTimeCode.modulo_time_base != vopheader.time_base_incr) + { + if (!bufEdit->editParams) + { + bufEdit->editParams = (bibEditParams_t *) malloc(sizeof(bibEditParams_t)); + if(!bufEdit->editParams) + { + //Memory not available + return TX_ERR; //indicating error; + } + else + { + bufEdit->numChanges = 1; + } + } + bufEdit->copyMode = CopyWithEdit; /* CopyWithEdit */ + bufEdit->editParams->curNumBits = vopheader.time_base_incr + 1; + bufEdit->editParams->newNumBits = CurNewTimeCode.modulo_time_base + 1; + bufEdit->editParams->newValue = ((1 << CurNewTimeCode.modulo_time_base) - 1) << 1; + bufEdit->editParams->StartByteIndex = moduloBaseByteIndex; + bufEdit->editParams->StartBitIndex = moduloBaseBitIndex; + numBitChange += bufEdit->editParams->newNumBits - bufEdit->editParams->curNumBits; + } + else + { + bufEdit->copyMode = CopyWhole; /* CopyWithEdit */ + } + /* set the end of copy point */ + bibRewindBits((inBuffer->numBytesRead<<3)+7-inBuffer->bitIndex,inBuffer,&error); + bibForwardBits((moduloBaseByteIndex<<3)+7-moduloBaseBitIndex+vopheader.time_base_incr+2, inBuffer); + + /* copy data */ + CopyStream(inBuffer,outBuffer,bufEdit,StartByteIndex,StartBitIndex); + StartByteIndex=inBuffer->getIndex; + StartBitIndex=inBuffer->bitIndex; + bufEdit->copyMode = CopyWhole; /* CopyWhole */ + + /* copy and edit until the end of Vop header */ + if (currentTimeIncResolution != outputTimeResolution /* && volheader.time_increment_resolution != 30 */ + || vopheader.time_inc != CurNewTimeCode.time_inc) + { + for (num_bits = 1; ((currentTimeIncResolution-1) >> num_bits) != 0; num_bits++) + { + } + /* prepare editing position */ + if (!bufEdit->editParams) + { + bufEdit->editParams = (bibEditParams_t *) malloc(sizeof(bibEditParams_t)); + if(!bufEdit->editParams) + { + //Memory not available + return TX_ERR; //indicating error no memory; + } + else + { + bufEdit->numChanges = 1; + } + + } + bufEdit->copyMode = CopyWithEdit; /* CopyWithEdit */ + bufEdit->editParams->StartByteIndex = timeIncByteIndex; + bufEdit->editParams->StartBitIndex = timeIncBitIndex; + bufEdit->editParams->curNumBits = num_bits; + bufEdit->editParams->newNumBits = numOutputTrBits; + bufEdit->editParams->newValue = vopheader.time_inc; + + /* update time increment */ + if (vopheader.time_inc != CurNewTimeCode.time_inc) + { + /*bufEdit->editParams->newValue = (int)(vopheader.time_inc * (float)outputTimeResolution / + (float)currentTimeIncResolution + 0.5); //CurNewTimeCode.time_inc; + */ + bufEdit->editParams->newValue = CurNewTimeCode.time_inc; + } + numBitChange += bufEdit->editParams->newNumBits - bufEdit->editParams->curNumBits; + } + + /* set the copy end point to the end of vop header */ + bibForwardBits(inBuffer->bitsLeft - vopheaderBitLeft, inBuffer); + + /* copy data */ + CopyStream(inBuffer,outBuffer,bufEdit,StartByteIndex,StartBitIndex); + StartByteIndex=inBuffer->getIndex; + StartBitIndex=inBuffer->bitIndex; + + if ( vdcTemp->pictureParam.error_res_disable && (inBuffer->bitsLeft > 40) ) // 40 as below to avoid negative values below + { + // there are no VP headers => no need to search for VP start codes => can jump to the end. + // 40 = 5 bytes; in the end there is a start code that has 4 bytes + bibForwardBits( inBuffer->bitsLeft-40 ,inBuffer); + } + + PRINT((_L("CopyEditVop() seek sync"))); + /* find the next resync marker */ + sncCode = sncSeekMPEGStartCode(inBuffer, vopheader.fcode_forward, vdcTemp->pictureParam.error_res_disable, 0, &error); + if ( sncCode == SNC_NO_SYNC ) + { + PRINT((_L("CopyEditVop() sync NOT found, interrupt the copying and return"))); + return TX_ERR; + } + PRINT((_L("CopyEditVop() sync found"))); + + /* record next resync position */ + int resyncBitsLeft = inBuffer->bitsLeft; + + /* rewind stuffing bits */ + sncRewindStuffing(inBuffer, &error); + + if (!bufEdit->editParams) + { + bufEdit->editParams = (bibEditParams_t *) malloc(sizeof(bibEditParams_t)); + if(!bufEdit->editParams) + { + //Memory not available + return TX_ERR; //indicating error no memory; + } + else + { + bufEdit->numChanges = 1; + } + } + + /* record position */ + bufEdit->editParams->StartByteIndex = inBuffer->getIndex; + bufEdit->editParams->StartBitIndex = inBuffer->bitIndex; + + /* calculate new stuffing bits */ + bufEdit->editParams->curNumBits = inBuffer->bitsLeft - resyncBitsLeft; + /* calculate number of bits/bytes changed */ + if (numBitChange<0) + { + outTirDecreased = 1; + numBitChange = -numBitChange; + } + int numByteChange = numBitChange >> 3; + + if (outTirDecreased) + { + increaseBytes -= numByteChange; + stuffingLength = bufEdit->editParams->curNumBits + (numBitChange - (numByteChange << 3)); + if (stuffingLength > 8) + { + stuffingLength -= 8; + increaseBytes --; + } + } + else + { + increaseBytes += numByteChange; + stuffingLength = bufEdit->editParams->curNumBits - (numBitChange - (numByteChange << 3)); + if (stuffingLength <= 0) + { + stuffingLength += 8; + increaseBytes ++; + } + } + + /* adjust the output buffer size */ + if (increaseBytes != 0) + { + outBuffer->size += increaseBytes; + if (increaseBytes>=0) + { + outBuffer->bitsLeft += (increaseBytes << 3); + } + else + { + outBuffer->bitsLeft -= ((-increaseBytes) << 3); + } + } + + /* update edit statistics */ + bufEdit->editParams->newNumBits = stuffingLength; + bufEdit->editParams->newValue = stuffingLength>0?(1<<(stuffingLength-1))-1:0; + if (stuffingLength != bufEdit->editParams->curNumBits) + { + bufEdit->copyMode = CopyWithEdit; + } + + bibForwardBits(bufEdit->editParams->curNumBits, inBuffer); + /* copy data */ + CopyStream(inBuffer,outBuffer,bufEdit,StartByteIndex,StartBitIndex); + /* record position */ + StartByteIndex = inBuffer->getIndex; + StartBitIndex = inBuffer->bitIndex; + + do + { + /* if it is the start of a video packet, copy it with edit */ + if (sncCode == SNC_VIDPACK ) + { + /* copy video packet with edit */ + int retVal = CopyEditVideoPacket(inBuffer, outBuffer, bufEdit, vdcTemp, aDecoderInfo, &vopheader, + &sncCode, &StartByteIndex, &StartBitIndex); + if(retVal<0) + { + //error inside function return error + return TX_ERR; + } + } + else if (sncCode == SNC_EOB || sncCode == SNC_EOS || sncCode == SNC_GOV) + { + // since it is EOB, so end of sequence has occurred, so no more data, so exit + break; + } + } + while(sncCode != SNC_VOP); + + /* copy the rest of bits */ + if ((int)inBuffer->numBytesRead < FrameSizeInByte) + { + bufEdit->copyMode = CopyWhole; + bibForwardBits((FrameSizeInByte-StartByteIndex)<<3, inBuffer); + CopyStream(inBuffer,outBuffer,bufEdit,StartByteIndex,StartBitIndex); + } + + PRINT((_L("CopyEditVop() end"))); + return TX_OK; + } + + +/* +* CopyEditVideoPacket +* +* +* Parameters: +* +* Function: +* This function copies the video packet with edited time stamps, if HEC is enabled +* +* Returns: +* TX error codes +*/ + +int CopyEditVideoPacket(bibBuffer_t* aInBuffer, + bibBuffer_t* aOutBuffer, + bibBufferEdit_t* aBufEdit, + vdcInstance_t * aVdcTemp, + vdeDecodeParamters_t* aDecoderInfo, + vdxVopHeader_t* aVopheader, + int* aSncCode, + int* aStartByteIndex, + int* aStartBitIndex) +{ + int16 error = 0; + int value = 0; + int bitsGot = 0; + int num_bits = 0; + int *bitErrorIndication = 0; + int numOutputTrBits = 0; + int resyncMarkerLength = 0; + int numMBs = 0; + int mbNumberLength = 0; + int startByteIndex = *aStartByteIndex; + int startBitIndex = *aStartBitIndex; + int currentTimeIncResolution = 0; + int outputTimeResolution = 0; + MPEG4TimeParameter curNewTimeCode; + MPEG4TimeParameter* timeStamp = aDecoderInfo->aMPEG4TimeStamp; + + int numBitChange = 0; + int increaseBytes = 0; + int stuffingLength = 0; + int outTirDecreased = 0; + + currentTimeIncResolution = aVdcTemp->pictureParam.time_increment_resolution > 0? aVdcTemp->pictureParam.time_increment_resolution : 30000; + outputTimeResolution = *aDecoderInfo->aMPEG4TargetTimeResolution; + for (numOutputTrBits=1; ((outputTimeResolution-1)>>numOutputTrBits)!=0; numOutputTrBits++) + { + } + /* evaluate resync marker length */ + resyncMarkerLength = (aVopheader->coding_type == 0 ? 17 : 16+aVopheader->fcode_forward); + /* evaluate MB number length */ + numMBs = ((aVdcTemp->pictureParam.lumWidth+15)>>4) * ((aVdcTemp->pictureParam.lumHeight+15)>>4); + for (mbNumberLength = 1; ((numMBs-1) >> mbNumberLength) != 0; mbNumberLength++) + { + } + + value = bibGetBits(resyncMarkerLength, aInBuffer, &bitsGot, bitErrorIndication, &error); // resync marker + value = bibGetBits(mbNumberLength, aInBuffer, &bitsGot, bitErrorIndication, &error); // mb number + value = bibGetBits(5, aInBuffer, &bitsGot, bitErrorIndication, &error); // quant scale + value = bibGetBits(1, aInBuffer, &bitsGot, bitErrorIndication, &error); // header extension code + + /* if HEC enabled, copy edit time increment fields in the video packet */ + if (value == 1) + { + /* copy-edit the part from the begin to the end of modulo base */ + curNewTimeCode = *timeStamp; + + if (curNewTimeCode.modulo_time_base != aVopheader->time_base_incr) + { + if (!aBufEdit->editParams) + { + aBufEdit->editParams = (bibEditParams_t *) malloc(sizeof(bibEditParams_t)); + if(!aBufEdit->editParams) + { + //Memory not available + return TX_ERR; //indicating error no memory; + } + else + { + aBufEdit->numChanges = 1; + } + } + aBufEdit->copyMode = CopyWithEdit; /* CopyWithEdit */ + aBufEdit->editParams->curNumBits = aVopheader->time_base_incr + 1; + aBufEdit->editParams->newNumBits = curNewTimeCode.modulo_time_base + 1; + aBufEdit->editParams->newValue = ((1 << curNewTimeCode.modulo_time_base) - 1) << 1; + aBufEdit->editParams->StartByteIndex = aInBuffer->getIndex; + aBufEdit->editParams->StartBitIndex = aInBuffer->bitIndex; + numBitChange += aBufEdit->editParams->newNumBits - aBufEdit->editParams->curNumBits; + } + else + { + aBufEdit->copyMode = CopyWhole; /* CopyWithEdit */ + } + /* set the end of copy point */ + bibForwardBits(aVopheader->time_base_incr+2, aInBuffer); // includes one bit for Marker + + /* copy data */ + CopyStream(aInBuffer,aOutBuffer,aBufEdit,startByteIndex,startBitIndex); + startByteIndex = aInBuffer->getIndex; + startBitIndex = aInBuffer->bitIndex; + aBufEdit->copyMode = CopyWhole; /* CopyWhole */ + + /* copy and edit 'time increment' field */ + if (currentTimeIncResolution != outputTimeResolution /* && volheader.time_increment_resolution != 30 */ + || aVopheader->time_inc != curNewTimeCode.time_inc) + { + for (num_bits = 1; ((currentTimeIncResolution-1) >> num_bits) != 0; num_bits++) + { + } + + /* prepare editing position */ + if (!aBufEdit->editParams) + { + aBufEdit->editParams = (bibEditParams_t *) malloc(sizeof(bibEditParams_t)); + if(!aBufEdit->editParams) + { + //Memory not available + return TX_ERR; //indicating error no memory; + } + else + { + aBufEdit->numChanges = 1; + } + } + aBufEdit->copyMode = CopyWithEdit; /* CopyWithEdit */ + aBufEdit->editParams->StartByteIndex = aInBuffer->getIndex; + aBufEdit->editParams->StartBitIndex = aInBuffer->bitIndex; + aBufEdit->editParams->curNumBits = num_bits; + aBufEdit->editParams->newNumBits = numOutputTrBits; + aBufEdit->editParams->newValue = aDecoderInfo->aMPEG4TimeStamp->time_inc; + + /* move to end position of 'time increment' field */ + bibForwardBits(num_bits, aInBuffer); // move to end of 'time increment' field + /* update time increment */ + if (aVopheader->time_inc != curNewTimeCode.time_inc) + { + aBufEdit->editParams->newValue = curNewTimeCode.time_inc; + } + numBitChange += aBufEdit->editParams->newNumBits - aBufEdit->editParams->curNumBits; + } + + /* copy time increment field with edit */ + CopyStream(aInBuffer,aOutBuffer,aBufEdit,startByteIndex,startBitIndex); + startByteIndex=aInBuffer->getIndex; + startBitIndex=aInBuffer->bitIndex; + + } + + /* copy rest of video packet */ + + /* find the next resync marker */ + *aSncCode = sncSeekMPEGStartCode(aInBuffer, aVopheader->fcode_forward, 0 /* VPs used*/, 0, &error); + + /* record next resync position */ + int resyncBitsLeft = aInBuffer->bitsLeft; + + /* rewind stuffing bits */ + sncRewindStuffing(aInBuffer, &error); + + if (!aBufEdit->editParams) + { + aBufEdit->editParams = (bibEditParams_t *) malloc(sizeof(bibEditParams_t)); + if(!aBufEdit->editParams) + { + //Memory not available + return TX_ERR; //indicating error no memory; + } + else + { + aBufEdit->numChanges = 1; + } + } + + /* record position */ + aBufEdit->editParams->StartByteIndex = aInBuffer->getIndex; + aBufEdit->editParams->StartBitIndex = aInBuffer->bitIndex; + + /* calculate new stuffing bits */ + aBufEdit->editParams->curNumBits = aInBuffer->bitsLeft - resyncBitsLeft; + + /* calculate number of bits/bytes changed */ + if (numBitChange<0) + { + outTirDecreased = 1; + numBitChange = -numBitChange; + } + int numByteChange = numBitChange >> 3; + + /* evaluate change in buffer size */ + if (outTirDecreased) + { + increaseBytes -= numByteChange; + stuffingLength = aBufEdit->editParams->curNumBits + (numBitChange - (numByteChange << 3)); + if (stuffingLength > 8) + { + stuffingLength -= 8; + increaseBytes --; + } + } + else + { + increaseBytes += numByteChange; + stuffingLength = aBufEdit->editParams->curNumBits - (numBitChange - (numByteChange << 3)); + if (stuffingLength <= 0) + { + stuffingLength += 8; + increaseBytes ++; + } + } + + /* adjust the output buffer size */ + if (increaseBytes != 0) + { + aOutBuffer->size += increaseBytes; + if (increaseBytes>=0) + { + aOutBuffer->bitsLeft += (increaseBytes << 3); + } + else + { + aOutBuffer->bitsLeft -= ((-increaseBytes) << 3); + } + } + /* update edit statistics */ + aBufEdit->editParams->newNumBits = stuffingLength; + aBufEdit->editParams->newValue = stuffingLength>0?(1<<(stuffingLength-1))-1:0; + if (stuffingLength != aBufEdit->editParams->curNumBits) + { + aBufEdit->copyMode = CopyWithEdit; // copy with edit + } + else + { + aBufEdit->copyMode = CopyWhole; // copy whole + } + + bibForwardBits(aBufEdit->editParams->curNumBits, aInBuffer); + /* copy video packet with stuffing bits edited */ + CopyStream(aInBuffer, aOutBuffer, aBufEdit, startByteIndex, startBitIndex); + /* record position */ + startByteIndex = aInBuffer->getIndex; + startBitIndex = aInBuffer->bitIndex; + + /* update position for return */ + *aStartByteIndex = startByteIndex; + *aStartBitIndex = startBitIndex; + + return TX_OK; +} + + +/* +* sPutBits +* +* Parameters: +* outBuf output buffer +* numBits number of bits to output +* value new value +* +* Function: +* Wrapper to sPutBits +* Returns: +* None. +* Error codes: +* None. +* +*/ +void vdtPutBits (void *buf, int numBits, unsigned int value) +{ + /* must be in this type! "void" is used here only because of the interface with vlb.cpp */ + sPutBits ((bibBuffer_t *)(buf), numBits, value); +} + + + +/* {{-output"vdtCopyBuffer.txt"}} */ +/* +* vdtCopyBuffer +* +* Parameters: +* +* Function: +* This function copies some data from source buffer to destination buffer +* Returns: +* None. +* Error codes: +* None. +* +*/ +void vdtCopyBuffer(bibBuffer_t *SrcBuffer,bibBuffer_t *DestBuffer, + int ByteStart,int BitStart, int ByteEnd, int BitEnd) +{ + int startByteIndex = SrcBuffer->getIndex; + int startBitIndex = SrcBuffer->bitIndex; + int bitsLeft = SrcBuffer->bitsLeft; + int numBytesRead = SrcBuffer->numBytesRead; + + CopyBuffer(SrcBuffer,DestBuffer, ByteStart, BitStart, ByteEnd, BitEnd); + + /* recover the postion */ + SrcBuffer->getIndex = startByteIndex ; + SrcBuffer->bitIndex = startBitIndex; + SrcBuffer->bitsLeft = bitsLeft; + SrcBuffer->numBytesRead = numBytesRead; +} + + + + +/* {{-output"vdtStuffBitsMPEG4.txt"}} */ +/* +* vdtStuffBitsMPEG4 +* +* Parameters: +* outBuf output buffer +* +* Function: +* This function puts some stuffing bits to the output buffer +* bits need to be stuffed in the output buffer at the end of vp in all cases (bw or not) +* Returns: +* None. +* Error codes: +* None. +* +*/ +void vdtStuffBitsMPEG4(bibBuffer_t *outBuffer) +{ + const int stuffingBits[8][2] = { {1,0}, {2,1}, {3,3}, {4,7}, {5,15}, {6,31}, {7,63}, {8,127} }; + VDTASSERT(outBuffer->baseAddr); + + /* find the number of stuffing bits to insert in the output buffer */ + int bi = outBuffer->bitIndex; + int newNumBits = stuffingBits[bi][0]; + int newValue = stuffingBits[bi][1]; + sPutBits(outBuffer, newNumBits, newValue); + + return; +} + + +/*************************************************************/ + + +/* {{-output"sResetH263IntraDcUV.txt"}} */ +/* +* sResetH263IntraDcUV +* +* Parameters: output buffer +* uValue +* vValue +* +* Function: +* This function reset the chrominace INTRADC when black and white color effect is applied +* Returns: +* none +* Error codes: +* None. +* +*/ +inline void sResetH263IntraDcUV(bibBuffer_t *DestBuffer, TInt uValue, TInt vValue) +{ + /* For the Color Effects Fill the U and V buffers with the + corresponding color values */ + + sPutBits(DestBuffer, 8, uValue); + sPutBits(DestBuffer, 8, vValue); +} + + +/* {{-output"vdtGetPMBBlackAndWhiteMCBPC.txt"}} */ +/* +* vdtGetPMBBlackAndWhiteMCBPC +* +* Parameters: +* +* Function: +* This function compute the new mcbpc for black and white effect * +* Returns: +* the length of the input mcbpc. +* Error codes: +* None. +* +*/ +int vdtGetPMBBlackAndWhiteMCBPC(int& new_len, int& new_val, int mcbpc) +{ + int cur_index, new_index, cur_len; + + const tVLCTable sCBPCPType[21] = + { + {1, 1}, {3, 4}, {2, 4}, {5, 6}, + {3, 3}, {7, 7}, {6, 7}, {5, 9}, + {2, 3}, {5, 7}, {4, 7}, {5, 8}, + {3, 5}, {4, 8}, {3, 8}, {3, 7}, + {4, 6}, {4, 9}, {3, 9}, {2, 9}, + {1, 9} + }; + + /* evaluate MCBPC parameters */ + int cur_cbpc = mcbpc & 3; + int new_cbpc = 0; // cpbc=0 indicates chroma is 0 + int mbType; + + mbType = mcbpc / 4; + /* evaluate indices in table */ + cur_index = mbType * 4 + cur_cbpc; + new_index = mbType * 4 + new_cbpc; + + /* retrieve values */ + cur_len = sCBPCPType[cur_index].length; + new_len = sCBPCPType[new_index].length; + new_val = sCBPCPType[new_index].code; + + return cur_len; +} + + +/* {{-output"vdtGetIMBBlackAndWhiteMCBPC.txt"}} */ +/* +* vdtGetIMBBlackAndWhiteMCBPC +* +* Parameters: None +* +* Function: +* This function compute the new mcbpc for black and white effect +* Returns: +* the length of the input mcbpc. +* Error codes: +* None. +* +*/ +int vdtGetIMBBlackAndWhiteMCBPC(int& new_len, int& new_val, int mcbpc) +{ + int cur_index, new_index, cur_len; + + const tVLCTable sCBPCIType[9] = + { + {1, 1}, {1, 3}, {2, 3}, {3, 3}, {1, 4}, + {1, 6}, {2, 6}, {3, 6}, {1, 9} + }; + + /* evaluate MCBPC parameters */ + int cur_cbpc = mcbpc & 3; + int new_cbpc = 0; // cpbc=0 indicates chroma is 0 + int mbType = (mcbpc <4)?3:4; + + /* evaluate indices in table */ + cur_index = (mbType == 3 ? 0 : 4) + cur_cbpc; + new_index = (mbType == 3 ? 0 : 4) + new_cbpc; + + /* retrieve values */ + cur_len = sCBPCIType[cur_index].length; + new_len = sCBPCIType[new_index].length; + new_val = sCBPCIType[new_index].code; + + return cur_len; +} + + + + + +/* {{-output"vdtGetVideoBitstreamInfo.txt"}} */ +/* +* vdtGetVideoBitstreamInfo +* +* Parameters: +* +* Function: +* This function provides the bitstream info to the processor * +* Returns: +* VDE error codes +* Error codes: +* None. +* +*/ +int vdtGetVideoBitstreamInfo(bibBuffer_t *inBuffer, vdeDecodeParamters_t *aInfoOut, int *aByteIndex, int *aBitIndex) +{ + int numBitsGot, + bitErrorIndication = 0; + int16 error = 0; + u_int32 bits; + int timeResolution = 0; + TVedVideoBitstreamMode streamMode = EVedVideoBitstreamModeUnknown; + vdxVolHeader_t volHeader; + volHeader.user_data = NULL; + + bits = bibShowBits(32, inBuffer, &numBitsGot, &bitErrorIndication, &error); + if (error) + { + streamMode = EVedVideoBitstreamModeUnknown; + goto exitFunction; + } + /* If PSC */ + if ((bits >> 10) == 32) { + streamMode = EVedVideoBitstreamModeH263; + } + + /* Else check for Visual Sequence, Visual Object or Video Object start code */ + else if ((bits == MP4_VOS_START_CODE) || + (bits == MP4_VO_START_CODE) || + ((bits >> MP4_VID_ID_CODE_LENGTH) == MP4_VID_START_CODE) || + ((bits >> MP4_VOL_ID_CODE_LENGTH) == MP4_VOL_START_CODE)) + { + + /* read the Stream headers from the bitstream */ + if ((vdxGetVolHeader(inBuffer, &volHeader, &bitErrorIndication, 1, aByteIndex, aBitIndex, NULL) != 0) || + (bitErrorIndication != 0)) + { + goto exitFunction; + } + + timeResolution = volHeader.time_increment_resolution; + streamMode = sGetMPEG4Mode(volHeader.error_res_disable, volHeader.data_partitioned, volHeader.reversible_vlc); + bits = bibShowBits(22, inBuffer, &numBitsGot, &bitErrorIndication, &error); + if (error) + goto exitFunction; + + /* Check if H.263 PSC follows the VOL header, in which case this is + MPEG-4 with short header and is decoded as H.263 */ + if ( bits == 32 ) + { + streamMode = EVedVideoBitstreamModeMPEG4ShortHeader; + } + } + + /* Else no H.263 and no MPEG-4 start code detected */ + else { + streamMode = EVedVideoBitstreamModeUnknown; + } + +exitFunction: + /* copy the got user data to the core data structure */ + if (volHeader.user_data != NULL) + { + free(volHeader.user_data); + } + + bibRewindBits( bibNumberOfFlushedBits( inBuffer ), inBuffer, &error ); + aInfoOut->streamMode = streamMode; + aInfoOut->iTimeIncrementResolution = timeResolution; + return TX_OK; +} + + + + + +/* {{-output"vdtGetVideoBitstreamInfo.txt"}} */ +/* +* sQuantizeMB +* +* Parameters: +* mbdata Contains the actual MB data to be quantized +* oldQuant: +* newQuant: +* intra +* +* Function: +* This function requantizes the AC/DCT data for one MB, used in MPEG4 -> H263 transcoding +* Returns: +* Coded Block Pattern. +* Error codes: +* None. +* +*/ +static void sQuantizeMB(int *mbdata, int oldQuant, int newQuant, int intra, int colorEffect) +{ +#define SIGN(x) (((x)<0) ? -1:1 ) + int coeffCnt; + int *block; + int blkCnt; + + for (blkCnt = 0; blkCnt < (colorEffect ? 4 : 6); blkCnt++) + { + block = &mbdata[blkCnt * BLOCK_COEFF_SIZE]; + for (coeffCnt = (intra == VDX_MB_INTRA); coeffCnt < BLOCK_COEFF_SIZE; + coeffCnt++) + { + if (block[coeffCnt]) + { + int level = abs(block[coeffCnt]); + int sign = SIGN(block[coeffCnt]); + int rcoeff; + // dequantize + if ((oldQuant % 2) == 1) + rcoeff = oldQuant * ((level << 1) + 1); + else + rcoeff = oldQuant * ((level << 1) + 1) - 1; + + rcoeff = min (2047, max (-2048, sign * rcoeff)); + + // requantize + if (intra == VDX_MB_INTRA) + { + level = (abs (rcoeff)) / (newQuant << 1); + } + else + { + level = (abs (rcoeff) - (newQuant >> 1)) / (newQuant << 1); + /* clipping to [-127,+127] */ + } + + /* clipping to [-127,+127] */ + block[coeffCnt] = min (127, max (-127, sign * level)); + } + else + { + /* Nothing */ + } + } + } + return ; +} + + + + +/* {{-output"vdtGetVideoBitstreamInfo.txt"}} */ +/* +* vdtChangeVosHeaderRegResyncL +* +* Parameters: +* +* Function: +* This function finds the error resillence bit and change it if necessary +* to make it Regular Resynchronization mode +* Returns: +* ETrue if buffer changed. +* Error codes: +* None +* +*/ +TBool vdtChangeVosHeaderRegResyncL(TPtrC8& aInputBuffer, TUint aBufferSize) +{ + int16 errorCode = 0; /* return code for bib functions */ + bibBuffer_t *buffer; /* input buffer */ + + /* Create bit buffer */ + buffer = bibCreate((TAny*)aInputBuffer.Ptr(), aBufferSize, &errorCode); + if (!buffer || errorCode) + return EFalse; + + int startByte = 0, startBit = 7; + vdeDecodeParamters_t decInfo; + vdtGetVideoBitstreamInfo(buffer, &decInfo, &startByte, &startBit); + + if (decInfo.streamMode == EVedVideoBitstreamModeMPEG4Regular) + { + char *temp = (char *) (TAny*)aInputBuffer.Ptr(); + unsigned char patern[8] = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F}; + temp[startByte] &= patern[startBit]; // change the error resillence bit to 0; + + /* Delete bit buffer */ + bibDelete(buffer, &errorCode); + return ETrue; + } + else + { + /* Delete bit buffer */ + bibDelete(buffer, &errorCode); + return EFalse; + } +} + +/* +* CMPEG4Transcoder +* +* Parameters: +* +* Function: +* Constructor +* +*/ +CMPEG4Transcoder::CMPEG4Transcoder(const vdeInstance_t *aVDEInstance, bibBuffer_t *aInBuffer, bibBuffer_t *aOutBuffer) +{ + VDTASSERT(aVDEInstance); + VDTASSERT(aInBuffer); + VDTASSERT(aOutBuffer); + + /* passing the arguments */ + iVDEInstance = aVDEInstance; + iInBuffer = aInBuffer; + iOutBuffer = aOutBuffer; + + /* Color Toning */ + iMBType = NULL; + iCurQuant = 0; + iColorEffect = aVDEInstance->iColorEffect; + iColorToneU = aVDEInstance->iColorToneU; + iColorToneV = aVDEInstance->iColorToneV; + iRefQuant = aVDEInstance->iRefQp; + iDcScaler = GetMpeg4DcScalerUV(iRefQuant); + + iDoModeTranscoding = EFalse; + iDoTranscoding = (iColorEffect || iDoModeTranscoding); + iTargetFormat = EVedVideoTypeMPEG4SimpleProfile; + iStuffingBitsUsed = 0; + + /* default values */ + iLastMBNum = -1; + iCurMBNum = 0; + + /* initialize here but will be changed later to proper value */ + iOutputMpeg4TimeIncResolution = KOutputMpeg4TimeIncResolution; + + iNumMBsInOneVOP = (iVDEInstance->lumHeight * iVDEInstance->lumWidth) >> 8; // /256 + iMBsinWidth = iVDEInstance->lumWidth >> 4; + iNumMBsInGOB = iVDEInstance->lumWidth >> 4; + + + iMBList = NULL; + iH263DCData = NULL; + h263mbi = NULL; + + + iH263MBVPNum = NULL; + iErrorResilienceStartByteIndex = KDataNotValid; + iErrorResilienceStartBitIndex = KDataNotValid; + + iVideoPacketNumInMPEG4 = 0; // the video packet number this MB belongs to, NOTE: the first GOB doesn't have a GOB header + iCurMBNumInVP = -1; + fFirstFrameInH263 = EFalse; + + return; +} + +/* +* ~CMPEG4Transcoder +* +* Parameters: +* +* Function: +* Destructor +* +*/ +CMPEG4Transcoder::~CMPEG4Transcoder() +{ + if (iCurIMBinstance) + { + free(iCurIMBinstance); + } + if (iCurPMBinstance) + { + free(iCurPMBinstance); + } + if (bufEdit.editParams) + { + free(bufEdit.editParams); + } + + // for H263 + if (iH263MBVPNum) + { + free(iH263MBVPNum); + } + + // for color toning + if (iMBType) + { + free(iMBType); + } + + + + if (iH263DCData) + { + for (int i = 0; i < iNumMBsInOneVOP; i++) + { + free(iH263DCData[i]); + } + free(iH263DCData); + } + + if ( ( (iTargetFormat == EVedVideoTypeH263Profile0Level10) || + (iTargetFormat == EVedVideoTypeH263Profile0Level45) ) && + iBitStreamMode != EVedVideoBitstreamModeMPEG4ShortHeader && + iBitStreamMode != EVedVideoBitstreamModeH263 && + h263mbi) + { + free(h263mbi); + } + + if ( iOutBuffer ) + { + + PRINT((_L("CMPEG4Transcoder: finish one frame successfully, buffer size %d"), + iOutBuffer->getIndex)); + } + +#ifdef _DEBUG + if (iOutBuffer->getIndex > KInitialBufferSize) + { + PRINT((_L("CMPEG4Transcoder: Output buffer size from engine is not big enough! check KInitialBufferSize"))); + + } +#endif + if ( iOutBuffer ) + { + VDTASSERT(iOutBuffer->getIndex < KInitialBufferSize); + } +} + +/* +* H263EscapeCoding +* +* Parameters: +* +* Function: +* Indicates whether escape vlc coding is used in one block +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::H263EscapeCoding(int aIndex, int fEscapeCodeUsed) +{ + iEscapeCodeUsed[aIndex] = fEscapeCodeUsed; +} + +/* +* SetTranscoding +* +* Parameters: +* +* Function: +* Indicates whether we need to do MPEG4 bitstream transcoding +* Returns: +* TX error codes +* Error codes: +* None +* +*/ +int CMPEG4Transcoder::SetTranscoding(vdeDecodeParamters_t *aDecoderInfo) +{ + iColorEffect = aDecoderInfo->aColorEffect; + iColorToneU = aDecoderInfo->aColorToneU; + iColorToneV = aDecoderInfo->aColorToneV; + iBitStreamMode = (TVedVideoBitstreamMode)aDecoderInfo->streamMode; + + iTargetFormat = aDecoderInfo->aOutputVideoFormat; + iDoModeTranscoding = aDecoderInfo->fModeChanged ? ETrue: EFalse; + iDoTranscoding = (iColorEffect || iDoModeTranscoding); + + /* set to proper value */ + iOutputMpeg4TimeIncResolution = *(aDecoderInfo->aMPEG4TargetTimeResolution); + + /* allocate buffer for MPEG4 - > H263 transcoding */ + /* the following is used if spatial domain processing is not done */ + + if ( ( (iTargetFormat == EVedVideoTypeH263Profile0Level10) || + (iTargetFormat == EVedVideoTypeH263Profile0Level45) ) && + iBitStreamMode != EVedVideoBitstreamModeMPEG4ShortHeader && + iBitStreamMode != EVedVideoBitstreamModeH263) + { + h263mbi = (tMBInfo*) malloc (sizeof(tMBInfo) * iNumMBsInOneVOP); + if (!h263mbi) + { + PRINT((_L("CMPEG4Transcoder::SetTranscoding - h263mbi creation failed"))); + deb("CMPEG4Transcoder::SetTranscoding - h263mbi creation failed\n"); + + return TX_ERR; + } + memset(h263mbi, 0, sizeof(tMBInfo) * iNumMBsInOneVOP); + } + + return TX_OK; +} + + + + +/* +* BeginOneVideoPacket +* +* Parameters: +* +* Function: +* Records the position before one Video packet is processed +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::BeginOneVideoPacket(dvpVPInParam_t *aVPin) +{ + VDTASSERT(iInBuffer); + VDTASSERT(aVPin); + + iCurVPIn = aVPin; + iVPStartByteIndex = iInBuffer->getIndex; + iVPStartBitIndex = iInBuffer->bitIndex; + + iCurMBNumInVP = -1; + + iStuffingBitsUsed = 0; + + iVopCodingType = aVPin->pictParam->pictureType; + iBitStreamMode = sGetMPEG4Mode(aVPin->pictParam->error_res_disable, + aVPin->pictParam->data_partitioned, aVPin->pictParam->reversible_vlc); +} + + +/* +* sConstructH263PicHeader +* +* Parameters: +* lBitOut output buffer +* quant quant value to be put in header +* picType VDX_VOP_TYPE_P or VDX_VOP_TYPE_I +* tr time increament +* Function: +* Writes the pic header into bit-stream for one MPEG4 frame +* Returns: +* None +* Error codes: +* None +* +*/ +void sConstructH263PicHeader(bibBuffer_t *lBitOut, int picType, int quant, int tr, int aVOPNotCoded, int aFormat) + +{ + if (aVOPNotCoded) + { + return; + } + /* ShortVideoStartMarker */ + sPutBits(lBitOut, 22, SHORT_VIDEO_START_MARKER); + /* TemporalReference */ + sPutBits(lBitOut, 8, (tr & 0x000000ff)); + /* Marker Bit */ + sPutBits(lBitOut, 1, MARKER_BIT); + /* Zero Bit */ + sPutBits(lBitOut, 1, 0); + /* SplitScreenIndicator = 0 */ + sPutBits(lBitOut, 1, 0); + /* DocumentCameraIndicator = 0 */ + sPutBits(lBitOut, 1, 0); + /* FullPictureFreezeRelease = 0 */ + sPutBits(lBitOut, 1, 0); + /* Source Fromat */ + sPutBits(lBitOut, 3, aFormat); + /* PictureCodingType 0 for intra, 1 for inter */ + sPutBits(lBitOut, 1, picType == VDX_VOP_TYPE_P); + /* UMV= 0 */ + sPutBits(lBitOut, 1, 0); + /* SAC = 0 */ + sPutBits(lBitOut, 1, 0); + /* Advanced Prediction = 0 */ + sPutBits(lBitOut, 1, 0); + /* PB frame = 0 */ + sPutBits(lBitOut, 1, 0); + /* VOPQuant */ + sPutBits(lBitOut, 5, quant); + /* ZeroBIt */ + sPutBits(lBitOut, 1, 0); + /* Pei = 0 */ + sPutBits(lBitOut, 1, 0); +} + + +/* +* VOPHeaderEnded +* +* Parameters: +* +* Function: +* Copy the VOP Header to output buffer +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::VOPHeaderEnded(int aStartByteIndex, int aStartBitIndex, + int aQuant, int aPicType, int aFrameNum, int aVOPNotCoded) +{ + const int KNumMbInSqcif = 48; + const int KNumMbInQcif = 99; + const int KNumMbInCif = 396; + + if (iTargetFormat == EVedVideoTypeH263Profile0Level10 || iTargetFormat == EVedVideoTypeH263Profile0Level45) + { + int sourceFormat = 2; // qcif + /* note: other formate not supported */ + if (iNumMBsInOneVOP == KNumMbInSqcif) /* sqcif */ + { + sourceFormat = 1; // sqcif + } + else if (iNumMBsInOneVOP == KNumMbInQcif) /* qcif */ + { + sourceFormat = 2; // qcif + } + else if (iNumMBsInOneVOP == KNumMbInCif) /* cif */ + { + sourceFormat = 3; // cif + } + sConstructH263PicHeader(iOutBuffer, aPicType, aQuant, 0, aVOPNotCoded, sourceFormat); + PRINT((_L("CMPEG4Transcoder: MPEG4 -> H263: picture header generated"))); + } + /* Copy the VOP header */ + else + { + bufEdit.copyMode = CopyWhole; // whole + CopyStream(iInBuffer,iOutBuffer,&bufEdit,aStartByteIndex,aStartBitIndex); + } + iPreQuant = aQuant; + iStuffingBitsUsed = 0; + + iCurQuant = aQuant; + /* Color Toning */ + if (!aFrameNum || !iRefQuant) + { + iRefQuant = iCurQuant; + iDcScaler = GetMpeg4DcScalerUV(iRefQuant); + } + +} + + +/* +* VOPEnded +* +* Parameters: +* +* Function: +* This function is called when one VOP has ended +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::VOPEnded() +{ + /* check if MBs are lost */ + int dataPartitioned = (iBitStreamMode == EVedVideoBitstreamModeMPEG4DP_RVLC || iBitStreamMode == EVedVideoBitstreamModeMPEG4Resyn_DP_RVLC + || iBitStreamMode == EVedVideoBitstreamModeMPEG4DP || iBitStreamMode == EVedVideoBitstreamModeMPEG4Resyn_DP); + + if (iLastMBNum != iNumMBsInOneVOP - 1 && !(dataPartitioned && !iDoModeTranscoding)) + { + for (int i = iLastMBNum+1; i < iNumMBsInOneVOP; i++) + { + /* output 1 bit COD */ + sPutBits (iOutBuffer, 1, 1); + } + } + + iLastMBNum = iNumMBsInOneVOP - 1; + /* bits need to be stuffed in the output buffer at the end VOP */ + if (!dataPartitioned && iTargetFormat == EVedVideoTypeMPEG4SimpleProfile) + { + if (!iStuffingBitsUsed) + { + vdtStuffBitsMPEG4(iOutBuffer); + } + iStuffingBitsUsed = 1; + } + else if (iTargetFormat == EVedVideoTypeH263Profile0Level10 || iTargetFormat == EVedVideoTypeH263Profile0Level45) + { + sStuffBitsH263(iOutBuffer); + } + + PRINT((_L("CMPEG4Transcoder: VOPEnded. color effect: %d, format convert %d, do transcoding: %d streammode: %d, outputformat: %d "), + iColorEffect, iDoModeTranscoding, iDoTranscoding, iBitStreamMode, iTargetFormat)); +} + +/* +* AfterOneVideoPacketHeader +* +* Parameters: +* +* Function: +* This function is called after retreiving the VP +* Records the position before the content of the video packet is processed +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::AfterVideoPacketHeader(dvpVPInOutParam_t *aVPInfo) +{ + VDTASSERT(aVPInfo); + iCurVPInOut = aVPInfo; + + iVPHeaderEndByteIndex = iInBuffer->getIndex; + iVPHeaderEndBitIndex = iInBuffer->bitIndex; + + /* Color Toning */ + iCurQuant = aVPInfo->quant; + + /* Copy the VP header to output stream. Note; the first VP does not have a VP header */ + if (iTargetFormat == EVedVideoTypeMPEG4SimpleProfile) + { + bufEdit.copyMode = CopyWhole; /* whole */ + CopyStream(iInBuffer,iOutBuffer,&bufEdit,iVPStartByteIndex,iVPStartBitIndex); + } +} + + +/* +* OneVPEnded +* +* Parameters: +* +* Function: +* This function is called after one VP contents are retrieved +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::OneVPEnded() +{ + if (!iDoTranscoding) + { + /* no transcoding, copy whole content VP */ + bufEdit.copyMode = CopyWhole; + CopyStream(iInBuffer,iOutBuffer,&bufEdit,iVPHeaderEndByteIndex,iVPHeaderEndBitIndex); + iStuffingBitsUsed = 1;// also stuffing is copied + } + else + { + int dataPartitioned = (iBitStreamMode == EVedVideoBitstreamModeMPEG4DP_RVLC || iBitStreamMode == EVedVideoBitstreamModeMPEG4Resyn_DP_RVLC + || iBitStreamMode == EVedVideoBitstreamModeMPEG4DP || iBitStreamMode == EVedVideoBitstreamModeMPEG4Resyn_DP); + int nextExpectedMBNum = iCurVPInOut->currMBNum; + + if (dataPartitioned && !iDoModeTranscoding) + { + /* if data is partitioned and we are not doing format transcoding, + not coded MBs info is already in data partition 1 + */ + } + else + { + /* MBs are lost or not coded, */ + for (int i = iLastMBNum+1; i < nextExpectedMBNum; i++) + { + /* output 1 bit COD */ + sPutBits (iOutBuffer, 1, 1); + } + } + + iLastMBNum = nextExpectedMBNum - 1; + /* bits need to be stuffed in the output buffer at the end of vp in all cases (bw or not) */ + if (iTargetFormat == EVedVideoTypeMPEG4SimpleProfile) + { + if (!iStuffingBitsUsed) + { + vdtStuffBitsMPEG4(iOutBuffer); + } + iStuffingBitsUsed = 1; + } + } +} + + + +/* +* BeginOneMB +* +* Parameters: +* +* Function: +* Records the position before one MB is processed +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::BeginOneMB(int aMBNum) +{ + VDTASSERT(iInBuffer); + + iMBStartByteIndex = iInBuffer->getIndex; + iMBStartBitIndex = iInBuffer->bitIndex; + iCurMBNum = aMBNum; + + // Color Toning + iCurMBNumInVP++; + + if ((iBitStreamMode == EVedVideoBitstreamModeMPEG4ShortHeader || iBitStreamMode == EVedVideoBitstreamModeH263) && iDoModeTranscoding) + { + /* H263 -> MPEG4 */ + VDTASSERT(iH263MBVPNum); + iH263MBVPNum[iCurMBNum]= iVideoPacketNumInMPEG4; + } +} + +/* +* BeginOneBlock +* +* Parameters: +* +* Function: +* Records the position before one block in MB is processed +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::BeginOneBlock(int aBlockIndex) +{ + VDTASSERT(aBlockIndex >= 0 && aBlockIndex < 6); + + iBlockStartByteIndex[aBlockIndex] = iInBuffer->getIndex; + iBlockStartBitIndex[aBlockIndex] = iInBuffer->bitIndex; +} + + +/* +* OneIMBDataStarted +* +* Parameters: +* +* Function: +* This function is called after the MB header is read; start one IMB, +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::OneIMBDataStarted(vdxIMBListItem_t *aMBInstance) +{ + VDTASSERT(aMBInstance); + VDTASSERT(iCurIMBinstance); + iMBCodingType = VDX_MB_INTRA; + iVopCodingType = VDX_VOP_TYPE_I; + iMBType[iCurMBNum] = iMBCodingType; + + + memcpy(iCurIMBinstance, aMBInstance, sizeof(vdxIMBListItem_t)); +} + +/* +* OnePMBDataStarted +* +* Parameters: +* +* Function: +* This function is called after the MB header is read; start one PMB, +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::OnePMBDataStarted(vdxPMBListItem_t *aMBInstance) +{ + VDTASSERT(aMBInstance); + VDTASSERT(iCurPMBinstance); + + iMBCodingType = aMBInstance->mbClass; + iVopCodingType = VDX_VOP_TYPE_P; + iMBType[iCurMBNum] = iMBCodingType; + + memcpy(iCurPMBinstance, aMBInstance, sizeof(vdxPMBListItem_t)); +} + + + +/* +* OneIMBDataStartedDataPartitioned +* +* Parameters: +* +* Function: +* Add one IMB instance, It is done after parsing Part1 and Part2 before the block data for current MB +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::OneIMBDataStartedDataPartitioned(vdxIMBListItem_t *aMBInstance, dlst_t *aMBList, int aCurrMBNumInVP, int aMBNum) +{ + VDTASSERT(aMBInstance); // at this point, the instance should not be null + VDTASSERT(aMBList); + + memcpy(iCurIMBinstance, aMBInstance, sizeof(vdxIMBListItem_t)); + iCurMBNumInVP = aCurrMBNumInVP; + iCurMBNum = aMBNum; + iMBList = aMBList; + iMBCodingType = VDX_MB_INTRA; + iVopCodingType = VDX_VOP_TYPE_I; + iMBType[iCurMBNum] = iMBCodingType; + + if (!iCurMBNumInVP && iDoTranscoding) + { + if (!iDoModeTranscoding) + { + /* We are not doing bitstream transcoding, + we have color effect here and need to reconstruct data partitions. + */ + ReconstructIMBPartitions(); + } + } +} + +/* +* OnePMBDataStartedDataPartitioned +* +* Parameters: +* +* Function: +* Add one IMB instance, It is done after parsing Part1 and Part2 before the block data for current MB +* Note: PMB may be INTRA coded. +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::OnePMBDataStartedDataPartitioned(vdxPMBListItem_t *aMBInstance, dlst_t *aMBList, int aCurrMBNumInVP, int aMBNum) +{ + VDTASSERT(aMBInstance); /* at this point, the instance should not be null */ + VDTASSERT(aMBList); + + memcpy(iCurPMBinstance, aMBInstance, sizeof(vdxPMBListItem_t)); + iCurMBNumInVP = aCurrMBNumInVP; + iCurMBNum = aMBNum; + iMBList = aMBList; + iMBCodingType = aMBInstance->mbClass; + iVopCodingType = VDX_VOP_TYPE_P; + iMBType[iCurMBNum] = iMBCodingType; + + if (!aMBInstance->fCodedMB && iDoModeTranscoding) + { + /* this MB is not coded and need to be converted to target mode, + out put the possible MB stuffing bits and COD + */ + /* MB stuffing bits if they exsit */ + vdtCopyBuffer(iInBuffer, iOutBuffer, + aMBInstance->DataItemStartByteIndex[11], aMBInstance->DataItemStartBitIndex[11], + aMBInstance->DataItemEndByteIndex[11], aMBInstance->DataItemEndBitIndex[11]); + /* It is a not-coded MB, output 1 bit COD (it always exists in P frame) */ + sPutBits (iOutBuffer, 1, 1); + iLastMBNum = iCurMBNum; + } + else if (!iCurMBNumInVP && iDoTranscoding) + { + if (!iDoModeTranscoding) + { + /* We are not doing bitstream transcoding, + we have color effect here and need to reconstruct data partitions. + */ + ReconstructPMBPartitions(); + } + } +} + + + +/* +* TranscodingOneMB +* +* Parameters: +* +* Function: +* Transcoding one MB, which may include dequantization, requantization , and re-encoding +* Returns: +* DMD error codes since called from decmbdct +* +*/ +int CMPEG4Transcoder::TranscodingOneMB(dmdPParam_t *aParam = NULL) +{ +/* Because it has block data, this MB must be a coded MB, +which means the position indicated by iMBStartByteIndex and iMBStartBitIndex starts with a MCBPC + */ + VDTASSERT(!(!iCurPMBinstance->fCodedMB && iMBCodingType == VDX_MB_INTER)); + + if (!iDoTranscoding) + { + iLastMBNum = iCurMBNum; // need to update the variable to avoid marking this as noncoded MB + return TX_OK; + } + + int dataPartitioned = (iBitStreamMode == EVedVideoBitstreamModeMPEG4DP_RVLC || iBitStreamMode == EVedVideoBitstreamModeMPEG4Resyn_DP_RVLC + || iBitStreamMode == EVedVideoBitstreamModeMPEG4DP || iBitStreamMode == EVedVideoBitstreamModeMPEG4Resyn_DP); + + if (dataPartitioned) + { + /* since we need to handle MB stuffing bits, which are handle outside the transcoder in other modes, + not coded MBs and MB stuffing bits are handled in OnePMBDataStartedDataPartitioned, + ReconstuctI/PMBPartitios or ConstructRegularMPEG4MBData + */ + } + else if(iCurMBNum != iLastMBNum + 1 ) + { + /* if previous MBs are lost or not coded, we copy one MB with COD = 1; */ + for (int i = 0 ; i < iCurMBNum - iLastMBNum - 1; i++) + { + /* output 1 bit COD */ + sPutBits (iOutBuffer, 1, 1); + } + } + + int newMCBPCLen = 0; + int newMCBPC = 0; + int oldMCBPCLen = 0; + + /* determine whether to change mcbpc */ + if (iColorEffect) + { + if (iVopCodingType == VDX_VOP_TYPE_P) + { + oldMCBPCLen = vdtGetPMBBlackAndWhiteMCBPC(newMCBPCLen, newMCBPC, iCurPMBinstance->mcbpc); + } + else + { + oldMCBPCLen = vdtGetIMBBlackAndWhiteMCBPC(newMCBPCLen, newMCBPC, iCurIMBinstance->mcbpc); + } + } + + + + if (iDoModeTranscoding && ( (iTargetFormat == EVedVideoTypeH263Profile0Level10) || + (iTargetFormat == EVedVideoTypeH263Profile0Level45) ) ) + { + if ( ConstructH263MBData(aParam, newMCBPCLen, newMCBPC) != VDC_OK ) + { + return TX_ERR; + } + } + else /* possible H263->MPEG4 transcoding */ + + { + /* MPEG4 with VDT_RESYN and VDT_REGULAR, we only do bitstream copying */ + if ( iBitStreamMode == EVedVideoBitstreamModeMPEG4Resyn || iBitStreamMode == EVedVideoBitstreamModeMPEG4Regular || + ((iBitStreamMode ==EVedVideoBitstreamModeMPEG4ShortHeader || iBitStreamMode == EVedVideoBitstreamModeH263) && !iDoModeTranscoding) ) + { + /* the MB stuffing is taken card of outside in file viddemux.cpp + we only need to output COD, MCBPC + */ + int mcbpcStartByteIndex, mcbpcStartBitIndex; + + if (iVopCodingType == VDX_VOP_TYPE_I) + { + mcbpcStartByteIndex = iCurIMBinstance->DataItemStartByteIndex[0]; + mcbpcStartBitIndex = iCurIMBinstance->DataItemStartBitIndex[0]; + } + else + { + mcbpcStartByteIndex = iCurPMBinstance->DataItemStartByteIndex[0]; + mcbpcStartBitIndex = iCurPMBinstance->DataItemStartBitIndex[0]; + /* It is a coded MB, output 1 bit COD (it always exists in P frame) */ + sPutBits (iOutBuffer, 1, 0); + } + + if (!iColorEffect) + { + bufEdit.copyMode = CopyWhole; /* whole */ + CopyStream(iInBuffer,iOutBuffer,&bufEdit,mcbpcStartByteIndex,mcbpcStartBitIndex); + } + else + { + /* modify mcbpc and copy only the Y data */ + bufEdit.copyMode = CopyWithEdit; // copy with edit + bufEdit.editParams[0].StartByteIndex = mcbpcStartByteIndex; + bufEdit.editParams[0].StartBitIndex = mcbpcStartBitIndex; + bufEdit.editParams[0].curNumBits = oldMCBPCLen; + bufEdit.editParams[0].newNumBits = newMCBPCLen; + bufEdit.editParams[0].newValue = newMCBPC; + CopyStream(iInBuffer,iOutBuffer,&bufEdit,mcbpcStartByteIndex,mcbpcStartBitIndex); + + /* disgard the UV data */ + int16 errorCode = 0; + int bitsToRewind = ((iInBuffer->getIndex << 3) + 7 - iInBuffer->bitIndex) + - ((iBlockStartByteIndex[4] << 3) + 7 - iBlockStartBitIndex[4]); + bibRewindBits(bitsToRewind, iOutBuffer, &errorCode ); + + if (iMBCodingType == VDX_MB_INTRA) + { + if (iBitStreamMode == EVedVideoBitstreamModeMPEG4ShortHeader || iBitStreamMode == EVedVideoBitstreamModeH263) + { + sResetH263IntraDcUV(iOutBuffer, iColorToneU, iColorToneV); + } + else + { + ResetMPEG4IntraDcUV(); + } + } + } + } + + else if ((iBitStreamMode == EVedVideoBitstreamModeMPEG4ShortHeader || iBitStreamMode == EVedVideoBitstreamModeH263) && iDoModeTranscoding) + { + H263ToMPEG4MBData(newMCBPCLen, newMCBPC); + } + + else /* data partitioned */ + { + if (iDoModeTranscoding) + { + /* for data partitioned bitstream, we do the bitstream rearrangement */ + ConstructRegularMPEG4MBData(newMCBPCLen, newMCBPC); + } + else + { + /* copy the ACs or DCTs */ + bufEdit.copyMode = CopyWhole; // whole + CopyStream(iInBuffer,iOutBuffer,&bufEdit,iBlockStartByteIndex[0],iBlockStartBitIndex[0]); + if (iColorEffect) + { + /* discard U V data */ + int16 errorCode = 0; + int bitsToRewind = ((iInBuffer->getIndex << 3) + 7 - iInBuffer->bitIndex) + - ((iBlockStartByteIndex[4] << 3) + 7 - iBlockStartBitIndex[4]); + bibRewindBits(bitsToRewind, iOutBuffer, &errorCode ); + } + } + } + + } + iLastMBNum = iCurMBNum; + return TX_OK; +} + + + + +/* +* ReconstructIMBPartitions +* +* Parameters: +* +* Function: +* Recontruct the partitions for color effect when we are not doing format transcoding +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::ReconstructIMBPartitions() +{ + vdxIMBListItem_t *MBinstance; + int *dataItemStartByteIndex; + int *dataItemStartBitIndex; + int *dataItemEndByteIndex; + int *dataItemEndBitIndex; + int newMCBPCLen = 0; + int newMCBPC = 0; + + VDTASSERT(iMBList); + + for (dlstHead(iMBList, (void **) &MBinstance); + MBinstance != NULL; + dlstNext(iMBList, (void **) &MBinstance)) + { + dataItemStartByteIndex = MBinstance->DataItemStartByteIndex; + dataItemStartBitIndex = MBinstance->DataItemStartBitIndex; + dataItemEndByteIndex = MBinstance->DataItemEndByteIndex; + dataItemEndBitIndex = MBinstance->DataItemEndBitIndex; + // MB stuffing bits if they exsit + vdtCopyBuffer(iInBuffer, iOutBuffer, dataItemStartByteIndex[11], dataItemStartBitIndex[11], + dataItemEndByteIndex[11], dataItemEndBitIndex[11]); + + /* MCBPC */ + if (iColorEffect) + { + /* MCBPC Changed. Ignore the old value (not used) */ + vdtGetIMBBlackAndWhiteMCBPC(newMCBPCLen, newMCBPC, MBinstance->mcbpc); + sPutBits(iOutBuffer, newMCBPCLen, newMCBPC); + } + else + { + vdtCopyBuffer(iInBuffer, iOutBuffer, + dataItemStartByteIndex[0], dataItemStartBitIndex[0], + dataItemEndByteIndex[0], dataItemEndBitIndex[0]); + } + + /* DQUANT, if it exsits */ + vdtCopyBuffer(iInBuffer, iOutBuffer, + dataItemStartByteIndex[1], dataItemStartBitIndex[1], + dataItemEndByteIndex[1], dataItemEndBitIndex[1]); + + /* INTRA DCs */ + if (!iColorEffect) + { + vdtCopyBuffer(iInBuffer, iOutBuffer, + dataItemStartByteIndex[4], dataItemStartBitIndex[4], + dataItemEndByteIndex[4], dataItemEndBitIndex[4]); + } + else + { + if (!(VDT_NO_DATA(dataItemStartByteIndex[4], dataItemStartBitIndex[4], + dataItemEndByteIndex[4], dataItemEndBitIndex[4]))) + { + vdtCopyBuffer(iInBuffer, iOutBuffer, + dataItemStartByteIndex[4], dataItemStartBitIndex[4], + dataItemStartByteIndex[8], dataItemStartBitIndex[8]); + ResetMPEG4IntraDcUV(); + } + } + } + + /* DC marker */ + sPutBits(iOutBuffer, DC_MARKER_LENGTH, DC_MARKER); + + for (dlstHead(iMBList, (void **) &MBinstance); + MBinstance != NULL; + dlstNext(iMBList, (void **) &MBinstance)) + { + dataItemStartByteIndex = MBinstance->DataItemStartByteIndex; + dataItemStartBitIndex = MBinstance->DataItemStartBitIndex; + dataItemEndByteIndex = MBinstance->DataItemEndByteIndex; + dataItemEndBitIndex = MBinstance->DataItemEndBitIndex; + + /* ac_pred_flag */ + vdtCopyBuffer(iInBuffer, iOutBuffer, + dataItemStartByteIndex[3], dataItemStartBitIndex[3], + dataItemEndByteIndex[3], dataItemEndBitIndex[3]); + + /* CBPY */ + vdtCopyBuffer(iInBuffer, iOutBuffer, + dataItemStartByteIndex[2], dataItemStartBitIndex[2], + dataItemEndByteIndex[2], dataItemEndBitIndex[2]); + } + + /* make sure the head of the list is reset */ + dlstHead(iMBList, (void **) &MBinstance); +} + +/* +* ReconstructPMBPartitions +* +* Parameters: +* +* Function: +* Recontruct the partitions for color effect when we are not doing format transcoding +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::ReconstructPMBPartitions() +{ + vdxPMBListItem_t *MBinstance; + int *dataItemStartByteIndex; + int *dataItemStartBitIndex; + int *dataItemEndByteIndex; + int *dataItemEndBitIndex; + int newMCBPCLen = 0; + int newMCBPC = 0; + + VDTASSERT(iMBList); + + for (dlstHead(iMBList, (void **) &MBinstance); + MBinstance != NULL; + dlstNext(iMBList, (void **) &MBinstance)) + { + dataItemStartByteIndex = MBinstance->DataItemStartByteIndex; + dataItemStartBitIndex = MBinstance->DataItemStartBitIndex; + dataItemEndByteIndex = MBinstance->DataItemEndByteIndex; + dataItemEndBitIndex = MBinstance->DataItemEndBitIndex; + + /* MB stuffing bits if they exsit */ + vdtCopyBuffer(iInBuffer, iOutBuffer, dataItemStartByteIndex[11], dataItemStartBitIndex[11], + dataItemEndByteIndex[11], dataItemEndBitIndex[11]); + + if (MBinstance->fCodedMB) + { + /* output 1 bit COD, coded */ + sPutBits (iOutBuffer, 1, 0); + + /* MCBPC */ + if (iColorEffect) + { + /* MCBPC Changed, ignore the return value */ + vdtGetPMBBlackAndWhiteMCBPC(newMCBPCLen, newMCBPC, MBinstance->mcbpc); + sPutBits(iOutBuffer, newMCBPCLen, newMCBPC); + } + else + { + vdtCopyBuffer(iInBuffer, iOutBuffer, + dataItemStartByteIndex[0], dataItemStartBitIndex[0], + dataItemEndByteIndex[0], dataItemEndBitIndex[0]); + } + + /* MVs, if they exist */ + vdtCopyBuffer(iInBuffer, iOutBuffer, + dataItemStartByteIndex[10], dataItemStartBitIndex[10], + dataItemEndByteIndex[10], dataItemEndBitIndex[10]); + } + else + { + /* output 1 bit COD, not coded */ + sPutBits (iOutBuffer, 1, 1); + } + } + + /* MM marker */ + sPutBits(iOutBuffer, MOTION_MARKER_LENGTH, MOTION_MARKER); + + for (dlstHead(iMBList, (void **) &MBinstance); + MBinstance != NULL; + dlstNext(iMBList, (void **) &MBinstance)) + { + if (MBinstance->fCodedMB) + { + dataItemStartByteIndex = MBinstance->DataItemStartByteIndex; + dataItemStartBitIndex = MBinstance->DataItemStartBitIndex; + dataItemEndByteIndex = MBinstance->DataItemEndByteIndex; + dataItemEndBitIndex = MBinstance->DataItemEndBitIndex; + + /* ac_pred_flag, if it exsits */ + vdtCopyBuffer(iInBuffer, iOutBuffer, + dataItemStartByteIndex[3], dataItemStartBitIndex[3], + dataItemEndByteIndex[3], dataItemEndBitIndex[3]); + + /* CBPY, */ + vdtCopyBuffer(iInBuffer, iOutBuffer, + dataItemStartByteIndex[2], dataItemStartBitIndex[2], + dataItemEndByteIndex[2], dataItemEndBitIndex[2]); + /* DQUANT, if it exsits */ + vdtCopyBuffer(iInBuffer, iOutBuffer, + dataItemStartByteIndex[1], dataItemStartBitIndex[1], + dataItemEndByteIndex[1], dataItemEndBitIndex[1]); + + /* INTRA DCs, if they exsit */ + if (!iColorEffect) + { + vdtCopyBuffer(iInBuffer, iOutBuffer, + dataItemStartByteIndex[4], dataItemStartBitIndex[4], + dataItemEndByteIndex[4], dataItemEndBitIndex[4]); + } + else + { + if (!(VDT_NO_DATA(dataItemStartByteIndex[4], dataItemStartBitIndex[4], + dataItemEndByteIndex[4], dataItemEndBitIndex[4]))) + { + vdtCopyBuffer(iInBuffer, iOutBuffer, + dataItemStartByteIndex[4], dataItemStartBitIndex[4], + dataItemStartByteIndex[8], dataItemStartBitIndex[8]); + ResetMPEG4IntraDcUV(); + } + } + } + } + + /* make sure the head of the list is reset */ + dlstHead(iMBList, (void **) &MBinstance); +} + +/* +* ResetMPEG4IntraDcUV +* +* Parameters: +* +* Function: +* This function resets the DCc for U V block in INTRA MB. +* Inputs are valid only with Color Effect +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::ResetMPEG4IntraDcUV() +{ + /* set INTRADC for u,v in the output buffer */ + TInt sizeU, sizeCodeU, sizeCodeLengthU, valueU, valueCodeU, valueCodeLengthU; + TInt sizeV, sizeCodeV, sizeCodeLengthV, valueV, valueCodeV, valueCodeLengthV; + TInt curDcScaler, delta; + TReal realDelta, realVal; + TInt mbh, mbv, mbd; // previous MB in the horizontal, vertical and diagonal directions + TInt codeMB; + + // initialize for codewords + sizeU = sizeCodeU = sizeCodeLengthU = valueCodeU = valueCodeLengthU = 0; + sizeV = sizeCodeV = sizeCodeLengthV = valueCodeV = valueCodeLengthV = 0; + + // initialize for prediction + mbh = mbv = mbd = VDX_MB_INTER; + codeMB = 0; + + // NOTE: VDX_MB_INTER=1, VDX_MB_INTRA=2, NOT-CODED MB has a value of 0 + if (iVopCodingType == VDX_VOP_TYPE_I) + { + /* encode intra DC coefficients for INTRA MBs of I-VOP if + either of the following is true: + - + - + else, do not encode intra DC + (because rest of MBs have differential intra DC, which is zero) + */ + if (!iCurMBNumInVP || + (!(iCurMBNum%iMBsinWidth) && (iCurMBNumInVPiMBsinWidth) + { + if (iCurMBNum%iMBsinWidth) + { + mbh = iMBType[iCurMBNum-1]; + mbd = iMBType[iCurMBNum-iMBsinWidth-1]; + } + mbv = iMBType[iCurMBNum-iMBsinWidth]; + } + else if (iCurMBNumInVP==iMBsinWidth) + { + if (iCurMBNum%iMBsinWidth) + { + mbh = iMBType[iCurMBNum-1]; + } + mbv = iMBType[iCurMBNum-iMBsinWidth]; + } + else if (iCurMBNumInVP>0) + { + if (iCurMBNum%iMBsinWidth) + { + mbh = iMBType[iCurMBNum-1]; + } + } + + // + if ((mbh8) + sPutBits(iOutBuffer, 1, 1); // marker bit + } + + // V + sPutBits(iOutBuffer, sizeCodeLengthV, sizeCodeV); // dct_dc_coeff size + if (sizeCodeV != 3) // size=0 + { + sPutBits(iOutBuffer, valueCodeLengthV, valueCodeV); // dct_dc_coeff differential + if (valueCodeLengthV>8) + sPutBits(iOutBuffer, 1, 1); // marker bit + } + } + else + { + sPutBits (iOutBuffer, 2, 3); /* U */ + sPutBits (iOutBuffer, 2, 3); /* V */ + } +} + + +/* +* GetMPEG4IntraDcCoeffUV +* +* Parameters: +* aValue coefficient value +* aDCAC pointer the reconstructed coefficients +* Function: +* This function fills the reconstructed DCAC values for INTRA block. +* Inputs are valid only with Color Effect +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::GetMPEG4IntraDcCoeffUV(TInt aValue, TInt& aSize, + TInt& aSizeCode, TInt& aSizeCodeLength, TInt& aValueCode, TInt& aValueCodeLength) +{ + int absVal = (aValue>=0 ? aValue : -aValue); + // size of aValueCode + for (aSize=0; absVal|0; absVal>>=1, aSize++) ; + if (aSize) + { + // codeword for aSize + if (aSize==1) + { + aSizeCode = 2; + aSizeCodeLength = 2; + } + else + { + aSizeCode = 1; + aSizeCodeLength = aSize; + } + + // codeword for aValue + aValueCode = aValue; + if (aValue<0) + aValueCode += ((1<= 0 && aIndex < 6); + + if (aDCAC && iDoModeTranscoding && (iTargetFormat == EVedVideoTypeH263Profile0Level10 || + iTargetFormat == EVedVideoTypeH263Profile0Level45)) + { + /* we only need the reconstructed DCACs for MPEG4 -> H263 */ + /* It is a coded block */ + memcpy(iDCTBlockData + (aIndex << 6), aDCAC, sizeof(int) * BLOCK_COEFF_SIZE); + } +} + +/* +* ConstructH263MBData +* +* Parameters: +* aNewMCBPCLen new length of mcbpc +* aNewMCBPC new mcbpc +* Function: +* This function creates a new H263 MB +* Inputs are valid only with Color Effect +* Returns: +* VDC error codes +* +*/ +int CMPEG4Transcoder::ConstructH263MBData(dmdPParam_t *aParam, int /*aNewMCBPCLen*/, int /*aNewMCBPC*/) +{ + /* MB data part1: output MCBPC, CBPY, DQuant, MV, intra DC etc */ + int *dataItemStartByteIndex; + int *dataItemStartBitIndex; + int *dataItemEndByteIndex; + int *dataItemEndBitIndex; + int quant, dquant; + int codedBlockPattern = 0; + + const unsigned int sDquant[5] = + { + 1, 0, (unsigned int)65536, 2, 3 + }; + + if (iVopCodingType == VDX_VOP_TYPE_P) + { + dataItemStartByteIndex = iCurPMBinstance->DataItemStartByteIndex; + dataItemStartBitIndex = iCurPMBinstance->DataItemStartBitIndex; + dataItemEndByteIndex = iCurPMBinstance->DataItemEndByteIndex; + dataItemEndBitIndex = iCurPMBinstance->DataItemEndBitIndex; + quant = iCurPMBinstance->quant; + dquant = iCurPMBinstance->dquant; + } + else + { + dataItemStartByteIndex = iCurIMBinstance->DataItemStartByteIndex; + dataItemStartBitIndex = iCurIMBinstance->DataItemStartBitIndex; + dataItemEndByteIndex = iCurIMBinstance->DataItemEndByteIndex; + dataItemEndBitIndex = iCurIMBinstance->DataItemEndBitIndex; + quant = iCurIMBinstance->quant; + dquant = iCurIMBinstance->dquant; + } + + if (iPreQuant != quant - dquant) + { + /* last quant in MPEG4 and H263 is different, dquant and VLCs may not be reused */ + if (abs(quant - iPreQuant) > 2) + { + /* VLCs cannot be reused, obtain the new ones */ + sQuantizeMB(iDCTBlockData, quant, iPreQuant, + iMBCodingType, iColorEffect); + quant = iPreQuant; + dquant = 0; + } + else + { + /* VLCs can be reused, but need to change dquant and MCBPC */ + dquant = quant - iPreQuant; + } + } + + /* MB stuffing bits if they exsit */ + vdtCopyBuffer(iInBuffer, iOutBuffer, dataItemStartByteIndex[11], dataItemStartBitIndex[11], + dataItemEndByteIndex[11], dataItemEndBitIndex[11]); + + if (iMBCodingType == VDX_MB_INTER) + { + VDTASSERT(aParam); + tMBPosition mbPos; + tMotionVector mvTestOutside; + mbPos.x = aParam->xPosInMBs * 16; + mbPos.y = aParam->yPosInMBs * 16; + mbPos.LeftBound = 0; + mbPos.RightBound = iVDEInstance->lumWidth << 1; + mbPos.TopBound = 0; + mbPos.BottomBound = iVDEInstance->lumHeight << 1; + mvTestOutside.mvx = (int16) ((aParam->mvx[0] << 1) / 10); + mvTestOutside.mvy = (int16) ((aParam->mvy[0] << 1) / 10); + + /* Three cases for MVs. 1): 4MVs -> need mapping 2). 1 outside frame MV 3) rounding type = 1 */ + vdcInstance_t * vdcTemp = (vdcInstance_t *)(iVDEInstance->vdcHInstance); + + /* Two cases for MVs. 1): 4MVs -> need mapping 2). 1 outside frame MV */ + if (iCurPMBinstance->numMVs == 4 || (iCurPMBinstance->numMVs == 1 && + vbmMVOutsideBound(&mbPos, &mvTestOutside, 1)) || vdcTemp->pictureParam.rtype) + { + int32 numTextureBits; + int32 searchRange = 16; + tMotionVector *initPred; + (h263mbi+iCurMBNum)->QuantScale = (int16) quant; + (h263mbi+iCurMBNum)->dQuant = (int16) dquant; + + /* note: this buffer is also used in the diamond search and half-pixel search !!!!! + which needs at least 8 points + */ + initPred = (tMotionVector*) malloc(8 * sizeof (tMotionVector)); + if(!initPred) + { + //Memory not available + return TX_ERR; + } + + + for (int i = 0; i < iCurPMBinstance->numMVs ; i++) + { + (initPred + i)->mvx = (int16) (aParam->mvx[i] / 10); /* the recorded mv is multipied by 10, */ + (initPred + i)->mvy = (int16) (aParam->mvy[i] / 10); /* the recorded mv is multipied by 10, */ + } + int32 noOfPredictors = iCurPMBinstance->numMVs; + + /* perform the 4MVs -> 1MV mapping, and output this MB */ + vbmPutInterMB(&mbPos, + iOutBuffer,aParam, + initPred, noOfPredictors, + (u_int32) iVDEInstance->lumWidth, (u_int32) iVDEInstance->lumHeight, + searchRange, iCurMBNum, &numTextureBits, + (int16)iColorEffect, h263mbi); + /* the MVs buffer is updated inside vbmPutInterMB */ + + if (initPred) + free(initPred); + } + else + { + /* Here, for Inter MB with One inside Frame MV, we simply reuse the DCTs */ + VDTASSERT(iCurPMBinstance->numMVs == 1); + + /* It is a coded MB, output 1 bit COD (it always exists in P frame) */ + sPutBits (iOutBuffer, 1, 0); + int cbpy; + int mcbpcVal; + int len; + + codedBlockPattern = sFindCBP(iDCTBlockData, OFF); + mcbpcVal = iColorEffect? 0 : (codedBlockPattern & 3); + cbpy = ((codedBlockPattern >> 2) & 0xf); + vbmGetH263PMCBPC(dquant, iColorEffect, cbpy, mcbpcVal, len); + sPutBits(iOutBuffer, len, mcbpcVal); //MCBPC, CBPY + + /* DQUANT, if it exsits */ + if (dquant) + { + sPutBits(iOutBuffer, 2, sDquant[dquant + 2]); + } + /* recode MVs, one more indice exists in the MV VLC table in MPEG4 + moreover, vop_fcode can be larger than 1 (although it may rarely happens), + so it is better to redo the VLC coding + */ + /* the recorded mv is multipied by 10, in pixel unit */ + int16 mvx = (int16) ((aParam->mvx[0] << 1) / 10); + int16 mvy = (int16) ((aParam->mvy[0] << 1) / 10); + + tMotionVector lPredMV[4]; + tMBInfo *mbi = h263mbi + iCurMBNum; + + /* get the new predicted MV */ + vbmMvPrediction(mbi, iCurMBNum, lPredMV, (u_int32)iMBsinWidth); + + vbmEncodeMVDifferential(mvx - lPredMV[0].mvx, mvy - lPredMV[0].mvy, 1, iOutBuffer); + cbpy = 32; + /* following is the block level data */ + for (int i = 0; i < (iColorEffect? 4 : 6); i++) + { + int fBlockCoded = cbpy & codedBlockPattern; + if (fBlockCoded) + { + /* here we do the VLC coding again */ + int numTextureBits = 0; + vdtPutInterMBCMT(iOutBuffer,0, iDCTBlockData + i * BLOCK_COEFF_SIZE, &numTextureBits, ON); + } + cbpy >>= 1; + } + + /* update the MVs buffer */ + (h263mbi + iCurMBNum)->MV[0][0] = (int16) ((aParam->mvx[0] << 1) / 10); /* the recorded mv is multipied by 10 */ + (h263mbi + iCurMBNum)->MV[0][1] = (int16) ((aParam->mvy[0] << 1) / 10); /* the recorded mv is multipied by 10 */ + + } /* end of if 4MVs */ + } + else /* INTRA MB */ + { + /* update the MVs buffer */ + (h263mbi + iCurMBNum)->MV[0][0] = 0; + (h263mbi + iCurMBNum)->MV[0][1] = 0; + /* MPEG4 and H263 use different methods for INTRA MB, redo the VLC coding */ + int cbpy; + int mcbpcVal; + int len; + + codedBlockPattern = sFindCBP(iDCTBlockData, ON); + mcbpcVal = iColorEffect? 0 : (codedBlockPattern & 3); + cbpy = ((codedBlockPattern >> 2) & 0xf); + vbmGetH263IMCBPC(dquant, (iVopCodingType == VDX_VOP_TYPE_P), iColorEffect, cbpy, mcbpcVal, len); + sPutBits(iOutBuffer, len, mcbpcVal); //COD, MCBPC, CBPY + + /* DQUANT, if it exsits */ + if (dquant) + { + sPutBits(iOutBuffer, 2, sDquant[dquant + 2]); + } + cbpy = 32; + + /* following is the block level data */ + for (int i = 0; i < (iColorEffect? 4 : 6); i++) + { + /* requantize INTRA DC */ + /* DC Quantization */ + int coeff = (iDCTBlockData + i * BLOCK_COEFF_SIZE)[0] >> 3; + + if(coeff < 1) coeff = 1; + if(coeff > 254) coeff = 254; + if(coeff == 128) + { + sPutBits(iOutBuffer, 8, 255); + } + else + { + sPutBits(iOutBuffer, 8, coeff); + } + + (iDCTBlockData + i * BLOCK_COEFF_SIZE)[0] = coeff; + if(cbpy & codedBlockPattern) + { + int numTextureBits = 0; + vdtPutInterMBCMT(iOutBuffer,1, iDCTBlockData + i * BLOCK_COEFF_SIZE, &numTextureBits, ON); + } + cbpy >>= 1; + } + } + + if (iColorEffect && (iMBCodingType == VDX_MB_INTRA)) + { + ResetH263IntraDcUV(iOutBuffer, iColorToneU, iColorToneV); + } + iPreQuant = quant; + + return TX_OK; +} + +/* +* ConstructRegularMPEG4MBData +* +* Parameters: +* aNewMCBPCLen new length of mcbpc +* aNewMCBPC new mcbpc +* Function: +* This function rearranges the data for bitstream with data partitioning +* Only valid in Data Partitioned mode +* Inputs are valid only with Color Effect +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::ConstructRegularMPEG4MBData(int aNewMCBPCLen, int aNewMCBPC) +{ + /* MB data part1: output MCBPC, CBPY, DQuant, MV, intra DC etc */ + int *dataItemStartByteIndex; + int *dataItemStartBitIndex; + int *dataItemEndByteIndex; + int *dataItemEndBitIndex; + + if (iVopCodingType == VDX_VOP_TYPE_P) + { + dataItemStartByteIndex = iCurPMBinstance->DataItemStartByteIndex; + dataItemStartBitIndex = iCurPMBinstance->DataItemStartBitIndex; + dataItemEndByteIndex = iCurPMBinstance->DataItemEndByteIndex; + dataItemEndBitIndex = iCurPMBinstance->DataItemEndBitIndex; + } + else + { + dataItemStartByteIndex = iCurIMBinstance->DataItemStartByteIndex; + dataItemStartBitIndex = iCurIMBinstance->DataItemStartBitIndex; + dataItemEndByteIndex = iCurIMBinstance->DataItemEndByteIndex; + dataItemEndBitIndex = iCurIMBinstance->DataItemEndBitIndex; + } + + /* MB stuffing bits if they exsit */ + vdtCopyBuffer(iInBuffer, iOutBuffer, dataItemStartByteIndex[11], dataItemStartBitIndex[11], + dataItemEndByteIndex[11], dataItemEndBitIndex[11]); + + if (iVopCodingType == VDX_VOP_TYPE_P) + { + /* It is a coded MB, output 1 bit COD (it always exists in P frame) */ + sPutBits (iOutBuffer, 1, 0); + } + + /* MCBPC. NOTE: the positions do not include MCBPC stuffing bits !! */ + if (iColorEffect) + { + /* MCBPC Changed */ + sPutBits(iOutBuffer, aNewMCBPCLen, aNewMCBPC); + } + else + { + vdtCopyBuffer(iInBuffer, iOutBuffer, dataItemStartByteIndex[0], dataItemStartBitIndex[0], + dataItemEndByteIndex[0], dataItemEndBitIndex[0]); + } + /* ac_pred_flag, if it exsits */ + vdtCopyBuffer(iInBuffer, iOutBuffer, dataItemStartByteIndex[3], dataItemStartBitIndex[3], + dataItemEndByteIndex[3], dataItemEndBitIndex[3]); + + /* CBPY */ + vdtCopyBuffer(iInBuffer, iOutBuffer, dataItemStartByteIndex[2], dataItemStartBitIndex[2], + dataItemEndByteIndex[2], dataItemEndBitIndex[2]); + + /* DQUANT, if it exsits */ + vdtCopyBuffer(iInBuffer, iOutBuffer, dataItemStartByteIndex[1], dataItemStartBitIndex[1], + dataItemEndByteIndex[1], dataItemEndBitIndex[1]); + + if (iMBCodingType == VDX_MB_INTER) + { + /* MVs, if they exsit */ + vdtCopyBuffer(iInBuffer, iOutBuffer, dataItemStartByteIndex[10], dataItemStartBitIndex[10], + dataItemEndByteIndex[10], dataItemEndBitIndex[10]); + } + + /* following is the block level data */ + for (int i = 0; i < (iColorEffect? 4 : 6); i++) + { + /* INTRA DC, if it exsits */ + vdtCopyBuffer(iInBuffer, iOutBuffer, dataItemStartByteIndex[i + 4], dataItemStartBitIndex[i + 4], + dataItemEndByteIndex[i + 4], dataItemEndBitIndex[i + 4]); + + /* block data part2, AC or DCT coefficients */ + if (iBitStreamMode == EVedVideoBitstreamModeMPEG4DP_RVLC || iBitStreamMode == EVedVideoBitstreamModeMPEG4Resyn_DP_RVLC) + { + /* remember for data partitioning, the positions only indicate the + AC or DCTs coefficients + */ + if (VDT_NO_DATA(iBlockStartByteIndex[i], iBlockStartBitIndex[i], + iBlockEndByteIndex[i], iBlockEndBitIndex[i])) + { + /* no coefficients,skip this block */ + continue; + } + else + { + /* for RVLC coding, we transform the block data back to VLC */ + int numTextureBits = 0; + /* redo the entropy coding, RVLC -> VLC + only for AC (IMB) or DCT (PMB) coefficients + */ + if (iMBCodingType == VDX_MB_INTRA) + { + vdtPutIntraMBCMT(iOutBuffer,iDCTBlockData + i * BLOCK_COEFF_SIZE, &numTextureBits, i, 1, 0); + } + else + { + vdtPutInterMBCMT(iOutBuffer,0, iDCTBlockData + i * BLOCK_COEFF_SIZE, &numTextureBits, OFF); + } + } + } + else /* ouput the AC or DCT coefficients */ + { + bufEdit.copyMode = CopyWhole; /* CopyWhole */ + vdtCopyBuffer(iInBuffer,iOutBuffer, + iBlockStartByteIndex[i],iBlockStartBitIndex[i], + iBlockEndByteIndex[i],iBlockEndBitIndex[i]); + } + } + if (iColorEffect && (iMBCodingType == VDX_MB_INTRA)) + { + ResetMPEG4IntraDcUV(); + } +} + + + +/* +* AddOneBlockDataToMB +* +* Parameters: +* blockData block data before VLC coding, in ZigZag order +* Function: +* This function input one block data to current MB +* only here the whole MB data is retrieved (COD=0) +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::AddOneBlockDataToMB(int aBlockIndex, int *aBlockData) +{ + VDTASSERT(aBlockIndex >= 0 && aBlockIndex < 6); + + + if (aBlockData && iDoModeTranscoding) + { + /* iDCTBlockData is only used when we need to convert the bitstream to MPEG4_RESYN + It is a coded block + */ + if (iMBCodingType == VDX_MB_INTRA && (iTargetFormat == EVedVideoTypeH263Profile0Level10 || + iTargetFormat == EVedVideoTypeH263Profile0Level45)) + { + /* we only need the reconstructed DCACs, skipped */ + } + else + { + memcpy(iDCTBlockData + (aBlockIndex << 6), aBlockData, sizeof(int) * BLOCK_COEFF_SIZE); + } + } + else + { + memset(iDCTBlockData + (aBlockIndex << 6), 0, sizeof(int) * BLOCK_COEFF_SIZE); + } + + + + iBlockEndByteIndex[aBlockIndex] = iInBuffer->getIndex; + iBlockEndBitIndex[aBlockIndex] = iInBuffer->bitIndex; +} + +/* +* ErrorResilienceInfo +* +* Parameters: +* header VOL Header data +* Function: +* This function records the position of resnc_marker_disable bit +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::ErrorResilienceInfo(vdxVolHeader_t *header, int aByte, int aBit) +{ + if (header) + { + + memcpy(&iVOLHeader, header, sizeof(vdxVolHeader_t)); // save the header info + + } + else + { + iErrorResilienceStartByteIndex = aByte; /* save the bits position */ + iErrorResilienceStartBitIndex = aBit; + } +} + + + +/* +* MPEG4TimerResolution +* +* Parameters: +* +* Function: +* This function records the position of vop_time_increment_resolution bit +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::MPEG4TimerResolution(int aStartByteIndex, int aStartBitIndex) +{ + iTimeResolutionByteIndex = aStartByteIndex; + iTimeResolutionBitIndex = aStartBitIndex; +} + + + +void CMPEG4Transcoder::ConstructVOSHeader(int aMPEG4, vdeDecodeParamters_t *aDecoderInfo) +{ + if (!aMPEG4 ) + { + /* for H263 and MPEG4 shortheader, no vos generated */ + if (iErrorResilienceStartByteIndex == KDataNotValid && + iErrorResilienceStartBitIndex == KDataNotValid) + { + iBitStreamMode = EVedVideoBitstreamModeH263; // pure H.263 + aDecoderInfo->vosHeaderSize = aDecoderInfo->fModeChanged? KH263ToMpeg4VosSize : 0; + } + else + { + /* we went into the VOL layer. It is a MPEG4 bitstream with short header */ + iBitStreamMode = EVedVideoBitstreamModeMPEG4ShortHeader; /* MPEG4 shortheader */ + iShortHeaderEndByteIndex = iInBuffer->getIndex; + iShortHeaderEndBitIndex = iInBuffer->bitIndex; + aDecoderInfo->vosHeaderSize = aDecoderInfo->fModeChanged? KH263ToMpeg4VosSize : KShortHeaderMpeg4VosSize; + } + fFirstFrameInH263 = ETrue; + } + else + { + iNumMBsInOneVOP = (iVDEInstance->lumHeight * iVDEInstance->lumWidth) / 256; + + /* even iBitStreamMode is given outside, we renew it here anyway */ + iBitStreamMode = sGetMPEG4Mode(iVOLHeader.error_res_disable, + iVOLHeader.data_partitioned, iVOLHeader.reversible_vlc); + + if (iTargetFormat != EVedVideoTypeH263Profile0Level10 && + iTargetFormat != EVedVideoTypeH263Profile0Level45) /* EVedVideoTypeMPEG4SimpleProfile or None */ + { + /* copy from the begining of the input buffer */ + vdtCopyBuffer(iInBuffer,iOutBuffer,0,7, iTimeResolutionByteIndex, iTimeResolutionBitIndex); + /* it is 16 bits */ + sPutBits (iOutBuffer, KMpeg4VopTimeIncrementResolutionLength, *aDecoderInfo->aMPEG4TargetTimeResolution); + + int startByteIndex, startBitIndex; + startByteIndex = iTimeResolutionByteIndex + 2; + startBitIndex = iTimeResolutionBitIndex; + + sPutBits(iOutBuffer, 1, MARKER_BIT); + /* close fixed_vop_rate */ + sPutBits (iOutBuffer, 1, 0); /* it is 1 bit */ + + int num_bits = 0; + vdcInstance_t * vdcTemp = (vdcInstance_t *)(iVDEInstance->vdcHInstance); + if (vdcTemp->pictureParam.fixed_vop_rate) + { + for (num_bits = 1; ((vdcTemp->pictureParam.time_increment_resolution-1) >> num_bits) != 0; num_bits++) + { + } + } + num_bits += 2; + + /* following is to skip the fixed_vop_rate */ + int bitsRemain, bitShift = 0; + int bitsToMove = 0 ; + /* complete the byte */ + if (startBitIndex != 7) + { + bitShift = startBitIndex + 1; + bitsToMove = (num_bits < bitShift) ? num_bits : bitShift; + /* update statistics to take care of bit addition or byte completion */ + if (num_bits < bitShift) + { + /* bits skipped but byte not completed */ + startBitIndex -= bitsToMove; + } + else + { + /* byte completed */ + startByteIndex ++; + startBitIndex = 7; + } + } + /* full bytes to skip */ + startByteIndex += ((num_bits - bitsToMove) >> 3); + bitsRemain = (num_bits - bitsToMove) % 8; + + /* the remaining bits */ + startBitIndex = ( bitsRemain != 0) ? 7 - bitsRemain : startBitIndex; + + + /* check if we have user data in the end of VOL; it cannot be copied as such but needs to be byte aligned */ + /* first need to rewind the input buffer to be able to seek in it */ + int16 error = 0; + int curByteIndex = iInBuffer->getIndex; + int curBitIndex = iInBuffer->bitIndex; + int bits = ((curByteIndex - iTimeResolutionByteIndex)<<3) + (7-curBitIndex); + bibRewindBits(bits, iInBuffer, &error); + int sncCode = sncSeekMPEGStartCode(iInBuffer, + vdcTemp->pictureParam.fcode_forward, 1 /* don't check VOPs */, 1 /* check for user data*/, &error); + + /* record next resync position */ + int resyncByteIndex = iInBuffer->getIndex; + + int stuffBits = 0; + int userDataExists = 0; + if ( sncCode == SNC_USERDATA ) + { + /* copy only until this sync code, and copy the rest separately in the end. */ + userDataExists = 1; + } + else + { + /* No UD */ + /* restore the original pointers in iInBuffer */ + iInBuffer->getIndex = curByteIndex; + iInBuffer->bitIndex = curBitIndex; + } + + if (iDoModeTranscoding || aDecoderInfo->fHaveDifferentModes) + { + /* close the error resilience tools, change the bitstream to regular MPEG4 with resyn marker */ + int numBits = iVOLHeader.data_partitioned ? 3 : 2; + + bufEdit.copyMode = CopyWithEdit; + bufEdit.editParams[0].StartByteIndex = iErrorResilienceStartByteIndex; + bufEdit.editParams[0].StartBitIndex = iErrorResilienceStartBitIndex; + bufEdit.editParams[0].curNumBits = numBits; + bufEdit.editParams[0].newNumBits = 2; + bufEdit.editParams[0].newValue = 0; /* new codeword: resyn, no dp, no rvlc */ + CopyStream(iInBuffer,iOutBuffer,&bufEdit, startByteIndex,startBitIndex); /* copy from vop_time_increment_resolution */ + + /* rewind stuffing bits */ + int16 error; + sncRewindStuffing(iOutBuffer, &error); + + // stuff bits in outbuffer for next start code + vdtStuffBitsMPEG4(iOutBuffer); + } + else + { + + /* rewind stuffing bits */ + sncRewindStuffing(iInBuffer, &error); + + /* record the number of bits rewinded - can be from 0 to 8 */ + /* note that iInBuffer must be byte aligned before rewinding */ + if (iInBuffer->bitIndex == 7) // full byte rewind + { + stuffBits = ( (int)(iInBuffer->getIndex) < resyncByteIndex) ? 8 : 0; + } + else + { + stuffBits = iInBuffer->bitIndex + 1; + } + + /* copy the rest of VOS until the first VOP (or UD) */ + bufEdit.copyMode = CopyWhole; + vdtCopyBuffer(iInBuffer,iOutBuffer, startByteIndex,startBitIndex, + resyncByteIndex, iInBuffer->bitIndex); + + // stuff bits in outbuffer for next start code + vdtStuffBitsMPEG4(iOutBuffer); + + // move inbuffer pointer back to original value + bibForwardBits(stuffBits, iInBuffer); + } + + + if ( userDataExists ) + { + /* seek for VOP start code */ + int sncCode = sncSeekMPEGStartCode(iInBuffer, + vdcTemp->pictureParam.fcode_forward, vdcTemp->pictureParam.error_res_disable, 0, &error); + + /* rewind stuffing bits */ + sncRewindStuffing(iInBuffer, &error); + + // record the number of bits rewinded - can be from 0 to 8 + // note that iInBuffer must be byte aligned before rewinding + if (iInBuffer->bitIndex == 7) // full byte rewind + { + stuffBits = ( (int)(iInBuffer->getIndex) < resyncByteIndex) ? 8 : 0; + } + else + { + stuffBits = iInBuffer->bitIndex + 1; + } + + bufEdit.copyMode = CopyWhole; + vdtCopyBuffer(iInBuffer,iOutBuffer, resyncByteIndex, 7, + iInBuffer->getIndex, iInBuffer->bitIndex); + + // stuff bits in outbuffer for next start code + vdtStuffBitsMPEG4(iOutBuffer); + + // move inbuffer pointer back to original value + bibForwardBits(stuffBits, iInBuffer); + + + + } + + aDecoderInfo->vosHeaderSize = iOutBuffer->getIndex; + } + + PRINT((_L("CMPEG4Transcoder: ConstructVOSHeader. resyn: %d, data partitioned: %d, rvlc: %d, resolution: %d"), + iVOLHeader.error_res_disable, iVOLHeader.data_partitioned, iVOLHeader.reversible_vlc, + aDecoderInfo->iTimeIncrementResolution)); + } + PRINT((_L("CMPEG4Transcoder: streammode: %d, outputformat: %d, vos size : %d"), + iBitStreamMode, iTargetFormat, aDecoderInfo->vosHeaderSize)); +} + + + + +/**************************************************************** +* * +* Functions for H.263, or H.263 -> MPEG4 (only baseline H.263) * +* * +*****************************************************************/ + + +/* Luminance block dc-scaler value corresponding to QP values of 0-31 */ +const u_int8 sLumDCScalerTbl[32] = +{ + 0, 8, 8, 8, 8, 10, 12, 14, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 34, 36, 38, 40, 42, 44, 46 +}; + +/* Chrominance block dc-scaler value corresponding to QP values of 0-31 */ +const u_int8 sChrDCScalerTbl[32] = +{ + 0, 8, 8, 8, 8, 9, 9, 10, + 10, 11, 11, 12, 12, 13, 13, 14, + 14, 15, 15, 16, 16, 17, 17, 18, + 18, 19, 20, 21, 22, 23, 24, 25 +}; + +/* +* sGetMPEG4INTRADCValue +* +* Parameters: +* intraDC reconstructed intra DC from H263 +* QP quantion factor +* blockNum block number (0 to 5) +* currMBNum current MB number +* mbinWidth number of MBs in picure width +* dcData matrix to store the INTRA DC values +* mbVPNumber matrix recording the video packet number for each MB +* +* Function: +* This function gets the new intra DC for MPEG4 +* Returns: +* INTRA DC to put into MPEG4 bitstream +* Error codes: +* None +* +*/ +int sGetMPEG4INTRADCValue(int intraDC, int blockNum, int currMBNum, + int32 QP, int32 mbinWidth, int **dcData, int *mbVPNumber) +{ + int tempDCScaler; + int blockA = 0, blockB = 0, blockC = 0; + int gradHor, gradVer, predDC; + + VDTASSERT(currMBNum >= 0); + VDTASSERT(QP <= 31); + + /* Prediction blocks A (left), B (above-left), and C (above) */ + switch (blockNum) + { + case 0: + case 4: + case 5: + /* Y0, U, and V blocks */ + if (((currMBNum % mbinWidth) == 0) || /* Left edge */ + (mbVPNumber[currMBNum - 1] != mbVPNumber[currMBNum])) + { + blockA = 1024; /* fixed value for H263 */ + } + else + { + blockA = dcData[currMBNum - 1][blockNum > 3? blockNum : 1]; + } + + if (((currMBNum / mbinWidth) == 0) || /* Top Edge */ + ((currMBNum % mbinWidth) == 0) || /* Left Edge */ + (mbVPNumber[currMBNum - mbinWidth - 1] != mbVPNumber[currMBNum])) + { + blockB = 1024; + } + else + { + blockB = dcData[currMBNum - mbinWidth - 1][blockNum > 3? blockNum : 3]; + } + + if (((currMBNum / mbinWidth) == 0) || /* Top Edge */ + (mbVPNumber[currMBNum - mbinWidth] != mbVPNumber[currMBNum])) + { + blockC = 1024; + } + else + { + blockC = dcData[currMBNum - mbinWidth][blockNum > 3? blockNum : 2]; + } + break; + + case 1: + /* Y1 block */ + blockA = dcData[currMBNum][0]; + + if (((currMBNum / mbinWidth) == 0) || /* Top Edge */ + (mbVPNumber[currMBNum - mbinWidth] != mbVPNumber[currMBNum])) + { + blockB = 1024; + blockC = 1024; + } + else + { + blockB = dcData[currMBNum - mbinWidth][2]; + blockC = dcData[currMBNum - mbinWidth][3]; + } + break; + + case 2: + /* Y2 block */ + + if (((currMBNum % mbinWidth) == 0) || /* Left Edge */ + (mbVPNumber[currMBNum - 1] != mbVPNumber[currMBNum])) + { + blockA = 1024; + blockB = 1024; + } + else + { + blockA = dcData[currMBNum - 1][3]; + blockB = dcData[currMBNum - 1][1]; + } + + blockC = dcData[currMBNum][0]; + break; + + case 3: + /* Y3 block */ + + blockA = dcData[currMBNum][2]; + blockB = dcData[currMBNum][0]; + blockC = dcData[currMBNum][1]; + break; + + default: + break; + } + + gradHor = blockB - blockC; + gradVer = blockA - blockB; + + if ((abs(gradVer)) < (abs(gradHor))) + { + /* Vertical prediction (from C) */ + predDC = blockC; + } + else + { + /* Horizontal prediction (from A) */ + predDC = blockA; + } + + /* DC quantization */ + if (blockNum < 4) /* Luminance Block */ + { + intraDC += (sLumDCScalerTbl[QP] >> 1); + intraDC /= sLumDCScalerTbl[QP]; + + /* update the DC data matrix + note: for INTER MB, the entry is already preset to 1024!! + */ + dcData[currMBNum][blockNum] = intraDC * sLumDCScalerTbl[QP]; + } + else /* Chrominance block */ + { + intraDC += (sChrDCScalerTbl[QP] >> 1); + intraDC /= sChrDCScalerTbl[QP]; + /* update the DC data matrix + note: for INTER MB, the entry is already preset to 1024!! + */ + dcData[currMBNum][blockNum] = intraDC * sChrDCScalerTbl[QP]; + } + /* DC prediction */ + tempDCScaler = (blockNum<4)? sLumDCScalerTbl[QP] : sChrDCScalerTbl[QP]; + + return (intraDC - ((predDC + tempDCScaler/2) / tempDCScaler)); +} + +/* +* sPutVOLHeader +* +* Parameters: +* bitOut pointer to the output buffer +* aWidth picture width +* aHeight picture height +* aTimerResolution timer resolution for MPEG4 +* +* Function: +* This function writes the VOL header into bit-stream +* Returns: +* None +* Error codes: +* None +* +*/ +inline void sPutVOLHeader(bibBuffer_t* bitOut, int aWidth, int aHeight, int aTimerResolution) +{ + bibBuffer_t *lBitOut; + uint32 vop_time_increment_resolution; + + lBitOut = bitOut; + WRITE32(lBitOut, (uint32)VIDEO_OBJECT_LAYER_START_CODE); + /* RandomAccessibleVol == 1 means all VOP's can be decoded independently */ + sPutBits(lBitOut, 1, 0); + /* VideoObjectTypeIndication = SIMPLE OBJECT */ + sPutBits(lBitOut, 8, SIMPLE_OBJECT); + /* IsObjectLayerIdentifier */ + sPutBits(lBitOut, 1, 0); + /* AspectRatioInfo */ + sPutBits(lBitOut, 4, ASPECT_RATIO_INFO); + /* vol_control_parameters = 1 */ + sPutBits(lBitOut, 1, 1); + /* Chroma Format */ + sPutBits(lBitOut, 2, CHROMA_FORMAT); + /* LowDelay = 1; */ + sPutBits(lBitOut, 1, 1); + /* vbvParameters = 0; */ + sPutBits(lBitOut, 1, 0); + /* VideoObjectLayerShape == RECTANGULAR */ + sPutBits(lBitOut, 2, RECTANGULAR); + /* Marker Bit */ + sPutBits(lBitOut, 1, MARKER_BIT); + /* VopTimeIncrementResolution */ + vop_time_increment_resolution = aTimerResolution; + sPutBits(lBitOut, 16, vop_time_increment_resolution); + /* Marker Bit */ + sPutBits(lBitOut, 1, MARKER_BIT); + /* FixedVOPRate = 0, not fixed */ + sPutBits(lBitOut, 1, 0); + /* Marker Bit */ + sPutBits(lBitOut, 1, MARKER_BIT); + /* VideoObjectLayerWidth */ + sPutBits(lBitOut, 13, aWidth); + /* Marker Bit */ + sPutBits(lBitOut, 1, MARKER_BIT); + /* VideoObjectLayerHeight */ + sPutBits(lBitOut, 13, aHeight); + /* Marker Bit */ + sPutBits(lBitOut, 1, MARKER_BIT); + /* Interlaced = 0 */ + sPutBits(lBitOut, 1, 0); + /* ObmcDisable= 1 */ + sPutBits(lBitOut, 1, 1); + /* SpriteEnable = 0 */ + sPutBits(lBitOut, 1, 0); + /* Not8Bit = 0 */ + sPutBits(lBitOut, 1, 0); + /* QuantType = H263 (0) */ + sPutBits(lBitOut, 1, H263); + /* Complexity Estimation Disable = 1 */ + sPutBits(lBitOut, 1, 1); + /* ResyncMarkerDisable */ + sPutBits(lBitOut, 1, 0); /* H263 is converted to resyn_marker MPEG4 in video editor */ + /* DataPartioned */ + sPutBits(lBitOut, 1, 0); /* always 0 for H263 */ + /* Reversible VLC closed */ + /* Scalability = 0 */ + sPutBits(lBitOut, 1, 0); + vdtStuffBitsMPEG4(lBitOut); + + return; +} + + +/* +* sPutGOVHeader +* +* Parameters: +* bitOut pointer to the output buffer +* aModuloTimeBase time base for MPEG4 +* +* Function: +* This function writes the group of VOP(GOV) header into bit-stream +* Returns: +* None +* Error codes: +* None +* +*/ +inline void sPutGOVHeader(bibBuffer_t *bitOut, int aModuloTimeBase) +{ + int32 time_code_hours; + int32 time_code_minutes; + int32 time_code_seconds; + + WRITE32(bitOut, (uint32)GROUP_OF_VOP_START_CODE); + time_code_seconds = aModuloTimeBase; + time_code_minutes = time_code_seconds / 60; + time_code_hours = time_code_minutes / 60; + time_code_minutes = time_code_minutes - (time_code_hours * 60); + time_code_seconds = time_code_seconds - (time_code_minutes * 60) + - (time_code_hours * 3600); + + sPutBits(bitOut, 5, time_code_hours); + sPutBits(bitOut, 6, time_code_minutes); + sPutBits(bitOut, 1, MARKER_BIT); + sPutBits(bitOut, 6, time_code_seconds); + + /* ClosedGov */ + sPutBits(bitOut, 1, 0); + /* Broken Link */ + sPutBits(bitOut, 1, 0); + + /* Stuff bits */ + vdtStuffBitsMPEG4(bitOut); + + return; +} + +/* +* sConstructMPEG4VOSHeaderForH263 +* +* Parameters: +* bitOut pointer to the output buffer +* aWidth picture width +* aHeight picture height +* +* Function: +* This function writes the MPEG4 VOS header into bit-stream +* Returns: +* None +* Error codes: +* None +* +*/ +void sConstructMPEG4VOSHeaderForH263(bibBuffer_t *bitOut, int aWidth, int aHeight, int aOutputMpeg4TimeRes) +{ + /* visual object sequence header */ + WRITE32(bitOut, (uint32)VISUAL_OBJECT_SEQUENCE_START_CODE); + + /* This is for testing for level 0,3 */ + uint32 level = 8; /* level 0 for QCIF or less */ + if(aWidth > 176 || aHeight > 144) /* level 2 for greater than QCIF */ + level = 2; + sPutBits(bitOut, 8, level); /* simple profile, level 0 for H263 */ + + /* visual object header begins */ + WRITE32(bitOut, (uint32)VISUAL_OBJECT_START_CODE); + /* IsVisualObjectIdentifier = 0 */ + sPutBits(bitOut, 1, 0); + /* VisualObjectType = VIDEO_OBJECT */ + sPutBits(bitOut, 4, VISUAL_OBJECT); + /* VideoSignalType = 0 */ + sPutBits(bitOut, 1, 0); + + vdtStuffBitsMPEG4(bitOut); + WRITE32(bitOut, (uint32)VIDEO_OBJECT_START_CODE); + + /* Writes the VOL header into bit-stream , for baseline H263 TR is marked with 29.97fps. ->? */ + sPutVOLHeader(bitOut, aWidth, aHeight, aOutputMpeg4TimeRes); + + /* Writes GOV , time base is 0 */ + sPutGOVHeader(bitOut, 0); + + return; +} + + +/* +* sPutVideoPacketHeader +* +* Parameters: +* lBitOut output buffer +* mbNo Macroblock number +* quantiserScale quant value to be put in header +* aMBsInVOP # of MBs in one VOP +* +* Function: +* This function writes the video packet header information into bit-stream +* Returns: +* None +* Error codes: +* None +* +*/ +inline void sPutVideoPacketHeader(bibBuffer_t *lBitOut, int32 mbNo, + int16 quantiserScale, + int aMBsInVOP) +{ + int32 lResyncMarkerLength = 17; + int32 lMBNoResolution; + + /* ResyncMarker */ + int fCode = 1; /*always 1 for H263 */ + lResyncMarkerLength = 16 + fCode; + sPutBits(lBitOut, lResyncMarkerLength, 1); + + --aMBsInVOP; + lMBNoResolution = 1; + while( (aMBsInVOP = + aMBsInVOP >> 1) > 0 ) + { + lMBNoResolution++; + } + sPutBits(lBitOut, lMBNoResolution, mbNo); + + /* QuantScale */ + sPutBits(lBitOut, 5, quantiserScale); + /* HEC */ + sPutBits(lBitOut, 1, 0); /* always 0 for H263 */ + + return; +} + +/* +* sConstructVOPHeaderForH263 +* +* Parameters: +* lBitOut output buffer +* prevQuant quant value to be put in header +* aVOPType picture coding type +* aVOPTimeIncrement time increament +* +* Function: +* This function writes the VOP header into bit-stream for one H263 frame +* Returns: +* None +* Error codes: +* None +* +*/ + +void sConstructVOPHeaderForH263(bibBuffer_t *lBitOut, int prevQuant, int aVOPType, int aVOPTimeIncrement,int aOutputMpeg4TimeRes) +{ + WRITE32(lBitOut, (uint32)VOP_START_CODE); + /* VOPType, 0 for Intra and 1 for inter */ + sPutBits(lBitOut, 2, aVOPType); + + /* H263 TR is marked with 29.97fps */ + /* Modulo Time Base */ + int outputTimerResolution = aOutputMpeg4TimeRes; + while ((unsigned)aVOPTimeIncrement >= (unsigned) outputTimerResolution) + { + sPutBits(lBitOut, 1, 1); + aVOPTimeIncrement -= outputTimerResolution; + } + sPutBits(lBitOut, 1, 0); + /* Marker Bit */ + sPutBits(lBitOut, 1, MARKER_BIT); + /* VopTimeIncrement */ + int numOutputTrBits; + for (numOutputTrBits = 1; ((outputTimerResolution-1) >> numOutputTrBits) != 0; numOutputTrBits++) + { + } + int VOPIncrementResolutionLength = numOutputTrBits; + sPutBits(lBitOut, VOPIncrementResolutionLength, aVOPTimeIncrement); + /* Marker Bit */ + sPutBits(lBitOut, 1, MARKER_BIT); + /* VOPCoded */ + sPutBits(lBitOut, 1, 1); /* always 1 for H263 */ + /* VOPRoundingType */ + if(aVOPType == P_VOP) + { + sPutBits(lBitOut, 1, 0); /* always 0 for H263 */ + } + /* IntraDCVLCThreshold */ + sPutBits(lBitOut, 3, 0); /* always 0 for H263 */ + /* VOPQuant */ + sPutBits(lBitOut, 5, prevQuant); + /* VOPFcodeForwad */ + if(aVOPType == P_VOP) + { + sPutBits(lBitOut, 3, 1); /* always 1 for H263 */ + } + + return; +} + + + +/* +* H263PictureHeaderEndedL +* +* Parameters: +* +* Function: +* This function is called after one H263 picture header is parsed +* Note: the input header is only valid inside this function +* Returns: +* VDC error codes +* Error codes: +* None +* +*/ +int CMPEG4Transcoder::H263PictureHeaderEnded(dphOutParam_t *aH263PicHeader, dphInOutParam_t *aInfo) +{ + VDTASSERT(aH263PicHeader); + + // asad + if (!aInfo->vdcInstance->frameNum || !iRefQuant) + { + iRefQuant = aH263PicHeader->pquant; + iDcScaler = GetMpeg4DcScalerUV(iRefQuant); + } + + if (!iDoModeTranscoding ) + { + + /* Copy the header to output stream */ + bufEdit.copyMode = CopyWhole; /* CopyWhole */ + + if ( (iTargetFormat == EVedVideoTypeH263Profile0Level10 || iTargetFormat == EVedVideoTypeH263Profile0Level45) && + fFirstFrameInH263 && iBitStreamMode == EVedVideoBitstreamModeMPEG4ShortHeader) + { + /* we don't need the VOS header, remove it */ + PRINT((_L("CMPEG4Transcoder: MPEG4 shortheader VOS removed"))); + + CopyStream(iInBuffer,iOutBuffer,&bufEdit,iShortHeaderEndByteIndex,iShortHeaderEndBitIndex); + fFirstFrameInH263 = EFalse; + } + else + { + /* copy from the begining of the input buffer, + including the VOS header for MPEG4 shortheader if its mode is not being changed + */ + CopyStream(iInBuffer,iOutBuffer,&bufEdit,0,7); + } + } + + + + else + { + /* H263 Picture Header -> MPEG4 VOP Header mapping + information about this frame + */ + iMBsinWidth = aInfo->vdcInstance->pictureParam.lumWidth >> 4; + + iNumMBsInOneVOP = (aInfo->vdcInstance->pictureParam.lumWidth >> 4) * + (aInfo->vdcInstance->pictureParam.lumHeight >> 4); + + iNumMBsInGOB = aInfo->vdcInstance->pictureParam.numMBsInGOB; + + /* create the intraDC matrix for DC prediction */ + VDTASSERT(!iH263DCData); + VDTASSERT(!iH263MBVPNum); + + iH263DCData = (int **)malloc(iNumMBsInOneVOP * sizeof(int)); + if (!iH263DCData) + { + deb("CMPEG4Transcoder::ERROR - iH263DCData creation failed\n"); + return TX_ERR; + } + + for (int i = 0; i < iNumMBsInOneVOP; i++) + { + iH263DCData[i] = (int *) malloc(6 * sizeof(int)); /* six blocks in one MB */ + VDTASSERT(iH263DCData[i]); + if (!iH263DCData[i]) + { + deb("CMPEG4Transcoder::ERROR - iH263DCData[i] creation failed\n"); + + for(int k=0; kvdcInstance->pictureParam.pictureType == VDX_PIC_TYPE_I? I_VOP : P_VOP; + + if (fFirstFrameInH263) + { + /* first frame, construct the VOS header */ + sConstructMPEG4VOSHeaderForH263(iOutBuffer, + aInfo->vdcInstance->pictureParam.lumWidth, + aInfo->vdcInstance->pictureParam.lumHeight, + iOutputMpeg4TimeIncResolution); + fFirstFrameInH263 = EFalse; + + PRINT((_L("CMPEG4Transcoder: H263 -> MPEG VOS generated"))); + } + sConstructVOPHeaderForH263(iOutBuffer, aH263PicHeader->pquant, pictureType, aH263PicHeader->trp == -1 ? 0 : aH263PicHeader->trp,iOutputMpeg4TimeIncResolution); + + + PRINT((_L("CMPEG4Transcoder: H263 -> MPEG4: transcoding one picture"))); + } + + + PRINT((_L("CMPEG4Transcoder: H263PictureHeaderEndedL. color effect: %d, format convert %d, do transcoding: %d streammode: %d, outputformat: %d "), + iColorEffect, iDoModeTranscoding, iDoTranscoding, + iBitStreamMode, iTargetFormat)); + + return TX_OK; +} + +/* +* H263GOBSliceHeaderEnded +* +* Parameters: +* +* Function: +* This function is called after one H263 GOB or Slice header is parsed +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::H263GOBSliceHeaderEnded(vdxGOBHeader_t *aH263GOBHeader, vdxSliceHeader_t */*aH263SliceHeader*/) +{ + iGOBSliceHeaderEndByteIndex = iInBuffer->getIndex; + iGOBSliceHeaderEndBitIndex = iInBuffer->bitIndex; + + if (aH263GOBHeader) + { + /* not the first GOB (no header), we have stuffing bits ahead + since we only store the position of GBSC not including + the stuffing bits, we may need to insert the stuffing bits here + if we have color effect, we have done the stuffing at the end of last GOB + see functin: H263OneGOBSliceWithHeaderEnded + */ + sStuffBitsH263(iOutBuffer); + } + + if (!iDoModeTranscoding) + { + /* Copy the header to output stream */ + bufEdit.copyMode = CopyWhole; // whole + CopyStream(iInBuffer,iOutBuffer,&bufEdit,iGOBSliceStartByteIndex,iGOBSliceStartBitIndex); + + } + + else + { + /* H263 GOB (Slice) Header -> MPEG4 VP Header mapping */ + if (!VDT_NO_DATA((int)iInBuffer->getIndex, iInBuffer->bitIndex, iGOBSliceStartByteIndex, iGOBSliceStartBitIndex) && + aH263GOBHeader) + { + /* sPutVideoPacketHeader */ + sPutVideoPacketHeader(iOutBuffer, aH263GOBHeader->gn * iNumMBsInGOB, (short)aH263GOBHeader->gquant, iNumMBsInOneVOP); + } + } + + // one slice ended, new video packet starting + iCurMBNumInVP = -1; + +} + + +/* +* H263GOBSliceHeaderBegin +* +* Parameters: +* +* Function: +* This function is called before one H263 GOB or Slice header is parsed +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::H263GOBSliceHeaderBegin() +{ + /* position not include the stuffing bits ahead of the GBSC ! */ + iGOBSliceStartByteIndex = iInBuffer->getIndex; + iGOBSliceStartBitIndex = iInBuffer->bitIndex; + iStuffingBitsUsed = 0; +} + + +/* +* H263GOBSliceHeaderBegin +* +* Parameters: +* +* Function: +* This function is called after one H263 GOB or Slice ends +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::H263OneGOBSliceEnded(int nextExpectedMBNum) +{ + if (iDoTranscoding) + { + /* MBs are lost or not coded, for H263 and H263->MPEG4 both */ + for (int i = iLastMBNum+1; i < nextExpectedMBNum; i++) + { + /* output 1 bit COD */ + sPutBits (iOutBuffer, 1, 1); + } + iLastMBNum = nextExpectedMBNum - 1; + } +} + + +/* +* H263OneGOBSliceWithHeaderEnded +* +* Parameters: +* +* Function: +* This function is called after GOB (Slice) that has GOB header (except the first GOB) ends +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::H263OneGOBSliceWithHeaderEnded() +{ + if (!iDoTranscoding) + { + bufEdit.copyMode = CopyWhole; /* CopyWhole */ + CopyStream(iInBuffer,iOutBuffer,&bufEdit, + iGOBSliceHeaderEndByteIndex,iGOBSliceHeaderEndBitIndex); + } + else + { + + if (iDoModeTranscoding) + { + /* for H263 to MPEG4, it implies that one video packet is finished */ + vdtStuffBitsMPEG4(iOutBuffer); + } + else + + { + /* stuffing occurs outside at the end of one GOB/slice withe header or end of frame, check in file core.cpp */ + sStuffBitsH263(iOutBuffer); + } + iVideoPacketNumInMPEG4 ++; + } + + // one slice ended, new video packet starting + iCurMBNumInVP = -1; // 0 + +} + + + +/* +* H263ToMPEG4MBData +* +* Parameters: +* +* Function: +* This function transcodes one H263 MB to one MPEG4 MB +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::H263ToMPEG4MBData(int aNewMCBPCLen, int aNewMCBPC) +{ + /* MB data part1: output MCBPC, CBPY, DQuant, MV, intra DC etc */ + int *dataItemStartByteIndex; + int *dataItemStartBitIndex; + int *dataItemEndByteIndex; + int *dataItemEndBitIndex; + int quant, cbpy, cbpc; + + if (iVopCodingType == VDX_VOP_TYPE_P) + { + dataItemStartByteIndex = iCurPMBinstance->DataItemStartByteIndex; + dataItemStartBitIndex = iCurPMBinstance->DataItemStartBitIndex; + dataItemEndByteIndex = iCurPMBinstance->DataItemEndByteIndex; + dataItemEndBitIndex = iCurPMBinstance->DataItemEndBitIndex; + quant = iCurPMBinstance->quant; + cbpy = iCurPMBinstance->cbpy; + cbpc = iCurPMBinstance->cbpc; + } + else + { + dataItemStartByteIndex = iCurIMBinstance->DataItemStartByteIndex; + dataItemStartBitIndex = iCurIMBinstance->DataItemStartBitIndex; + dataItemEndByteIndex = iCurIMBinstance->DataItemEndByteIndex; + dataItemEndBitIndex = iCurIMBinstance->DataItemEndBitIndex; + quant = iCurIMBinstance->quant; + cbpy = iCurIMBinstance->cbpy; + cbpc = iCurIMBinstance->cbpc; + } + + /* COD and MCBPC, (for I frame, it is MCBPC, for P frame it is COD and MCBPC) */ + if (iVopCodingType == VDX_VOP_TYPE_P) + { + /* It is a coded MB, output 1 bit COD (it always exists in P frame) */ + sPutBits (iOutBuffer, 1, 0); + } + + if (iColorEffect) + { + /* MCBPC Changed */ + sPutBits(iOutBuffer, aNewMCBPCLen, aNewMCBPC); + } + else + { + /* remember the positions do not include the possible stuffing MCBPC bits */ + vdtCopyBuffer(iInBuffer, iOutBuffer, + dataItemStartByteIndex[0], dataItemStartBitIndex[0], + dataItemEndByteIndex[0], dataItemEndBitIndex[0]); + } + + /* ac_pred_flag */ + if (iMBCodingType == VDX_MB_INTRA) + { + sPutBits(iOutBuffer, 1, 0);// it is closed for H263 INTRA MB + } + + /* CBPY */ + vdtCopyBuffer(iInBuffer, iOutBuffer, + dataItemStartByteIndex[2], dataItemStartBitIndex[2], + dataItemEndByteIndex[2], dataItemEndBitIndex[2]); + + /* DQUANT, if it exsits */ + vdtCopyBuffer(iInBuffer, iOutBuffer, + dataItemStartByteIndex[1], dataItemStartBitIndex[1], + dataItemEndByteIndex[1], dataItemEndBitIndex[1]); + + if (iMBCodingType == VDX_MB_INTER) + { + /* MVs, if they exsit */ + vdtCopyBuffer(iInBuffer, iOutBuffer, + dataItemStartByteIndex[10], dataItemStartBitIndex[10], + dataItemEndByteIndex[10], dataItemEndBitIndex[10]); + } + + /* following is the block level data */ + for (int i = 0; i < (iColorEffect? 4 : 6); i++) + { + if (iMBCodingType == VDX_MB_INTRA) + { + int fBlockCoded = 0; + if (i < 4) + { + fBlockCoded = vdxIsYCoded(cbpy, i + 1); + } + else if (i == 4) + { + fBlockCoded = vdxIsUCoded(cbpc); + } + else + { + fBlockCoded = vdxIsVCoded(cbpc); + } + + /* Difference between H263 and MPEG4 : + 0. DC quantization is different, DC need to be dequantized and requantized + Note: for ACs, here we only support H263 quantization in MPEG4, we can copy them + 1. DC prediction is used in MPEG4 + 2. They use different VLC table for INTRA AC coefficient + */ + /* reconstuct INTRA DC */ + int intraDC = (iDCTBlockData + i * BLOCK_COEFF_SIZE)[0]; /* it is already dequantized in funcion vdxGetIntraDCTBlock */ + + /* INTRA quantization and prediction */ + (iDCTBlockData + i * BLOCK_COEFF_SIZE)[0] = sGetMPEG4INTRADCValue(intraDC, + i, iCurMBNum, quant, iMBsinWidth,iH263DCData, iH263MBVPNum); + + /* recoding the INTRA block */ + int numTextureBits = 0; + + vdtPutIntraMBCMT(iOutBuffer,iDCTBlockData + i * BLOCK_COEFF_SIZE, &numTextureBits, i, 0, 1); /* DC coding */ + + if (fBlockCoded) + { + vdtPutIntraMBCMT(iOutBuffer,iDCTBlockData + i * BLOCK_COEFF_SIZE, &numTextureBits, i, 1, 0); /*encode ACs */ + } + + } + + else if (!(VDT_NO_DATA(iBlockStartByteIndex[i], iBlockStartBitIndex[i], + iBlockEndByteIndex[i], iBlockEndBitIndex[i]))) + { + + /* 4. same VLC table for DCTs in H263 and MPEG4, but with different Escape Coding type. + see 7.4.1.3. in MPEG4 draft + */ + if (iEscapeCodeUsed[i]) + { + int numTextureBits = 0; + vdtPutInterMBCMT(iOutBuffer,0, iDCTBlockData + i * BLOCK_COEFF_SIZE, &numTextureBits, OFF); + } + else + { + bufEdit.copyMode = CopyWhole; /* CopyWhole */ + vdtCopyBuffer(iInBuffer,iOutBuffer, + iBlockStartByteIndex[i],iBlockStartBitIndex[i], + iBlockEndByteIndex[i],iBlockEndBitIndex[i]); + } + } + } + + if (iColorEffect && (iMBCodingType == VDX_MB_INTRA)) + { + ResetMPEG4IntraDcUV(); + } +} + + + +/* +* NeedDecodedYUVFrame +* +* Parameters: +* +* Function: +* This function indicates if whether we need the decoded frame +* Returns: +* ETrue if we need the decoded frame +* Error codes: +* None +* +*/ +int CMPEG4Transcoder::NeedDecodedYUVFrame() +{ + if ( (iTargetFormat == EVedVideoTypeH263Profile0Level10 || iTargetFormat == EVedVideoTypeH263Profile0Level45) && + iBitStreamMode !=EVedVideoBitstreamModeMPEG4ShortHeader && iBitStreamMode != EVedVideoBitstreamModeH263) + return ETrue; + else + return EFalse; +} + +/* +* NewL +* +* Parameters: +* +* Function: +* Symbian two-phased constructor +* Returns: +* pointer to constructed object, or NULL +* Error codes: +* None +* +*/ +CMPEG4Transcoder* CMPEG4Transcoder::NewL(const vdeInstance_t *aVDEInstance, bibBuffer_t *aInBuffer, bibBuffer_t *aOutBuffer) +{ + CMPEG4Transcoder *self = new (ELeave) CMPEG4Transcoder(aVDEInstance, aInBuffer, aOutBuffer); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + + return self; +} + + +/* +* ConstructL +* +* Parameters: +* +* Function: +* Symbian 2nd phase constructor (can leave) +* Returns: +* None +* Error codes: +* None +* +*/ +void CMPEG4Transcoder::ConstructL() +{ + + /* Create one IMB Instance */ + iCurIMBinstance = (vdxIMBListItem_t *) malloc(sizeof(vdxIMBListItem_t)); + if (!iCurIMBinstance) + { + deb("CMPEG4Transcoder::ERROR - iCurIMBinstance creation failed\n"); + User::Leave(KErrNoMemory); + + } + memset(iCurIMBinstance, 0, sizeof(vdxIMBListItem_t)); + + /* Create one PMBInstance */ + iCurPMBinstance = (vdxPMBListItem_t *) malloc(sizeof(vdxPMBListItem_t)); + if (!iCurPMBinstance) + { + deb("CMPEG4Transcoder::ERROR - iCurPMBinstance creation failed\n"); + User::Leave(KErrNoMemory); + + } + memset(iCurPMBinstance, 0, sizeof(vdxPMBListItem_t)); + + /* initialize the edit buffer */ + bufEdit.editParams = (bibEditParams_t *) malloc(sizeof(bibEditParams_t)); + VDTASSERT(bufEdit.editParams); + if (!bufEdit.editParams) + { + deb("CMPEG4Transcoder::ERROR - bufEdit.editParams creation failed\n"); + User::Leave(KErrNoMemory); + + }else{ + bufEdit.numChanges = 1; + } + + if (!iMBType) + { + iMBType = (u_char *) malloc(iNumMBsInOneVOP * sizeof(u_char)); + if (!iMBType) + { + deb("CMPEG4Transcoder::ERROR - iMBType creation failed\n"); + User::Leave(KErrNoMemory); + } + memset(iMBType, VDX_MB_INTER, iNumMBsInOneVOP * sizeof(u_char)); + } + +} + + +/* +* GetMpeg4DcScaler +* +* Parameters: +* +* aQP Quantization parameter +* +* Function: +* Evaluates Chrominance DC Scaler from QP for MPEG4 +* Returns: +* int DC scaler value +* Error codes: +* None +* +*/ +int CMPEG4Transcoder::GetMpeg4DcScalerUV(int aQP) +{ + if (aQP>=1 && aQP<=4) + return (8); + else if (aQP>=5 && aQP<=24) + return ((aQP+13)/2); + else if (aQP>=25 && aQP<=31) + return (aQP-6); + else + return (0); // error +} + + +void CMPEG4Transcoder::AfterMBLayer(int aUpdatedQp) +{ + iCurQuant = aUpdatedQp; +} + + + + +/* End of File */