diff -r 000000000000 -r 951a5db380a0 videoeditorengine/h263decoder/src/vdcmvc.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/videoeditorengine/h263decoder/src/vdcmvc.cpp Fri Jan 29 14:08:33 2010 +0200 @@ -0,0 +1,1701 @@ +/* +* 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: +* Motion vector calculations and storage. +* +*/ + + + + +#include "h263dConfig.h" + +#include "vdcmvc.h" + +#include "core.h" +#include "errcodes.h" +#include "debug.h" + + +/* + * Defines + */ + +#define NEIGHBOUR_SIZE 2 /* The size for neighbour array */ +#define MVD_NOT_CODED -32767 /* Macroblock is not coded in mvcTable_t */ +#define MVD_INTRA -32765 /* Marks intra macroblock in mvcTable_t */ + +#define MVD_UMIN_MPEG4 -10240 + +#define MVD_MIN -160 /* The minimum for mvd. */ +#define MVD_MAX 155 /* The maximum for mvd. */ +#define MVD_UMIN_V1 -315 /* The minimum for MV in unrestricted mode (v1) */ +#define MVD_UMAX_V1 315 /* The maximum for MV in unrestricted mode (v1) */ +#define MVD_UMIN_V2 -32000 /* The minimum for MV in unrestricted mode (v2) + Note: this value is used to check the validity + of MVs. If there is no MV for a MB + MVD_NOT_CODED or MVD_INTRA are used, and + therefore any value bigger than those + suits for this definition. In H.263 v2 + unlimited submode, MVs can have any length + within a picture (plus 15-pixel border), + and therefore this definition is set to small + enough value. */ +#define MVD_155 155 /* MV for 15.5 */ +#define MVD_160 160 /* MV for 16 */ +#define MVD_320 320 /* MV for 32 */ +/* It is assumed that motion vector values are signed and in order + (for example MV for 15.5 < MV for 16). + No other assumptions are made. */ + + +/* + * Macros + */ + +/* mvValid checks if the specified item is a valid motion vector */ +/* Note: MVD_NOT_CODED and MVD_INTRA are very small negative numbers. + Thus, we can use the minimum MV for H.263 Annex D unlimited + submode to check the validity of a passed item. Actually, + we could use any value larger than MVD_NOT_CODED and MVD_INTRA + and smaller than or equal to the minimum MV. */ +#define mvValid(d1item, d1y, d1time) \ + (d1item.mvx >= MVD_UMIN_V2 \ + && d1item.y == (d1y) && d1item.time == (d1time)) + + +#define mvValidMPEG(d1item, d1y, d1time) \ + (d1item.mvx >= MVD_UMIN_MPEG4 \ + && d1item.y == (d1y) && d1item.time == (d1time)) + +/* mvLegal cheks if the specified item has been updated to either contain + a motion vector or not coded / intra information */ +#define mvLegal(d5item, d5y, d5time) \ + (d5item.y == (d5y) && d5item.time == (d5time)) + +/* mvStore puts given arguments into the motion vector array + Used from: mvcCalcMV */ +#define mvStore(d2row, d2x, d2y, d2mvx, d2mvy, d2time, d2type) \ + d2row[d2x].mvx = d2mvx; d2row[d2x].mvy = d2mvy; \ + d2row[d2x].y = d2y; d2row[d2x].time = d2time; d2row[d2x].fourMVs = 1; \ + d2row[d2x].type = d2type + +/* mvStoreMB puts given arguments into the motion vector array for the + whole macroblock + Used from: mvcCalcMV, mvcMarkMBIntra, mvcMarkMBNotCoded */ +#define mvStoreMB(d4row1, d4row2, d4x, d4y, d4mvx, d4mvy, d4time, d4type) \ + d4row1[d4x].mvx = d4row1[d4x + 1].mvx = \ + d4row2[d4x].mvx = d4row2[d4x + 1].mvx = d4mvx; \ + d4row1[d4x].mvy = d4row1[d4x + 1].mvy = \ + d4row2[d4x].mvy = d4row2[d4x + 1].mvy = d4mvy; \ + d4row1[d4x].y = d4row1[d4x + 1].y = d4y; \ + d4row2[d4x].y = d4row2[d4x + 1].y = d4y + 1; \ + d4row1[d4x].time = d4row1[d4x + 1].time = \ + d4row2[d4x].time = d4row2[d4x + 1].time = time; \ + d4row1[d4x].fourMVs = d4row1[d4x + 1].fourMVs = \ + d4row2[d4x].fourMVs = d4row2[d4x + 1].fourMVs = 0; \ + d4row1[d4x].type = d4row1[d4x + 1].type = \ + d4row2[d4x].type = d4row2[d4x + 1].type = (d4type) + +/* updateRowPointers checks if currX, currY or currTime have changed + and updates them. It also updates mvRow0, mvRow1 and mvRow2. + Used from: mvcCalcMV, mvcMarkMBIntra, mvcMarkMBNotCoded */ +#define updateRowPointers(d3x, d3y, d3time) \ + if (d3x != mvcData->currX) \ + mvcData->currX = d3x; \ + if (d3y != mvcData->currY) { \ + int \ + mvRowIndex, \ + currMaxX = mvcData->currMaxX; \ + mvRowItem_t *mvRow = mvcData->mvRow; \ + mvcData->currY = d3y; \ + mvcData->mvRowIndex = mvRowIndex = (mvcData->mvRowIndex + 2) % 3; \ + mvcData->mvRow0 = &mvRow[(currMaxX + 1) * 2 * mvRowIndex]; \ + mvcData->mvRow1 = &mvRow[(currMaxX + 1) * 2 * ((mvRowIndex + 1) % 3)]; \ + mvcData->mvRow2 = &mvRow[(currMaxX + 1) * 2 * ((mvRowIndex + 2) % 3)]; \ + } \ + if (d3time != mvcData->currTime) \ + mvcData->currTime = d3time + +/* mvcInvMVD takes the other one of the possible MVD values defined in + H.263 Recommendation */ +#define mvcInvMVD(invMv) \ + (invMv < 0) ? \ + MVD_320 + invMv : \ + -MVD_320 + invMv + +/* sign123(x) returns + 1 if x < 0, + 2 if x > 0, + 3 if x == 0 + In other words, + bit 0 = 1 if x <= 0, + bit 1 = 1 if x >= 0 */ +#define sign123(x) ((x == 0) ? 3 : (x < 0) ? 1 : 2) + + +/* + * Local prototypes + */ + +static void mvcGetNeighbourMVs(mvcData_t *mvcData, int x, int y, int time, + int *nmvx, int *nmvy, int prevFlag, int16 *error); + +__inline static void mvcCheckAndSet( + mvRowItem_t *mvRowPtr, int xind, int yind, int time, int nind, + int *nmvx, int *nmvy, mvRowItem_t *cmvRowPtr, int cxind, int cyind, + int16 *error); + +__inline static void mvcSetToCurrent( + mvRowItem_t *mvRowPtr, int xind, int yind, int time, int nind, + int *nmvx, int *nmvy, int16 *error); + + +/* + * Global functions + */ + + +/* {{-output"mvcSetBorders.txt"}} */ +/* + * + * mvcSetBorders + * + * Parameters: + * mvcData mvcData_t structure + * x the x coordinate of the MB (0 .. maxX) + * y the y coordinate of the MB + * (0 .. macroblock rows in frame - 1) + * mba Macroblock address of starting MB of the slice. This + * value SHOULD be set to -1 if Annex K is not in use. + * numMBsInMBLine Number of MBs in MB line + * rightOfBorder There is a border on the left of the current MB + * downOfBorder There is a border on top of the current MB + * + * Function: + * This function calculates the borders of GOBs and Slices..This function + * SHOULD be called before mvcCalcMV..... + * + * Returns: + * Nothing + * + * Error codes: + * None + * + */ + +void mvcSetBorders( + mvcData_t *mvcData, int x, int y, int mba, int numMBsInMBLine, + int *rightOfBorder, int *downOfBorder +) +{ + int + upRightMBIsStart; + + if (mvcData) { + mvcData->rightOfBorderPrev = mvcData->rightOfBorder; + mvcData->downOfBorderPrev = mvcData->downOfBorder; + } + + if (mba == -1) { + if (x == 0) { + *rightOfBorder = 1; + } + else { + *rightOfBorder = 0; + } + + /* Always downOfBorder is set to 1, since in QCIF and CIF every GOB + has only 1 MB line. If larger images are supported, numMBLinesInGOB + should be passed here. Also number of starting MB of the GOB may be + needed...*/ + *downOfBorder = 1; + upRightMBIsStart = 0; + } + else { + int + xs, /* x coordinate of start MB */ + ys; /* y coordinate of start MB */ + xs = mba % numMBsInMBLine; + ys = mba / numMBsInMBLine; + + /* slice structured mode*/ + /* Check if there is slice border on top of the current MB: + For that, check either current MB should be on the same MB line + with the starting MB of slice or current MB should not be on the + left of the starting MB if the MB is on the second line of the + slice. */ + + if ((y == ys) || ((x < xs) && (ys+1 == y))) { + *downOfBorder = 1; + } + else { + *downOfBorder = 0; + } + /* Check if there is a slice border on the left of the current MB.*/ + if (((x == xs) && (y == ys)) || (x == 0)) { + *rightOfBorder = 1; + } + else { + *rightOfBorder = 0; + } + + /* Test the situation of MV2 is in another slice but MV3 in in the + same slice... i.e: + MB1 MB1 MB1 MB2 MB2 .........MB2 + MB2 MB2 MB2 MB2 MB2..........MB2 + * + The MB marked with * is an exmaple. MB on top of it is in another slice + but the MB which MV3 will come from is in the same slice...*/ + if ((x+1 == xs) && (y-1 == ys)) + upRightMBIsStart = 1; + else + upRightMBIsStart = 0; + } + + if (mvcData) { + mvcData->upRightMBIsStart = upRightMBIsStart; + mvcData->downOfBorder = *downOfBorder; + mvcData->rightOfBorder = *rightOfBorder; + mvcData->leftOfBorder = 0; + } +} + +/* {{-output"mvcCalcMV.txt"}} */ +/* + * + * mvcCalcMV + * + * Parameters: + * mvcData mvcData_t structure + * + * mvdx motion vector data returned by vlcGetMVD + * mvdy + * + * *mvx the resulting motion vector is placed to *mvx and *mvy + * *mvy + * + * predictorMode 0, 1, 2 or 3. See H.263 recommendation, Annex F, Figure + * 15, where modes are in the following order: + * 0 1 + * 2 3 + * + * Advanced Prediction mode: It is assumed that this + * function is called by setting predictorMode 0, 1, 2 + * and 3 in this order for a particular macroblock. + * + * Normal: This function should be called by setting + * predictorMode to 0. + * + * fourMVs if != 0, four motion vectors for current macroblock + * is assumed + * + * unrestrictedMV if != 0, unrestricted motion vector mode is used + * + * topOfGOB if != 0, the current MB is assumed to be in the + * first line of the current GOB + * + * nonEmptyGOBHeader if != 0, the GOB header of the current GOB is + * is assumed to be non-empty, and MV2 and MV3 are + * set to MV1 if they are outside the GOB. If Annex K + * is in use set this value to 1...... + * + * x the x coordinate of the MB (0 .. maxX) + * y the y coordinate of the MB + * (0 .. macroblock rows in frame - 1) + * + * time a value which is related to the time when the current + * frame must be shown. This value should be unique + * among a relatively small group of consecutive frames. + * + * mbType must be MVC_MB_INTER or MVC_MB_INTRA. MVC_MB_INTRA + * should be used only in PB frames mode. + * + * error error code + * + * fPLUSPTYPE PLUSTYPE flag + * + * fUMVLimited Annex D v2 flag + * 1 => Limited MVs (UUI = 1) + * 0 => Unlimited MVs (UUI = 01) + * + * Function: + * This function counts the motion vector value for given macroblock. + * See H.263 Recommendation 6.1.1 Differential Motion Vectors and + * Annex F. Advanced Prediction Mode. + * + * Returns: + * Changes *mvx, *mvy and possibly *error. + * + * Error codes: + * ERR_MVC_MVDX_ILLEGAL mvdx illegal + * ERR_MVC_MVDY_ILLEGAL mvdy illegal + * ERR_MVC_MVX_ILLEGAL mvx is NULL + * ERR_MVC_MVY_ILLEGAL mvy is NULL + * ERR_MVC_MODE_ILLEGAL predictorMode illegal + * ERR_MVC_X_ILLEGAL x < 0 or x > maxX + * ERR_MVC_Y_ILLEGAL y < 0 + * ERR_MVC_TIME_ILLEGAL time < 0 + * ERR_MVC_MVPTR result is not legal + * + */ + +void mvcCalcMV(mvcData_t *mvcData, int mvdx, int mvdy, + int *mvx, int *mvy, u_char predictorMode, u_char fourMVs, + u_char unrestrictedMV, u_char nonEmptyGOBHeader, int x, + int y, int time, int mbType, int16 *error, int fPLUSPTYPE, + int fUMVLimited) +/* {{-output"mvcCalcMV.txt"}} */ +{ + + int + i, j, /* loop variables */ + mvcx[3], /* Candidates: mv[0] = MV1, mv[1] = MV2, mv[2] = MV3 */ + mvcy[3], + *mv, /* mvcx or mvcy */ + *mvptr, /* == mvx or mvy */ + mvd, /* mvdx or mvdy */ + xx2, /* x * 2 */ + yx2, /* y * 2 */ + xmv1, /* index for MV1 */ + xmv2, /* index for MV2 */ + xmv3, /* index for MV3 */ + ymv1, + ymv2, + ymv3, + mvRangeLow, /* Lower boundary for MV Range + Look H.263+ Rec. Table D.1, D.2 */ + mvRangeHigh, /* Higher boundary for MV Range + Look H.263+ Rec. Table D.1, D.2 */ + picDim, /* Temporary variable for luminance width or height */ + mbCorner, /* Temporary variable for MB's topleft corner's + coordinate (x or y)*/ + mvRes; /* MB's rightmost or bottommost pixel plus MV + for checking restriction D.1.1 */ + mvRowItem_t + *currMvRow, + *prevMvRow, + *mvRow0, + *mvRow1, + *mvRow2; + + /* Check parameters */ + if ((!fPLUSPTYPE) || (!unrestrictedMV)) + { + if (mvdx < MVD_MIN || mvdx > MVD_MAX) { + *error = ERR_MVC_MVDX_ILLEGAL; + return; + } + + if (mvdy < MVD_MIN || mvdy > MVD_MAX) { + *error = ERR_MVC_MVDY_ILLEGAL; + return; + } + } + + if (!mvx) { + *error = ERR_MVC_MVX_ILLEGAL; + return; + } + + if (!mvy) { + *error = ERR_MVC_MVY_ILLEGAL; + return; + } + + if ((fourMVs && predictorMode > 3) || + (!fourMVs && predictorMode > 0)) { + *error = ERR_MVC_MODE_ILLEGAL; + return; + } + + if (x < 0 || x > mvcData->currMaxX) { + *error = ERR_MVC_X_ILLEGAL; + return; + } + + if (y < 0) { + *error = ERR_MVC_Y_ILLEGAL; + return; + } + + if (time < 0) { + *error = ERR_MVC_TIME_ILLEGAL; + return; + } + + updateRowPointers(x, y, time); + mvRow0 = mvcData->mvRow0; + mvRow1 = mvcData->mvRow1; + mvRow2 = mvcData->mvRow2; + + /* Seek candidate predictors */ + + xx2 = x << 1; /* xx2 = x * 2 */ + yx2 = y << 1; + + xmv1 = xx2 - 1 + (predictorMode & 1); + xmv2 = xx2 + (predictorMode == 1); + xmv3 = xx2 + 2 - (predictorMode > 1); + ymv1 = yx2 + (predictorMode > 1); + ymv2 = ymv3 = yx2 - 1 + (predictorMode > 1); + + if (predictorMode <= 1) { + currMvRow = mvRow1; + prevMvRow = mvRow0; + } + else { + currMvRow = mvRow2; + prevMvRow = mvRow1; + } + + if ( (predictorMode & 1) || /* right column of the MB */ + ( !mvcData->rightOfBorder && mvValid(currMvRow[xmv1], ymv1, time) ) ) { + mvcx[0] = currMvRow[xmv1].mvx; + mvcy[0] = currMvRow[xmv1].mvy; + } + else + /* if (x == 0 || motion vector for previous MB does not exist || + the previous MB belongs to a different slice) */ + mvcx[0] = mvcy[0] = 0; + + if ((y == 0 || (mvcData->downOfBorder && nonEmptyGOBHeader)) && predictorMode <= 1) { + /* mv2 and mv3 are outside the picture or GOB + (if non-empty GOB header) or outside the slice*/ + mvcx[1] = mvcx[0]; + mvcy[1] = mvcy[0]; + /* Check if the MB ont the previous line and on the next column + in in the same slice (means start MBof the slice).. */ + if (!mvcData->upRightMBIsStart) { + mvcx[2] = mvcx[0]; + mvcy[2] = mvcy[0]; + } + if (x == mvcData->currMaxX) + mvcx[2] = mvcy[2] = 0; + } + else { + if (mvValid(prevMvRow[xmv2], ymv2, time)) { + mvcx[1] = prevMvRow[xmv2].mvx; + mvcy[1] = prevMvRow[xmv2].mvy; + } + else + mvcx[1] = mvcy[1] = 0; + + if (mvValid(prevMvRow[xmv3], ymv3, time)) { + mvcx[2] = prevMvRow[xmv3].mvx; + mvcy[2] = prevMvRow[xmv3].mvy; + } + else + mvcx[2] = mvcy[2] = 0; + } + + for (j = 0, mv = mvcx, mvd = mvdx, mvptr = mvx, + picDim = mvcData->currLumWidth, mbCorner = x, + mvRangeLow = mvcData->mvRangeLowX, + mvRangeHigh = mvcData->mvRangeHighX; + j < 2; + j++, mv = mvcy, mvd = mvdy, mvptr = mvy, + picDim = mvcData->currLumHeight, mbCorner = y, + mvRangeLow = mvcData->mvRangeLowY, + mvRangeHigh = mvcData->mvRangeHighY) { + + int choice1, min, predictor; + + /* Find the median of the candidates */ + + min = mv[0]; + predictor = 32767; + + for (i = 1; i < 3; i++) { + if (mv[i] <= min) { + predictor = min; + min = mv[i]; + continue; + } + if (mv[i] < predictor) + predictor = mv[i]; + } + + /* Count the new motion vector value */ + + if (!unrestrictedMV) { + /* Default prediction mode. + Count the legal [-16..15.5] motion vector */ + + choice1 = predictor + mvd; + + *mvptr = (MVD_MIN <= choice1 && choice1 <= MVD_MAX) ? + choice1 : + /*(mvd == 0) ? + predictor :*/ /* index 32, should never happen?! */ + (mvd < 0) ? + MVD_320 + choice1 : /* index 0..31: 32 + mvd + predictor */ + -MVD_320 + choice1; /* index 33..63: -32 + mvd + predictor */ + + /* Check that the result is [-16..15.5] */ + if (*mvptr < MVD_MIN || *mvptr > MVD_MAX) { + *error = ERR_MVC_MVPTR; + return; + } + } + + else if ((-MVD_155 <= predictor && predictor <= MVD_160) && (!fPLUSPTYPE)) + /* Unrestricted motion vector mode && -15.5 <= predictor <= 16. + mvd is always valid. */ + *mvptr = predictor + mvd; + + else if (!fPLUSPTYPE) + { + /* Unrestricted motion vector mode && predictor not in [-15.5, 16] + Result in [-31.5, 31.5] and has the same sign as predictor */ + choice1 = predictor + mvd; + *mvptr = (MVD_UMIN_V1 <= choice1 && choice1 <= MVD_UMAX_V1 && + (sign123(choice1) & sign123(predictor))) ? + choice1 : + /*(mvd == 0) ? + predictor :*/ /* index 32, should never happen!? */ + (mvd < 0) ? + MVD_320 + choice1 : /* index 0..31: 32 + mvd + predictor */ + -MVD_320 + choice1; /* index 33..63: -32 + mvd + predictor */ + + /* Check that the result is in the appropriate range. */ + if ((predictor < -MVD_155 && *mvptr > 0) || + (predictor > MVD_160 && *mvptr < 0)) { + *error = ERR_MVC_MVPTR; + return; + } + + } + else if (fUMVLimited) + /* fPlusType==1 && UUI == 1*/ + { + *mvptr = predictor + mvd; + + if ( *mvptr > 0 ) + /* mvRes is the leftmost/topmost pixels coordinate of next + macroblock plus 2 times MV */ + mvRes = (mbCorner+1)*32 + (*mvptr)/5 ; + else + /* mvRes is the leftmost/topmost pixels coordinate of current + macroblock plus 2 times MV, + half a pixel corresponds to 1 in integer scale */ + mvRes = mbCorner*32 + (*mvptr)/5 ; + + if ((mvRes < -30) || (mvRes > picDim * 2 + 30)) + /* Restriction D.1.1 */ + { + *error = ERR_MVC_MVPTR; + deb("Restriction D.1.1\n"); + return; + } + + if ((*mvptr < mvRangeLow) || (*mvptr > mvRangeHigh)) + /* Restriction D.2 */ + { + *error = ERR_MVC_MVPTR; + deb("Restriction D.2 \n"); + return; + } + } + else /* fPlusType==1 && UUI == 01 */ + { + *mvptr = predictor + mvd; + if ( *mvptr > 0 ) + mvRes = (mbCorner+1)*32 + (*mvptr)/5; + else + mvRes = mbCorner*32 + (*mvptr)/5; + if ((mvRes < -30) || (mvRes > picDim * 2 + 30)) + /* Restriction D.1.1 */ + { + *error = ERR_MVC_MVPTR; + deb("Restriction D.1.1\n"); + return; + } + } + } + + /* Update motion vector buffer arrays */ + switch (predictorMode) { + case 0: + if (fourMVs) { + mvStore(mvRow1, xx2, yx2, *mvx, *mvy, time, mbType); + } + else { + mvStoreMB(mvRow1, mvRow2, xx2, yx2, *mvx, *mvy, time, mbType); + } + break; + case 1: + mvStore(mvRow1, xx2 + 1, yx2, *mvx, *mvy, time, mbType); + break; + case 2: + mvStore(mvRow2, xx2, yx2 + 1, *mvx, *mvy, time, mbType); + break; + case 3: + mvStore(mvRow2, xx2 + 1, yx2 + 1, *mvx, *mvy, time, mbType); + break; + } +} + + +/* {{-output"mvcCalcMPEGMV.txt"}} */ +/* + * + * mvcCalcMPEGMV + * + * Parameters: + * mvcData mvcData_t structure + * + * mvdx motion vector data returned by vlcGetMVD + * mvdy + * + * *mvx the resulting motion vector is placed to *mvx and *mvy + * *mvy + * + * predictorMode 0, 1, 2 or 3. See H.263 recommendation, Annex F, Figure + * 15, where modes are in the following order: + * 0 1 + * 2 3 + * + * Advanced Prediction mode: It is assumed that this + * function is called by setting predictorMode 0, 1, 2 + * and 3 in this order for a particular macroblock. + * + * Normal: This function should be called by setting + * predictorMode to 0. + * + * fourMVs if != 0, four motion vectors for current macroblock + * is assumed + * + * topOfVP if != 0, the current MB is assumed to be in the + * first line of the current VideoPacket + * + * leftOfVP if != 0, the current MB is assumed to be the + * first in the VideoPacket + * + * fmv3_out if != 0, the 3rd MB (top, right) used as MV predictor + * is outside of the current VideoPacket + * + * x the x coordinate of the MB (0 .. maxX) + * y the y coordinate of the MB + * (0 .. macroblock rows in frame - 1) + * + * time a value which is related to the time when the current + * frame must be shown. This value should be unique + * among a relatively small group of consecutive frames. + * + * mbType must be MVC_MB_INTER or MVC_MB_INTRA. MVC_MB_INTRA + * should be used only in PB frames mode. + * + * error error code + * + * Function: + * This function counts the motion vector value for given macroblock. + * See H.263 Recommendation 6.1.1 Differential Motion Vectors and + * Annex F. Advanced Prediction Mode. + * + * Returns: + * Changes *mvx, *mvy and possibly *error. + * + * Error codes: + * The following codes are assertion-like checks: + * ERR_MVC_MVDX_ILLEGAL mvdx illegal + * ERR_MVC_MVDY_ILLEGAL mvdy illegal + * ERR_MVC_MVX_ILLEGAL mvx is NULL + * ERR_MVC_MVY_ILLEGAL mvy is NULL + * ERR_MVC_MODE_ILLEGAL predictorMode illegal + * ERR_MVC_X_ILLEGAL x < 0 or x > maxX + * ERR_MVC_Y_ILLEGAL y < 0 + * ERR_MVC_TIME_ILLEGAL time < 0 + * + * The following code may also be caused by a bit error: + * ERR_MVC_MVPTR result is not legal + * + */ + +void mvcCalcMPEGMV(mvcData_t *mvcData, + int mvdx, int mvdy, int *mvx, int *mvy, + u_char predictorMode, u_char fourMVs, + u_char topOfVP, u_char leftOfVP, u_char fmv3_out, + int x, int y, int time, int mbType, int16 *error) +/* {{-output"mvccalc.txt"}} */ +{ + int + i, j, /* loop variables */ + mvcx[3], /* Candidates: mv[0] = MV1, mv[1] = MV2, mv[2] = MV3 */ + mvcy[3], + mvc1_out = 0, mvc2_out = 0, mvc3_out = 0, + *mv, /* mvcx or mvcy */ + *mvptr, /* == mvx or mvy */ + mvd, /* mvdx or mvdy */ + xx2, /* x * 2 */ + yx2, /* y * 2 */ + xmv1, /* index for MV1 */ + xmv2, /* index for MV2 */ + xmv3, /* index for MV3 */ + ymv1, + ymv2, + ymv3; + mvRowItem_t + *currMvRow, + *prevMvRow, + *mvRow0, + *mvRow1, + *mvRow2; + + + if (!mvx) { + *error = ERR_MVC_MVX_ILLEGAL; + return; + } + + if (!mvy) { + *error = ERR_MVC_MVY_ILLEGAL; + return; + } + + if ((fourMVs && predictorMode > 3) || + (!fourMVs && predictorMode > 0)) { + *error = ERR_MVC_MODE_ILLEGAL; + return; + } + + if (x < 0 || x > mvcData->currMaxX) { + *error = ERR_MVC_X_ILLEGAL; + return; + } + + if (y < 0) { + *error = ERR_MVC_Y_ILLEGAL; + return; + } + + if (time < 0) { + *error = ERR_MVC_TIME_ILLEGAL; + return; + } + + updateRowPointers(x, y, time); + mvRow0 = mvcData->mvRow0; + mvRow1 = mvcData->mvRow1; + mvRow2 = mvcData->mvRow2; + + /* Seek candidate predictors */ + + xx2 = x << 1; /* xx2 = x * 2 */ + yx2 = y << 1; + + xmv1 = xx2 - 1 + (predictorMode & 1); + xmv2 = xx2 + (predictorMode == 1); + xmv3 = xx2 + 2 - (predictorMode > 1); + ymv1 = yx2 + (predictorMode > 1); + ymv2 = ymv3 = yx2 - 1 + (predictorMode > 1); + + if (predictorMode <= 1) { + currMvRow = mvRow1; + prevMvRow = mvRow0; + } + else { + currMvRow = mvRow2; + prevMvRow = mvRow1; + } + + if ((x == 0 || leftOfVP) && !(predictorMode & 1)) { + /* mv1 is outside the VP or VOP */ + mvcx[0] = mvcy[0] = 0; + mvc1_out = 1; + } + else { + if (mvValidMPEG(currMvRow[xmv1], ymv1, time)) { + mvcx[0] = currMvRow[xmv1].mvx; + mvcy[0] = currMvRow[xmv1].mvy; + } + else mvcx[0] = mvcy[0] = 0; + } + + if ((y == 0 || topOfVP) && predictorMode <= 1) { + /* mv2 is outside the VP or VOP */ + mvcx[1] = mvcy[1] = 0; + mvc2_out = 1; + } + else { + if (mvValidMPEG(prevMvRow[xmv2], ymv2, time)) { + mvcx[1] = prevMvRow[xmv2].mvx; + mvcy[1] = prevMvRow[xmv2].mvy; + } + else mvcx[1] = mvcy[1] = 0; + } + + if ((y == 0 || fmv3_out || x == mvcData->currMaxX) && predictorMode <= 1) { + /* mv3 is outside the VP or VOP */ + mvcx[2] = mvcy[2] = 0; + mvc3_out = 1; + } + else { + if (mvValidMPEG(prevMvRow[xmv3], ymv3, time)) { + mvcx[2] = prevMvRow[xmv3].mvx; + mvcy[2] = prevMvRow[xmv3].mvy; + } + else + mvcx[2] = mvcy[2] = 0; + } + + for (j = 0, mv = mvcx, mvd = mvdx, mvptr = mvx; + j < 2; + j++, mv = mvcy, mvd = mvdy, mvptr = mvy) { + + int min, predictor; + + switch (mvc1_out + mvc2_out + mvc3_out) + { + case 3: + predictor = 0; + break; + case 2: + predictor = mv[0] + mv[1] + mv[2]; + break; + case 1: + case 0: + /* Find the median of the candidates */ + min = mv[0]; + predictor = 32767; + + for (i = 1; i < 3; i++) { + if (mv[i] <= min) { + predictor = min; + min = mv[i]; + continue; + } + if (mv[i] < predictor) + predictor = mv[i]; + } + break; + default: + /* Should never happen */ + vdcAssert(0); + predictor = 0; + break; + } + + /* Count the new motion vector value */ + *mvptr = predictor + mvd; + + if (*mvptr < -(mvcData->range)) + *mvptr += 2*(mvcData->range); + else if (*mvptr > (mvcData->range)-5) + *mvptr -= 2*(mvcData->range); + } + + /* Update motion vector buffer arrays */ + switch (predictorMode) { + case 0: + if (fourMVs) { + mvStore(mvRow1, xx2, yx2, *mvx, *mvy, time, mbType); + } + else { + mvStoreMB(mvRow1, mvRow2, xx2, yx2, *mvx, *mvy, time, mbType); + } + break; + case 1: + mvStore(mvRow1, xx2 + 1, yx2, *mvx, *mvy, time, mbType); + break; + case 2: + mvStore(mvRow2, xx2, yx2 + 1, *mvx, *mvy, time, mbType); + break; + case 3: + mvStore(mvRow2, xx2 + 1, yx2 + 1, *mvx, *mvy, time, mbType); + break; + } +} + +/* {{-output"mvcFree.txt"}} */ +/* + * + * mvcFree + * + * Parameters: + * mvcData mvcData_t structure + * + * Function: + * This function frees the dynamic memory allocated by mvcStart. + * mvcFree 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 mvcFree(mvcData_t *mvcData) +/* {{-output"mvcFree.txt"}} */ +{ + if (mvcData) { + if (mvcData->mvRow) free(mvcData->mvRow); + mvcData->currMaxX = -1; + } +} + + +/* {{-output"mvcGetCurrentMVs.txt"}} */ +/* + * + * mvcGetCurrentMVs + * + * Parameters: + * mvcData mvcData_t structure + * mvx + * mvy + * error error code + * + * Function: + * These functions return the motion vectors of the current + * blocks. + * + * Returns: + * Changes mvx, mvy and possibly error. + * + * Error codes: + * + * ERR_MVC_CURR_NOT_VALID if the motion vectors for the current + * macroblock do not exist + * + * ERR_MVC_CURR_NOT_CODED if the current macroblock was not coded + * + * ERR_MVC_CURR_INTRA if the current macroblock was coded in + * INTRA mode + * + */ +void mvcGetCurrentMVs(mvcData_t *mvcData, int *mvx, int *mvy, + int16 *error) +{ + int + xx2 = mvcData->currX << 1, + yx2 = mvcData->currY << 1; + mvRowItem_t + *mvRow1 = mvcData->mvRow1, + *mvRow2 = mvcData->mvRow2; + if (mvValid(mvRow1[xx2], yx2, mvcData->currTime) && + mvRow1[xx2].type == MVC_MB_INTER) { + mvx[0] = mvRow1[xx2].mvx; + mvx[1] = mvRow1[xx2 + 1].mvx; + mvx[2] = mvRow2[xx2].mvx; + mvx[3] = mvRow2[xx2 + 1].mvx; + mvy[0] = mvRow1[xx2].mvy; + mvy[1] = mvRow1[xx2 + 1].mvy; + mvy[2] = mvRow2[xx2].mvy; + mvy[3] = mvRow2[xx2 + 1].mvy; + } + else { + mvx[0] = mvx[1] = mvx[2] = mvx[3] = + mvy[0] = mvy[1] = mvy[2] = mvy[3] = 0; + if mvLegal(mvRow1[xx2], yx2, mvcData->currTime) { + if (mvRow1[xx2].type == MVC_MB_NOT_CODED) { + /*deb("mvcGetCurrentMVs: ERROR - macroblock not coded.\n");*/ + *error = ERR_MVC_CURR_NOT_CODED; + } + else if (mvRow1[xx2].type == MVC_MB_INTRA) { + /*deb("mvcGetCurrentMVs: ERROR - INTRA macroblock.\n");*/ + *error = ERR_MVC_CURR_INTRA; + } + else { + /*deb("mvcGetCurrentMVs: ERROR - macroblock not valid.\n");*/ + *error = ERR_MVC_CURR_NOT_VALID; + } + } + else { + /*deb("mvcGetCurrentMVs: ERROR - macroblock not valid.\n");*/ + *error = ERR_MVC_CURR_NOT_VALID; + } + } +} + +/* {{-output"mvcGetNeighbourMVs.txt"}} */ +/* + * + * mvcGetCurrNeighbourMVs + * mvcGetPrevNeighbourMVs + * + * Parameters: + * mvcData mvcData_t structure + * + * nmvx pointer to motion vector x component array + * nmvy pointer to motion vector y component array + * The size of the array must be 6. The indexing of the + * neighboring motion vectors goes like this: + * (X = the motion vector which is investigated, i.e. + * the last one decoded (mvcGetCurrNeighbourMVs) or + * the one before the last one (mvcGetPrevNeighbourMVs)) + * 2 3 + * 0 X X 4 + * 1 X X 5 + * It is suggested that the following defines are used + * instead of values: + * MVC_XM1_UP (0) + * MVC_XM1_DOWN (1) + * MVC_YM1_LEFT (2) + * MVC_YM1_RIGHT (3) + * MVC_XP1_UP (4) + * MVC_XP1_DOWN (5) + * (M stand for minus and P for plus) + * + * pmvx and pmvy are for mvcGetPrevNeighbourMVs only: + * pmvx pointer to the motion vector x component array of the + * previous macroblock + * pmvy pointer to the motion vector y component array of the + * previous macroblock + * The size of the array must be 4. The indexing is similar + * to normal block indexing inside a macroblock: + * 0 1 + * 2 3 + * + * error error code + * + * Function: + * These functions return the motion vectors of the neighboring + * blocks (on the left side, above or on the right side) of the + * macroblock which is investigated, i.e. + * - the last one decoded (mvcGetCurrNeighbourMVs) or + * - the one before the last one (mvcGetPrevNeighbourMVs)) + * + * The H.263 standard for Overlapped motion compensation for luminance + * (Annex F.3) is followed, that is: + * If one of the surrounding macroblocks was not coded, the + * corresponding remote motion vector is set to zero. If one of the + * surrounding (macro)blocks was coded in INTRA mode, the corresponding + * remote motion vector is replaced by the motion vector for the + * current block expect when in PB-frames mode. In this case (INTRA + * block in PB-frame mode), the INTRA block's motion vector is used. + * If the current block is at the border of the picture and therefore + * a surrounding block is not present, the corresponding remote motion + * vector is replaced by the current motion vector. + * + * mvcGetPrevNeighbourMVs also returns the motion vector for the + * previous macroblock. + * + * Returns: + * Changes nmvx, nmvy, pmvx, pmvy and possibly error. + * + * Error codes: + * ERR_MVC_NO_PREV_MB if the current MB has x coordinate 0 and + * mvcGetPrevNeighbourMVs is called + * + * ERR_MVC_NEIGHBOUR_NOT_VALID if one of the neighboring MVs is not + * valid, i.e. it has not been updated + * for this frame. The MV in nmvx and nmvy + * is set to zero. + * + * for mvcGetPrevNeighbourMVs only: + * ERR_MVC_PREV_NOT_VALID if the motion vectors for the previous + * macroblock do not exist + * + * ERR_MVC_PREV_NOT_CODED if the previous macroblock was not coded + * + * ERR_MVC_PREV_INTRA if the previous macroblock was coded in + * INTRA mode + * + * + * + * + * + * + * + */ + +void mvcGetCurrNeighbourMVs(mvcData_t *mvcData, int *nmvx, int *nmvy, + int16 *error) +/* {{-output"mvcGetNeighbourMVs.txt"}} */ +{ + mvRowItem_t + *mvRow1 = mvcData->mvRow1; + int xx2 = mvcData->currX << 1; + + mvcGetNeighbourMVs(mvcData, mvcData->currX, mvcData->currY, + mvcData->currTime, nmvx, nmvy, 0, error); + if (*error) { + if mvLegal(mvRow1[xx2], mvcData->currY << 1, mvcData->currTime) { + if (mvRow1[xx2].type == MVC_MB_NOT_CODED) { + /*deb("mvcGetPrevNeighbourMVs: ERROR - macroblock not coded.\n");*/ + *error = ERR_MVC_CURR_NOT_CODED; + } + else if (mvRow1[xx2].type == MVC_MB_INTRA) { + /*deb("mvcGetPrevNeighbourMVs: ERROR - INTRA macroblock.\n");*/ + *error = ERR_MVC_CURR_INTRA; + } + else { + /*deb("mvcGetPrevNeighbourMVs: ERROR - macroblock not valid.\n");*/ + *error = ERR_MVC_CURR_NOT_VALID; + } + } + else { + /*deb("mvcGetPrevNeighbourMVs: ERROR - macroblock not valid.\n");*/ + *error = ERR_MVC_CURR_NOT_VALID; + } + } +} + +/* {{-output"mvcGetPrevNeighbourMVs.txt"}} */ +void mvcGetPrevNeighbourMVs(mvcData_t *mvcData, int *nmvx, int *nmvy, + int *pmvx, int *pmvy, u_char *fourMVs, int16 *error) +/* {{-output"mvcGetPrevNeighbourMVs.txt"}} */ +{ + int + currX = mvcData->currX, + currY = mvcData->currY; + mvRowItem_t + *mvRow1 = mvcData->mvRow1, + *mvRow2 = mvcData->mvRow2; + + if (currX > 0) { + int xx2 = (currX - 1) << 1; + mvcGetNeighbourMVs(mvcData, currX - 1, currY, + mvcData->currTime, nmvx, nmvy, 1, error); + if (mvValid(mvRow1[xx2], currY << 1, mvcData->currTime) && + mvRow1[xx2].type == MVC_MB_INTER) { + pmvx[0] = mvRow1[xx2].mvx; + pmvx[1] = mvRow1[xx2 + 1].mvx; + pmvx[2] = mvRow2[xx2].mvx; + pmvx[3] = mvRow2[xx2 + 1].mvx; + pmvy[0] = mvRow1[xx2].mvy; + pmvy[1] = mvRow1[xx2 + 1].mvy; + pmvy[2] = mvRow2[xx2].mvy; + pmvy[3] = mvRow2[xx2 + 1].mvy; + *fourMVs = mvRow1[xx2].fourMVs; + } + else { + pmvx[0] = pmvx[1] = pmvx[2] = pmvx[3] = + pmvy[0] = pmvy[1] = pmvy[2] = pmvy[3] = 0; + *fourMVs = 0; + if mvLegal(mvRow1[xx2], currY << 1, mvcData->currTime) { + if (mvRow1[xx2].type == MVC_MB_NOT_CODED) { + /*deb("mvcGetPrevNeighbourMVs: ERROR - macroblock not coded.\n");*/ + *error = ERR_MVC_PREV_NOT_CODED; + } + else if (mvRow1[xx2].type == MVC_MB_INTRA) { + /*deb("mvcGetPrevNeighbourMVs: ERROR - INTRA macroblock.\n");*/ + *error = ERR_MVC_PREV_INTRA; + } + else { + /*deb("mvcGetPrevNeighbourMVs: ERROR - macroblock not valid.\n");*/ + *error = ERR_MVC_PREV_NOT_VALID; + } + } + else { + /*deb("mvcGetPrevNeighbourMVs: ERROR - macroblock not valid.\n");*/ + *error = ERR_MVC_PREV_NOT_VALID; + } + } + } + else { + /*deb("mvcGetPrevNeighbourMVs: ERROR - no previous macroblock.\n");*/ + *error = ERR_MVC_NO_PREV_MB; + } +} + + +/* {{-output"mvcGetPrevMVFsAndMVBs.txt"}} */ +/* + * + * mvcGetPrevMVFsAndMVBs + * + * Parameters: + * mvcData mvcData_t structure + * + * mvfx the resulting forward motion vector + * mvfy + * + * mvbx the resulting backward motion vector + * mvby + * + * fourMVs 1 if there is four motion vectors per macroblock + * 0 otherwise + * + * Function: + * This function gets the forward and backward motion vectors for the + * previous B macroblock. + * + * Returns: + * Changes *mvfx, *mvfy, *mvbx, *mvby and *fourMVs. + * + * Error codes: + * ERR_MVC_NO_PREV_MB if the current MB has x coordinate 0 and + * mvcGetPrevNeighbourMVs is called + * + * ERR_MVC_PREV_NOT_VALID if the motion vectors for the previous + * macroblock do not exist + * + * + */ + +void mvcGetPrevMVFsAndMVBs(mvcData_t *mvcData, int *mvfx, int *mvfy, + int *mvbx, int *mvby, u_char *fourMVs, int16 *error) +/* {{-output"mvcGetPrevMVFsAndMVBs.txt"}} */ +{ + mvBFBufItem_t + *mvFBuf = mvcData->mvFBufArray[mvcData->mvBFBufIndex ^ 1], + *mvBBuf = mvcData->mvBBufArray[mvcData->mvBFBufIndex ^ 1]; + int i; + + if (mvcData->currX > 0) { + if (mvBBuf[0].x == mvcData->currX - 1 && + mvValid(mvBBuf[0], mvcData->currY, mvcData->currTime)) { + *fourMVs = mvBBuf[0].fourMVs; + for (i = 0; i < 4; i++) { + mvfx[i] = mvFBuf[i].mvx; + mvfy[i] = mvFBuf[i].mvy; + mvbx[i] = mvBBuf[i].mvx; + mvby[i] = mvBBuf[i].mvy; + } + } + else { + /*deb("mvcGetPrevMVFsAndMVBs: ERROR - PREV_NOT_VALID.\n");*/ + *error = ERR_MVC_PREV_NOT_VALID; + } + } + else { + /*deb("mvcGetPrevMVFsAndMVBs: ERROR - NO_PREV_MB.\n");*/ + *error = ERR_MVC_NO_PREV_MB; + } +} + + +/* {{-output"mvcMarkMB.txt"}} */ +/* + * + * mvcMarkMBIntra + * mvcMarkMBNotCoded + * + * Parameters: + * mvcData mvcData_t structure + * x the x coordinate of the MB (0 .. maxX) + * y the y coordinate of the MB + * (0 .. macroblock rows in frame - 1) + * + * time a value which is related to the time when the current + * frame must be shown. This value should be unique + * among a relatively small group of consecutive frames. + * + * Function: + * These functions are used to mark that the macroblock is either + * intra coded or not coded at all. The information is used when + * deciding the neighboring motion vectors of a macroblock in + * mvcGetPrevNeighbourMVs and mvcGetCurrNeighbourMVs. + * Note that mvcMarkMBIntra should not be called in case of + * INTRA block in PB-frame mode. Instead mvcCalcMV should be used. + * + * Returns: + * Nothing + * + * Error codes: + * None + * + * + * + */ + +void mvcMarkMBIntra(mvcData_t *mvcData, int x, int y, int time) +/* {{-output"mvcMarkMB.txt"}} */ +{ + int + xx2 = x << 1, + yx2 = y << 1; + mvRowItem_t + *mvRow1, + *mvRow2; + + updateRowPointers(x, y, time); + mvRow1 = mvcData->mvRow1; + mvRow2 = mvcData->mvRow2; + mvStoreMB(mvRow1, mvRow2, xx2, yx2, MVD_INTRA, MVD_INTRA, time, MVC_MB_INTRA); +} + +/* {{-output"mvcMarkMBNotCoded.txt"}} */ +void mvcMarkMBNotCoded(mvcData_t *mvcData, int x, int y, int time) +/* {{-output"mvcMarkMBNotCoded.txt"}} */ +{ + int + xx2 = x << 1, + yx2 = y << 1; + mvRowItem_t + *mvRow1, + *mvRow2; + + updateRowPointers(x, y, time); + mvRow1 = mvcData->mvRow1; + mvRow2 = mvcData->mvRow2; + mvStoreMB(mvRow1, mvRow2, xx2, yx2, MVD_NOT_CODED, + MVD_NOT_CODED, time, MVC_MB_NOT_CODED); +} + + +/* {{-output"mvcStart.txt"}} */ +/* + * + * mvcStart + * + * Parameters: + * mvcData mvcData_t structure + * + * maxX the largest x coordinate possible for a macroblock + * If maxX if different from maxX when the function was + * last called, a new dynamic memory allocation is made. + * + * lumWidth Luminance width + * + * lumHeight Luminance height + * + * error error code + * + * Function: + * This function initialises motion vector buffers. It also allocates + * buffer memory if needed. + * One should call mvcStart in the beginning of each video sequence. + * + * Returns: + * Nothing + * + * Error codes: + * ERR_MVC_ALLOC1 dynamic allocation error + * ERR_MVC_MAX_X_ILLEGAL maxX <= 0 + * + * + * + * + */ + +void mvcStart(mvcData_t *mvcData, int maxX, int lumWidth, int lumHeight, int16 *error) +/* {{-output"mvcStart.txt"}} */ +{ + int + i, j, /* loop variables */ + rowSize; /* the number of items in prevMV?Row */ + + if (maxX < 0) { + *error = ERR_MVC_MAX_X_ILLEGAL; + return; + } + + rowSize = (maxX + 1) << 1; + + if (mvcData->currMaxX != maxX || mvcData->mvRow == NULL) { + /* frame size changed */ + + if (mvcData->mvRow) free(mvcData->mvRow); + + mvcData->mvRow = (mvRowItem_t *) vdcMalloc( + rowSize * 3 * sizeof(mvRowItem_t)); + if (mvcData->mvRow == NULL) { + deb("mvcStart: ERROR - memory allocation failed.\n"); + *error = ERR_MVC_ALLOC1; + return; + } + + mvcData->currMaxX = maxX; + } + + /* Horizontal motion vector range when PLUSTYPE present and UUI = 1 + See Table D.1/H.263 */ + if (mvcData->currLumHeight != lumHeight) + { + mvcData->currLumHeight = lumHeight; + if ((lumHeight>=4)&&(lumHeight<=288)) + { + mvcData->mvRangeLowY = -320; + mvcData->mvRangeHighY = 315; + } + else if ((lumHeight>=292)&&(lumHeight<=576)) + { + mvcData->mvRangeLowY = -640; + mvcData->mvRangeHighY = 635; + } + else if ((lumHeight>=580)&&(lumHeight<=1152)) + { + mvcData->mvRangeLowY = -1280; + mvcData->mvRangeHighY = 1275; + } + } + + /* Vertical motion vector range when PLUSTYPE present and UUI = 1 + See Table D.2/H.263 */ + if (mvcData->currLumWidth != lumWidth) + { + mvcData->currLumWidth = lumWidth; + if ((lumWidth>=4)&&(lumWidth<=352)) + { + mvcData->mvRangeLowX = -320; + mvcData->mvRangeHighX = 315; + } + else if ((lumWidth>=356)&&(lumWidth<=704)) + { + mvcData->mvRangeLowX = -640; + mvcData->mvRangeHighX = 635; + } + else if ((lumWidth>=708)&&(lumWidth<=1408)) + { + mvcData->mvRangeLowX = -1280; + mvcData->mvRangeHighX = 1275; + } + else if ((lumWidth>=1412)&&(lumWidth<=2048)) + { + mvcData->mvRangeLowX = -2560; + mvcData->mvRangeHighX = 2555; + } + } + /* Set time to be impossible */ + for (i = 0; i < 3 * rowSize; i++) { + mvcData->mvRow[i].time = -2; + } + + for (j = 0; j < 2; j++) { + for (i = 0; i < 4; i++) { + mvcData->mvFBufArray[j][i].time = -2; + mvcData->mvBBufArray[j][i].time = -2; + } + } + + mvcData->currX = -1; + mvcData->currY = -1; + mvcData->currTime = -2; + mvcData->mvRowIndex = 0; + mvcData->mvBFBufIndex = 0; + mvcData->prevPredMode = 3; +} + + +/* Local functions */ + + + +/* + * + * mvcGetNeighbourMVs + * + * Parameters: + * mvcData mvcData_t structure + * x + * y macroblock coordinates + * time time reference + * nmvx pointer to motion vector x component array + * nmvy pointer to motion vector y component array + * See mvcGetCurrNeighbourMVs/mvcGetPrevNeighbourMVs for + * description. + * prevFlag If this flag is set, the previous border values should + * be used. + * error error code + * + * Function: + * This function return the motion vectors of the neighboring + * blocks (on the left side, above or on the right side) of the + * macroblock which is investigated. mvcGetNeighbourMVs is used + * by mvcGetCurrNeighbourMVs and mvcGetPrevNeighbourMVs. + * See also the functional description for these functions. + * + * Returns: + * Changes nmvx and nmvy and possibly error. + * + * Error codes: + * ERR_MVC_NEIGHBOUR_NOT_VALID if one of the neighboring MVs is not + * valid, i.e. it has not been updated + * for this frame. The MV in nmvx and nmvy + * is set to zero. + * + * + */ + +static void mvcGetNeighbourMVs(mvcData_t *mvcData, int x, int y, int time, + int *nmvx, int *nmvy, int prevFlag, int16 *error) +{ + int + xx2 = x << 1, + yx2 = y << 1, + xtmp, + ytmp, + rightOfBorder, + downOfBorder, + leftOfBorder; + mvRowItem_t + *mvRow0 = mvcData->mvRow0, + *mvRow1 = mvcData->mvRow1, + *mvRow2 = mvcData->mvRow2; + + if (prevFlag) { + rightOfBorder = mvcData->rightOfBorderPrev; + downOfBorder = (mvcData->fSS)?mvcData->downOfBorderPrev:(y==0); + leftOfBorder = 0; + } + else { + rightOfBorder = mvcData->rightOfBorder; + downOfBorder = (mvcData->fSS)?mvcData->downOfBorder:(y==0); + leftOfBorder = (mvcData->fSS)?(x == mvcData->currMaxX)||(mvcData->leftOfBorder):(x == mvcData->currMaxX); + } + //if (x > 0) { + if (!rightOfBorder) { + xtmp = xx2 - 1; + mvcCheckAndSet(mvRow1, xtmp, yx2, time, MVC_XM1_UP, nmvx, nmvy, + mvRow1, xx2, yx2, error); + mvcCheckAndSet(mvRow2, xtmp, yx2 + 1, time, MVC_XM1_DOWN, nmvx, nmvy, + mvRow2, xx2, yx2 + 1, error); + } + else { + mvcSetToCurrent(mvRow1, xx2, yx2, time, MVC_XM1_UP, nmvx, nmvy, + error); + mvcSetToCurrent(mvRow2, xx2, yx2 + 1, time, MVC_XM1_DOWN, nmvx, nmvy, + error); + } + + //if (y > 0) { + if (!downOfBorder) { + ytmp = yx2 - 1; + mvcCheckAndSet(mvRow0, xx2, ytmp, time, MVC_YM1_LEFT, nmvx, nmvy, + mvRow1, xx2, yx2, error); + mvcCheckAndSet(mvRow0, xx2 + 1, ytmp, time, MVC_YM1_RIGHT, nmvx, nmvy, + mvRow1, xx2 + 1, yx2, error); + } + else { + mvcSetToCurrent(mvRow1, xx2, yx2, time, MVC_YM1_LEFT, nmvx, nmvy, + error); + mvcSetToCurrent(mvRow1, xx2 + 1, yx2, time, MVC_YM1_RIGHT, nmvx, nmvy, + error); + } + + //if (x < mvcData->currMaxX) { + if (!leftOfBorder) { + xtmp = xx2 + 2; + mvcCheckAndSet(mvRow1, xtmp, yx2, time, MVC_XP1_UP, nmvx, nmvy, + mvRow1, xtmp - 1, yx2, error); + mvcCheckAndSet(mvRow2, xtmp, yx2 + 1, time, MVC_XP1_DOWN, nmvx, nmvy, + mvRow2, xtmp -1, yx2 + 1, error); + } + else { + xtmp = xx2 + 1; + mvcSetToCurrent(mvRow1, xtmp, yx2, time, MVC_XP1_UP, nmvx, nmvy, + error); + mvcSetToCurrent(mvRow2, xtmp, yx2 + 1, time, MVC_XP1_DOWN, nmvx, nmvy, + error); + } +} + + + +/* + * mvcCheckAndSet + * + * Parameters: + * mvRowPtr Source row item pointer + * xind x index of the source block + * yind y index of the source block + * timeref time reference + * nind index to motion vector arrays ( x and y) + * nmvx pointer to motion vector x component array + * nmvy pointer to motion vector y component array + * cmvRowPtr Target row item pointer + * cxind x index of the target block + * cyind y index of the target block + * error error code + * + * Function: + * Sets the correct value for neighboring motion vector + * used from: mvcGetNeighbourMVs + * + * Returns: + * Nothing + * + * Error codes: + * + */ + +__inline static void mvcCheckAndSet( + mvRowItem_t *mvRowPtr, int xind, int yind, int timeref, int nind, + int *nmvx, int *nmvy, mvRowItem_t *cmvRowPtr, int cxind, int cyind, + int16 *error) +{ + + if (mvLegal(mvRowPtr[xind], yind, timeref)) { + if (mvRowPtr[xind].mvx >= MVD_UMIN_V2) { + nmvx[nind] = mvRowPtr[xind].mvx; + nmvy[nind] = mvRowPtr[xind].mvy; + } + else if (mvRowPtr[xind].mvx == MVD_INTRA) { + if (mvLegal(cmvRowPtr[cxind], cyind, timeref)) { + if (mvValid(cmvRowPtr[cxind], cyind, timeref)) { + nmvx[nind] = cmvRowPtr[cxind].mvx; + nmvy[nind] = cmvRowPtr[cxind].mvy; + } + else /* Not coded macroblock */ + nmvx[nind] = nmvy[nind] = 0; + } + else { + deb("mvcCheckAndSet: ERROR - neighbour not valid.\n"); + *error = ERR_MVC_NEIGHBOUR_NOT_VALID; + nmvx[nind] = nmvy[nind] = 0; + } + } + else { /* MVD_NOT_CODED */ + nmvx[nind] = nmvy[nind] = 0; + } + } + else { + deb("mvcCheckAndSet: ERROR - neighbour not valid.\n"); + *error = ERR_MVC_NEIGHBOUR_NOT_VALID; + nmvx[nind] = nmvy[nind] = 0; + } +} + +/* + * mvcSetToCurrent + * + * Parameters: + * mvRowPtr Current row item pointer + * xind x index of the block + * yind y index of the block + * timeref time reference + * nind index to motion vector arrays ( x and y) + * nmvx pointer to motion vector x component array + * nmvy pointer to motion vector y component array + * error error code + * + * Function: + * Sets the correct value for neighboring motion vector using current + * motion vector, used in cases of border used from: mvcGetNeighbourMVs + * + * Returns: + * Nothing + * + * Error codes: + * + * History + */ + +__inline static void mvcSetToCurrent( + mvRowItem_t *mvRowPtr, int xind, int yind, int timeref, int nind, + int *nmvx, int *nmvy, int16 *error) +{ + if (mvValid(mvRowPtr[xind], yind, timeref)) { + nmvx[nind] = mvRowPtr[xind].mvx; + nmvy[nind] = mvRowPtr[xind].mvy; + } + else { + deb("mvcSetToCurrent: ERROR - neighbour not valid.\n"); + *error = ERR_MVC_NEIGHBOUR_NOT_VALID; + nmvx[nind] = nmvy[nind] = 0; + } +} + +// End of File