diff -r 000000000000 -r 951a5db380a0 videoeditorengine/h263decoder/src/vdcaic.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/videoeditorengine/h263decoder/src/vdcaic.cpp Fri Jan 29 14:08:33 2010 +0200 @@ -0,0 +1,627 @@ +/* +* 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: +* Advanced Intra Coding functions (MPEG-4). +* +*/ + + + + +#include "h263dConfig.h" + +#include "vdcaic.h" + +#include "errcodes.h" +#include "debug.h" + +#include "zigzag.h" + +/* + * + * aicIntraDCSwitch + * + * Parameters: + * intraDCVLCThr VOP-header field for QP dependent switching between + * MPEG-4 IntraDC coding and IntraAC VLC coding of the + * Intra DC coefficients + * QP quantization parameter + * + * Function: + * This function decides based on the input parameters if the Intra DC + * should be decoded as MPEG-4 IntraDC (switched=0) or switched to + * IntraAC VLC (switched=1) + * + * Returns: + * switched value + * + * + * + */ + +u_char aicIntraDCSwitch(int intraDCVLCThr, int QP) { + + if ( intraDCVLCThr == 0 ) { + return 0; + } + else if ( intraDCVLCThr == 7 ) { + return 1; + } + else if ( QP >= intraDCVLCThr*2+11 ) { + return 1; + } + else { + return 0; + } +} + +/* + * + * aicDCScaler + * + * Parameters: + * QP quantization parameter + * type type of Block "1" Luminance "2" Chrominance + * + * Function: + * Calculation of DC quantization scale according + * to the incoming QP and block type + * + * Returns: + * dcScaler value + * + * + * + */ + +int aicDCScaler (int QP, int type) { + + int dcScaler; + if (type == 1) { + if (QP > 0 && QP < 5) { + dcScaler = 8; + } + else if (QP > 4 && QP < 9) { + dcScaler = 2 * QP; + } + else if (QP > 8 && QP < 25) { + dcScaler = QP + 8; + } + else { + dcScaler = 2 * QP - 16; + } + } + else { + if (QP > 0 && QP < 5) { + dcScaler = 8; + } + else if (QP > 4 && QP < 25) { + dcScaler = (QP + 13) / 2; + } + else { + dcScaler = QP - 6; + } + } + return dcScaler; +} + +/** + * Small routine to compensate the QP value differences between the + * predictor and current block AC coefficients + * + **/ + +static int compensateQPDiff(int val, int QP) { + + if (val<0) { + return (val-(QP>>1))/QP; + } + else { + return (val+(QP>>1))/QP; + } +} + +/** + * Small routine to fill default prediction values into a dcStore entry + * + */ + +static void resetPredRow(int pred[]) +{ + memset (pred, 0, 7 * sizeof(int)); +} + +/* + * + * aicStart + * + * Parameters: + * aicData aicData_t structure + * instance pointer to vdcInstance_t structure + * + * Function: + * This function initialises dcStore and qpStore buffers. + * One should call aicStart in the beginning of each VOP. + * + * Returns: + * Nothing + * + * Error codes: + * + * + */ + +void aicStart(aicData_t *aicData, int numMBsInMBLine, int16 *error) +{ + + int i,j, numStoreUnits; + int initXpos[6] = {-1, 0, -1, 0, -1, -1}; + int initYpos[6] = {-1, -1, 0, 0, -1, -1}; + int initXtab[6] = {1, 0, 3, 2, 4, 5}; + int initYtab[6] = {2, 3, 0, 1, 4, 5}; + int initZtab[6] = {3, 2, 1, 0, 4, 5}; + + numStoreUnits = numMBsInMBLine*2; + + if (!aicData->qpStore || !aicData->dcStore) { + aicData->qpStore = (int16 *) calloc(numStoreUnits, sizeof(int16)); + if (!aicData->qpStore) + { + *error = ERR_VDC_MEMORY_ALLOC; + return; + } + + /* allocate space for 3D matrix to keep track of prediction values + for DC/AC prediction */ + + aicData->dcStore = (int ***)calloc(numStoreUnits, sizeof(int **)); + if (!aicData->dcStore) + { + *error = ERR_VDC_MEMORY_ALLOC; + return; + } + + for (i = 0; i < numStoreUnits; i++) + { + aicData->dcStore[i] = (int **)calloc(6, sizeof(int *)); + if (!aicData->dcStore[i]) + { + *error = ERR_VDC_MEMORY_ALLOC; + return; + } + + for (j = 0; j < 6; j++) + { + aicData->dcStore[i][j] = (int *)calloc(15, sizeof(int)); + if ( !(aicData->dcStore[i][j]) ) + { + *error = ERR_VDC_MEMORY_ALLOC; + return; + } + } + } + + aicData->numMBsInMBLine = numMBsInMBLine; + + for (i= 0; i < 6; i++) + { + aicData->Xpos[i] = initXpos[i]; + aicData->Ypos[i] = initYpos[i]; + aicData->Xtab[i] = initXtab[i]; + aicData->Ytab[i] = initYtab[i]; + aicData->Ztab[i] = initZtab[i]; + } + + /* 1 << (instance->bits_per_pixel - 1) */ + aicData->midGrey = 1 << 7; + + aicData->ACpred_flag = 1; + } else { + memset(aicData->qpStore, 0, numStoreUnits * sizeof(int16)); + } + +} + +/* + * Clip the reconstructed coefficient when it is stored for prediction + * + */ + +#define aicClip(rec) \ + ((rec < -2048) ? -2048 : ((rec > 2047) ? 2047 : rec)) + +/* + * + * aicBlockUpdate + * + * Parameters: + * aicData aicData_t structure + * currMBNum Current Macroblocks Number + * + * Function: + * This function fills up the dcStore and qpStore of current MB. + * + * Returns: + * Nothing + * + * Error codes: + * None + * + * + */ + +void aicBlockUpdate (aicData_t *aicData, int currMBNum, int blockNum, int *block, + int pquant, int DC_coeff) +{ + + int n, currDCStoreIndex; + assert(currMBNum >= 0); + + currDCStoreIndex = ((currMBNum / aicData->numMBsInMBLine) % 2) * aicData->numMBsInMBLine + + (currMBNum % aicData->numMBsInMBLine); + + if (block != NULL) { + + aicData->dcStore[currDCStoreIndex][blockNum][0] = aicClip(DC_coeff); + block[0] = aicClip(block[0]); + + for (n = 1; n < 8; n++) + { + aicData->dcStore[currDCStoreIndex][blockNum][n] = block[zigzag[n]] = aicClip(block[zigzag[n]]); + aicData->dcStore[currDCStoreIndex][blockNum][n+7] = block[zigzag[n<<3 /**8*/]] = aicClip(block[zigzag[n<<3 /**8*/]]); + } + } + + if (blockNum == 0) + aicData->qpStore[currDCStoreIndex]= (int16) pquant; +} + +/* + * + * aicIsBlockValid + * + * Parameters: + * aicData aicData_t structure + * currMBNum Current Macroblocks Number + * + * Function: + * This function checks if the current MB has a valid entry in the + * dcStore and qpStore (needed in predictor validation of I-MBs in a P-VOP). + * + * Returns: + * 1 if MB has a valid entry + * 0 if MB doesn't have a valid entry + * + * Error codes: + * None + * + * + */ + +int aicIsBlockValid (aicData_t *aicData, int currMBNum) +{ + int currDCStoreIndex; + assert(currMBNum >= 0); + + currDCStoreIndex = ((currMBNum / aicData->numMBsInMBLine) % 2) * aicData->numMBsInMBLine + + (currMBNum % aicData->numMBsInMBLine); + + if (aicData->qpStore[currDCStoreIndex] > 0 && aicData->qpStore[currDCStoreIndex] < 32) + return 1; + else + return 0; +} + +/* + * + * aicFree + * + * Parameters: + * aicData aicData_t structure + * numOfMBs Number of Macroblocks in VOP + * + * Function: + * This function frees the dynamic memory allocated by aicStart. + * aicFree should be called at least when exiting the main program. + * Alternatively it can be called whenever the playing a video has + * ended. + * + * Returns: + * Nothing + * + * Error codes: + * None + * + * + */ + +void aicFree(aicData_t *aicData) +{ + int i,j; + + /* Free allocated memory for 3D matrix */ + if (aicData->dcStore) { + for (i = 0; i < (aicData->numMBsInMBLine*2); i++) + { + for (j = 0; j < 6; j++) + free((char *)aicData->dcStore[i][j]); + free((char *)aicData->dcStore[i]); + } + free((char *)aicData->dcStore); + } + + /* Free allocated memory for qpStore matrix */ + if (aicData->qpStore) { + free((char *)aicData->qpStore); + } +} + +/* + * + * aicDCACrecon + * + * Parameters: + * aicData aicData_t structure + * QP QP of the current MB + * fTopMBMissing flag indicating if the block above the current block + * is outside of the current Video Packet or not a valid + * Intra block (in case of P-VOP decoding) + * fLeftMBMissing flag indicating if the block left to the current block + * is outside of the current Video Packet or not a valid + * Intra block (in case of P-VOP decoding) + * fBBlockOut flag indicating if the top-left neighbour block of the + * current block is outside of the current Video Packet + * or not a valid Intra block (in case of P-VOP decoding) + * blockNum number of the current block in the MB + * (0..3 luminance, 4..5 chrominance) + * qBlock block of coefficients + * currMBNum number of the current macroblocks in the VOP + * + * Function: + * This function reconstructs the DC and AC (first column or first row or none) + * coefficients of the current block by selecting the predictor from the + * neighbouring blocks (or default values), and adding these predictor + * values to qBlock. Its output is the quantized coefficient matrix in + * normal zigzag order. + * + * Returns: + * Nothing + * + * Error codes: + * None + * + * + */ + +void aicDCACrecon(aicData_t *aicData, int QP, u_char fTopMBMissing, u_char fLeftMBMissing, + u_char fBBlockOut, int blockNum, int *qBlock, int currMBNum) +{ + int m, n, tempDCScaler; + int xCoordMB, yCoordMB, mbWidth, currDCStoreIndex; + int blockA = 0, blockB = 0, blockC = 0, fBlockAExist = 0, fBlockCExist = 0; + int gradHor, gradVer, predDC; + int fVertical; + int predA[7], predC[7]; + int pcoeff[64]; + assert(currMBNum >= 0); + assert(qBlock != NULL); + + xCoordMB = currMBNum % aicData->numMBsInMBLine; + yCoordMB = currMBNum / aicData->numMBsInMBLine; + currDCStoreIndex = (yCoordMB % 2)*aicData->numMBsInMBLine + xCoordMB; + mbWidth = aicData->numMBsInMBLine * ((currDCStoreIndex < aicData->numMBsInMBLine) ? -1 : 1); + + + /* Find the direction of prediction and the DC prediction */ + switch ( blockNum ) { + case 0 : + case 4 : + case 5 : + /* Y0, U, and V blocks */ + + + /* Prediction blocks A (left), B (above-left), and C (above) */ + if ( ( yCoordMB == 0 && xCoordMB == 0) || (fTopMBMissing && fLeftMBMissing) || (xCoordMB == 0 && fTopMBMissing) || (yCoordMB == 0 && fLeftMBMissing) ) { + /* top-left edge of VOP or VP */ + blockA = aicData->midGrey<<3 /**8*/; + blockB = aicData->midGrey<<3 /**8*/; + blockC = aicData->midGrey<<3 /**8*/; + fBlockAExist = fBlockCExist = 0; + } + else if ( yCoordMB == 0 || fTopMBMissing ) { + /* top row of VOP or VP, or MB on top not valid */ + blockA = aicData->dcStore[currDCStoreIndex+aicData->Xpos[blockNum]][aicData->Xtab[blockNum]][0]; + fBlockAExist = 1; + if ( yCoordMB == 0 || fBBlockOut ) { + /* B MB is out of this VP */ + blockB = aicData->midGrey<<3 /**8*/; + } + else { + blockB = aicData->dcStore[currDCStoreIndex+(aicData->Ypos[blockNum])*mbWidth+aicData->Xpos[blockNum]][aicData->Ztab[blockNum]][0]; + } + blockC = aicData->midGrey<<3 /**8*/; + fBlockCExist = 0; + } + else if ( xCoordMB == 0 || fLeftMBMissing ) { + /* left edge of VOP or VP, or MB on left not valid */ + blockA = aicData->midGrey<<3 /**8*/; + fBlockAExist = 0; + if ( xCoordMB == 0 || fBBlockOut ) { + /* B MB is out of this VP */ + blockB = aicData->midGrey<<3 /**8*/; + } + else { + blockB = aicData->dcStore[currDCStoreIndex+(aicData->Ypos[blockNum])*mbWidth+aicData->Xpos[blockNum]][aicData->Ztab[blockNum]][0]; + } + blockC = aicData->dcStore[currDCStoreIndex+(aicData->Ypos[blockNum])*mbWidth][aicData->Ytab[blockNum]][0]; + fBlockCExist = 1; + } + else { + /* Something else */ + blockA = aicData->dcStore[currDCStoreIndex+aicData->Xpos[blockNum]][aicData->Xtab[blockNum]][0]; + if ( fBBlockOut ) { + /* B MB is out of this VP */ + blockB = aicData->midGrey<<3 /**8*/; + } + else { + blockB = aicData->dcStore[currDCStoreIndex+(aicData->Ypos[blockNum])*mbWidth+aicData->Xpos[blockNum]][aicData->Ztab[blockNum]][0]; + } + blockC = aicData->dcStore[currDCStoreIndex+(aicData->Ypos[blockNum])*mbWidth][aicData->Ytab[blockNum]][0]; + fBlockAExist = fBlockCExist = 1; + } + break; + case 1 : + /* Y1 block */ + + /* Prediction block A (left) always available */ + blockA = aicData->dcStore[currDCStoreIndex+aicData->Xpos[blockNum]][aicData->Xtab[blockNum]][0]; + fBlockAExist = 1; + /* Prediction blocks B (above-left) and C (above) */ + if ( yCoordMB == 0 || fTopMBMissing ) { + /* top row of VOP or VP */ + blockB = aicData->midGrey<<3 /**8*/; + blockC = aicData->midGrey<<3 /**8*/; + fBlockCExist = 0; + } + else { + blockB = aicData->dcStore[currDCStoreIndex+(aicData->Ypos[blockNum])*mbWidth+aicData->Xpos[blockNum]][aicData->Ztab[blockNum]][0]; + blockC = aicData->dcStore[currDCStoreIndex+(aicData->Ypos[blockNum])*mbWidth][aicData->Ytab[blockNum]][0]; + fBlockCExist = 1; + } + break; + case 2 : + /* Y2 block */ + + /* Prediction blocks A (left) and B (above-left) */ + if ( xCoordMB == 0 || fLeftMBMissing ) { + /* left edge or first MB in VP */ + blockA = aicData->midGrey<<3 /**8*/; + blockB = aicData->midGrey<<3 /**8*/; + fBlockAExist = 0; + } + else { + blockA = aicData->dcStore[currDCStoreIndex+aicData->Xpos[blockNum]][aicData->Xtab[blockNum]][0]; + blockB = aicData->dcStore[currDCStoreIndex+(aicData->Ypos[blockNum])*mbWidth+aicData->Xpos[blockNum]][aicData->Ztab[blockNum]][0]; + fBlockAExist = 1; + } + /* Prediction block C (above) always available */ + blockC = aicData->dcStore[currDCStoreIndex+(aicData->Ypos[blockNum])*mbWidth][aicData->Ytab[blockNum]][0]; + fBlockCExist = 1; + break; + case 3 : + /* Y3 block */ + + /* Prediction block A (left) always available */ + blockA = aicData->dcStore[currDCStoreIndex+aicData->Xpos[blockNum]][aicData->Xtab[blockNum]][0]; + /* Prediction block B (above-left) always available */ + blockB = aicData->dcStore[currDCStoreIndex+(aicData->Ypos[blockNum])*mbWidth+aicData->Xpos[blockNum]][aicData->Ztab[blockNum]][0]; + /* Prediction block C (above) always available */ + blockC = aicData->dcStore[currDCStoreIndex+(aicData->Ypos[blockNum])*mbWidth][aicData->Ytab[blockNum]][0]; + fBlockAExist = fBlockCExist = 1; + break; + } + + + + + gradHor = blockB - blockC; + gradVer = blockA - blockB; + + if ((abs(gradVer)) < (abs(gradHor))) { + /* Vertical prediction (from C) */ + predDC = blockC; + fVertical = 1; + } + else { + /* Horizontal prediction (from A) */ + predDC = blockA; + fVertical = 0; + } + + /* Now reconstruct the DC coefficient */ + tempDCScaler = aicDCScaler(QP,(blockNum<4)?1:2); + qBlock[0] = (u_int8) (qBlock[0] + (predDC + tempDCScaler/2) / tempDCScaler); + + /* Do AC prediction if required */ + if (aicData->ACpred_flag == 1) { + + /* Do inverse zigzag-scanning */ + if (fVertical) { + for (m = 0; m < 64; m++) { + pcoeff[m] = qBlock[zigzag_h[m]]; + } + } + else { /* horizontal prediction */ + for (m = 0; m < 64; m++) { + pcoeff[m] = qBlock[zigzag_v[m]]; + } + } + + + + /* AC predictions */ + if ( !fVertical && fBlockAExist ) { + /* prediction from A */ + for (m = 8; m < 15; m++) { + predA[m-8] = compensateQPDiff(((aicData->dcStore[currDCStoreIndex+aicData->Xpos[blockNum]][aicData->Xtab[blockNum]][m]) * 2 * (aicData->qpStore[currDCStoreIndex+aicData->Xpos[blockNum]])), (QP<<1)); + } + } + else if ( fVertical && fBlockCExist ) { + /* prediction from C */ + for (m = 1; m < 8; m++) { + predC[m-1] = compensateQPDiff(((aicData->dcStore[currDCStoreIndex+(aicData->Ypos[blockNum])*mbWidth][aicData->Ytab[blockNum]][m]) * 2 * (aicData->qpStore[currDCStoreIndex+(aicData->Ypos[blockNum])*mbWidth])), (QP<<1)); + } + } + else { + /* Prediction not possible */ + if ( fVertical ) { + resetPredRow(predC); + } + else { + resetPredRow(predA); + } + } + + + + /* AC coefficients reconstruction*/ + if (fVertical) { /* Vertical, top row of block C */ + for (m = 0; m < 7; m++) { + qBlock[zigzag[(m+1)*8]] = pcoeff[(m+1)*8]; + } + for (m = 1; m < 8; m++) { + qBlock[zigzag[m]] = pcoeff[m] + predC[m-1]; + } + } + else { /* Horizontal, left column of block A */ + for (m = 0; m < 7; m++) { + qBlock[zigzag[(m+1)*8]] = pcoeff[(m+1)*8] + predA[m]; + } + for (m = 1; m < 8; m++) { + qBlock[zigzag[m]] = pcoeff[m]; + } + } + + /* Copy the rest of the coefficients back to qBlock */ + for (m = 1; m < 8; m++) { + for (n = 1; n < 8; n++) { + qBlock[zigzag[m*8+n]] = pcoeff[m*8+n]; + } + } + } + +} + +// End of file