videoeditorengine/h263decoder/src/vdcmvc.cpp
changeset 0 951a5db380a0
--- /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