--- /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