mcomp.c
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:79k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. /*-----------------------------------------------------------------------------
  36.  *  MCOMP.C
  37.  *
  38.  *  DESCRIPTION
  39.  *      mcomp.c - Motion compensation for H.263 codec
  40.  *          Performs motion compensation for a macroblock with half-pixel accuracy
  41.  *          Supports Unrestricted Motion Vector mode, i.e., motion vectors are allowed
  42.  *          to point outside picture boundaries; uses edge pixels when needed.
  43.  *          Supports Advanced Prediction mode, i.e., four motion vectors per macroblock
  44.  *          and overlapped motion compensation for luminance.
  45.  *
  46.  *          In Advanced Prediction mode, the prediction is formed in two steps.
  47.  *          First, MotionComp263 is called to generate non-overlapped motion compensation.
  48.  *          Then, OverlapMC is called to perform the overlapping on the luminance.
  49.  *          OverlapMC requires mv's from left, top, and right neighbors.  Therefore,
  50.  *          the encoder needs to decide on the coding mode for the next mb (i.e., to the
  51.  *          right) before overlap can be done.
  52.  *
  53.  *          In PB-frame mode, the B-frame prediction is generated by PredBframe.  It uses
  54.  *          previous P-frame and the corresponding macroblock from the next P-frame.
  55.  *          Hence, the next P-frame macroblock needs to be reconstructed before calling 
  56.  *          PredBframe.
  57.  *
  58.  *          This module also contains the motion compensation routine for 
  59.  *          H.261 (MotionComp), which performs integer motion compensation.
  60.  *          MotionComp was extracted from file PREDSEL.C and modified.
  61.  *
  62.  *  CALLING SEQUENCE
  63.  *      MotionComp263(  MACROBLOCK_DESCR * mb,  // Describes block to be motion-compensated
  64.  *                      PICTURE * prev_pic,     // Describes previous picture used to form MC
  65.  *                      PICTURE * pic)          // Output picture where MC block is placed
  66.  *      OverlapMC( MACROBLOCK_DESCR * mb,   // Describes block to be motion-compensated
  67.  *                      PICTURE * prevPic,  // Describes previous picture used to form MC
  68.  *                      PICTURE * pic,      // Output picture where MC block is placed
  69.  *                      int     mbWidth,    // Macroblocks per row
  70.  *                      int     mbOffset,   // Row offset; (mb-mbOffset) is neighbor on top
  71.  *                      int     overlap[4]  // Returns YES or NO to indicate whether overlap
  72.  *                      )                   // was done in each 8x8 subblock
  73.  *      PredBframe( MACROBLOCK_DESCR * mb,  // Macroblock to be predicted
  74.  *                      PICTURE * prevPic,      // Prev. picture (forward pred)
  75.  *                      PICTURE * nextPic,      // Next P-picture (backward pred)
  76.  *                      PICTURE * Bpic          // Output picture where pred is placed
  77.  *                      )
  78.  *
  79.  *          The routines do not return a value.
  80.  *
  81.  *          Assumptions:
  82.  *          1. "pic", "prev_pic", "nextPic", and "Bpic" have same line offset and size
  83.  *          2. Chroma components Cb and Cr have same line offset and size
  84.  *          3. All arrays are quad-aligned, i.e., start address is multiple of 4.
  85.  *          4. Motion vectors are represented with one fractional bit
  86.  *
  87.  *
  88.  *      MotionComp(     MACROBLOCK_DESCR * mb,  // Describes block to be motion-compensated
  89.  *                      PICTURE * prev_pic,     // Describes previous picture used to form MC
  90.  *                      PICTURE * pic )         // Output picture where MC block is placed
  91.  *
  92.  *          The routine returns H261_ERROR if motion vectors point outside picture, otherwise OK.
  93.  *
  94.  *          Assumptions:
  95.  *          1-3. As above
  96.  *          4. Motion vectors are represented by integers.
  97.  *
  98.  *
  99.  -----------------------------------------------------------------------------*/ 
  100. //#include <stdio.h>
  101. //#include <stdlib.h>
  102. #ifdef _MACINTOSH
  103. #include <stdlib.h> // for exit()
  104. #endif
  105. #include "dllindex.h"
  106. #include "h261defs.h"
  107. #include "h261func.h"
  108. #ifdef COMPILE_MMX
  109. #include "mmxcpuid.h"
  110. #endif
  111. //#define VVPROFILER
  112. #ifdef VVPROFILER
  113. #include "hvdebtim.h"
  114. extern struct CVvDebugTimer * pVvProf[];
  115. extern unsigned long pVvProfCount[];
  116. #endif
  117. // Declarations of local functions
  118. static int chromaMVComp( int mvLuma );
  119. static int chromaMvComp4V( S8 mvLuma[4] );
  120. void mc( int hSize, int vSize, 
  121.                     PIXEL in[], PIXEL out[], int hdim,
  122.                     int mvX, int mvY    // Motion vector
  123.                     );
  124. void mcMMX( int hSize, int vSize, 
  125.                     PIXEL in[], PIXEL out[], int hdim,
  126.                     int mvX, int mvY    // Motion vector
  127.                     );
  128. static void limitMC( int hSize, int vSize, 
  129.                     PIXEL const *in, PIXEL *out, int hdim,
  130.                     int mvX, int mvY,   // Motion vector
  131.                     int minX, int maxX, int minY, int maxY // Limits for hor/vert indices
  132.                     );
  133. static int mvDiff( int mvX, int mvY,    // motion vector
  134.                 MACROBLOCK_DESCR const *borderMB,   // adjacent macroblock
  135.                 int subBlk, // adjacent subblock (needed if borderMB has 4 motion vectors)
  136.                 int PBframe,    // If PBframe: do overlap also with INTRA neighbor
  137.                 int border[2]   // return motion vector components for adjacent block
  138.                 );
  139. static void doOverlapMC( int subBlk,    // Indicates subblock to process (UL, UR, LL, LR)
  140.                     MACROBLOCK_DESCR *mb,   // Used to determine (x,y) coordinates for block
  141.                     PICTURE *prevPic,   // Previous picture; used to create overlapping MC
  142.                     PICTURE *pic, // Contains non-overlapped MC on entry; returns overlapped MC
  143.                     int borderMv[4][2], // Motion vectors for adjacent blocks (L,Top,R,Bottom)
  144.                     int left,           // If YES, overlap using LEFT mv
  145.                     int top,            // If YES, overlap using TOP mv
  146.                     int right,          // If YES, overlap using RIGHT mv
  147.                     int bottom          // If YES, overlap using BOTTOM mv
  148.                     );
  149. static void weigh8x4( PIXEL dest[], PIXEL const *p, int hdim, int vert, int left, int right );
  150. static void weighLeft_Vert( PIXEL *dest, PIXEL const *p, int hdim );
  151. static void weighNoLeft_Vert( PIXEL *dest, PIXEL const *p, int hdim );
  152. static void weighLeft( PIXEL *dest, PIXEL const *p, int hdim );
  153. static void weighRight_Vert( PIXEL *dest, PIXEL const *p, int hdim );
  154. static void weighNoRight_Vert( PIXEL *dest, PIXEL const *p, int hdim );
  155. static void weighRight( PIXEL *dest, PIXEL const *p, int hdim );
  156. static void mc16pelsNoInterpol( PIXEL *in, PIXEL out[], int hdim, int vSize );
  157. static void mc8pelsNoInterpol( PIXEL *in, PIXEL out[], int hdim, int vSize );
  158. static void mc4pelsNoInterpol( PIXEL *in, PIXEL out[], int hdim, int vSize );
  159. static void mc16pelsHorInterpol( PIXEL const *in, PIXEL out[], int hdim, int vSize );
  160. static void mc8pelsHorInterpol( PIXEL const *in, PIXEL out[], int hdim, int vSize );
  161. static void mc4pelsHorInterpol( PIXEL const *in, PIXEL out[], int hdim, int vSize );
  162. static void mc16pelsVertInterpol( PIXEL const *in, PIXEL out[], int hdim, int vSize );
  163. static void mc8pelsVertInterpol( PIXEL const *in, PIXEL out[], int hdim, int vSize );
  164. static void mc4pelsVertInterpol( PIXEL const *in, PIXEL out[], int hdim, int vSize );
  165. static void mc16pels2DInterpol( PIXEL const *in, PIXEL out[], int hdim, int vSize );
  166. static void mc8pels2DInterpol( PIXEL const *in, PIXEL out[], int hdim, int vSize );
  167. static void mc4pels2DInterpol( PIXEL const *in, PIXEL out[], int hdim, int vSize );
  168. static void saveBackwardPred( MACROBLOCK_DESCR * mb,    // Describes block to be saved
  169.                               PICTURE * pic // Picture with pixels to be saved
  170.                               );
  171. static void averageForBack( MACROBLOCK_DESCR * mb,  // Describes block to be averaged
  172.                             PICTURE * pic   // Input: contains forward prediction
  173.                                             // Output: contains B-frame prediction
  174.                             );
  175. static void copyBlock( S32 source[], int hSize, int vSize, int sourceOffset,
  176.                        S32 dest[], int destOffset );
  177. void averageBlock( PIXEL forPred[], int hSize, int vSize, int forOffset,
  178.                           PIXEL backPred[], int backOffset );
  179. void averageBlockMMX( PIXEL forPred[], int hSize, int vSize, int forOffset,
  180.                           PIXEL backPred[], int backOffset );
  181. // MotionComp - perform integer-pixel motion compensation for H.261
  182. extern int  MotionComp( MACROBLOCK_DESCR *mb, PICTURE *prev_pic, PICTURE *pic )
  183. {
  184.     int     row, col, status, i, cx, cy, pic_offset, prev_offset;
  185.     union {     // Copy words to speed up routine
  186.         PIXEL   * pix;
  187.         S32    * word;
  188.     } pixel, prev;
  189.     PIXEL   * source, * dest;
  190.     status = OK;
  191.     if (mb->mv_x == 0  &&  mb->mv_y == 0) {   // Copy macroblock
  192.         col = 16 * mb->x;
  193.         row = 16 * mb->y;
  194.         pic_offset = col + row * pic->y.hoffset;
  195.         pixel.pix = pic->y.ptr + pic_offset;
  196.         prev.pix = prev_pic->y.ptr + pic_offset;
  197.         for (i = 0; i < 16; i++) {
  198.             *(pixel.word) = *(prev.word);
  199.             *(pixel.word + 1) = *(prev.word + 1);
  200.             *(pixel.word + 2) = *(prev.word + 2);
  201.             *(pixel.word + 3) = *(prev.word + 3);
  202.             pixel.pix += pic->y.hoffset;
  203.             prev.pix += pic->y.hoffset;
  204.         }
  205.         if (pic->color) {
  206.             col = 8 * mb->x;
  207.             row = 8 * mb->y;
  208.             // Assuming same offset for Cr and Cb
  209.             pic_offset = col + row * pic->cb.hoffset;
  210.             pixel.pix = pic->cb.ptr + pic_offset;
  211.             prev.pix = prev_pic->cb.ptr + pic_offset;
  212.             for (i = 0; i < 8; i++) {
  213.                 *(pixel.word) = *(prev.word);
  214.                 *(pixel.word + 1) = *(prev.word + 1);
  215.                 pixel.pix += pic->cb.hoffset;
  216.                 prev.pix += pic->cb.hoffset;
  217.             }
  218.             pixel.pix = pic->cr.ptr + pic_offset;
  219.             prev.pix = prev_pic->cr.ptr + pic_offset;
  220.             for (i = 0; i < 8; i++) {
  221.                 *(pixel.word) = *(prev.word);
  222.                 *(pixel.word + 1) = *(prev.word + 1);
  223.                 pixel.pix += pic->cr.hoffset;
  224.                 prev.pix += pic->cr.hoffset;
  225.             }
  226.         }
  227.     } else {    // Non-zero motion vector
  228.         // Wrap motion vectors to allowed range
  229.         while (mb->mv_x < MV_MIN) {
  230.             mb->mv_x += MV_WRAP;
  231.         }
  232.         while (mb->mv_x > MV_MAX) {
  233.             mb->mv_x -= MV_WRAP;
  234.         }
  235.         while (mb->mv_y < MV_MIN) {
  236.             mb->mv_y += MV_WRAP;
  237.         }
  238.         while (mb->mv_y > MV_MAX) {
  239.             mb->mv_y -= MV_WRAP;
  240.         }
  241.         // Compute pointers
  242.         col = 16 * mb->x;
  243.         row = 16 * mb->y;
  244.         if (col == 0  &&  mb->mv_x < 0) {    // Pointing left of first col?
  245.             mb->mv_x = 0, status = H261_ERROR;
  246.         }
  247.         if (col == pic->y.nhor - 16  &&  mb->mv_x > 0) {  // Right of last col?
  248.             mb->mv_x = 0, status = H261_ERROR;
  249.         }
  250.         if (row == 0  &&  mb->mv_y < 0) {    // Pointing above first row?
  251.             mb->mv_y = 0, status = H261_ERROR;
  252.         }
  253.         if (row == pic->y.nvert - 16  &&  mb->mv_y > 0) {  // Below last row?
  254.             mb->mv_y = 0, status = H261_ERROR;
  255.         }
  256.         // Copy displaced macroblock
  257.         pic_offset = col + row * pic->y.hoffset;
  258.         prev_offset = col + mb->mv_x + (row + mb->mv_y) * pic->y.hoffset;
  259.         pixel.pix = pic->y.ptr + pic_offset;
  260.         prev.pix = prev_pic->y.ptr + prev_offset;
  261.         for (i = 0; i < 16; i++) {
  262.             source = prev.pix;
  263.             for (dest = pixel.pix; dest < pixel.pix + 16; dest++) {
  264.                 *dest = *(source++);
  265.             }
  266.             pixel.pix += pic->y.hoffset;
  267.             prev.pix += pic->y.hoffset;
  268.         }
  269.         if (pic->color) {
  270.             col = 8 * mb->x;
  271.             row = 8 * mb->y;
  272.             // Truncate motion vectors for chroma towards zero
  273.             if (mb->mv_x < 0) {
  274.                 cx = (mb->mv_x + 1) >> 1;
  275.             } else {
  276.                 cx = mb->mv_x >> 1;
  277.             }
  278.             if (mb->mv_y < 0) {
  279.                 cy = (mb->mv_y + 1) >> 1;
  280.             } else {
  281.                 cy = mb->mv_y >> 1;
  282.             }
  283.             // Assuming same offset for Cr and Cb
  284.             pic_offset = col + row * pic->cb.hoffset;
  285.             prev_offset = col + cx + (row + cy) * pic->cb.hoffset;
  286.             pixel.pix = pic->cb.ptr + pic_offset;
  287.             prev.pix = prev_pic->cb.ptr + prev_offset;
  288.             for (i = 0; i < 8; i++) {
  289.                 source = prev.pix;
  290.                 for (dest = pixel.pix; dest < pixel.pix + 8; dest++) {
  291.                     *dest = *(source++);
  292.                 }
  293.                 pixel.pix += pic->cb.hoffset;
  294.                 prev.pix += pic->cb.hoffset;
  295.             }
  296.             pixel.pix = pic->cr.ptr + pic_offset;
  297.             prev.pix = prev_pic->cr.ptr + prev_offset;
  298.             for (i = 0; i < 8; i++) {
  299.                 source = prev.pix;
  300.                 for (dest = pixel.pix; dest < pixel.pix + 8; dest++) {
  301.                     *dest = *(source++);
  302.                 }
  303.                 pixel.pix += pic->cr.hoffset;
  304.                 prev.pix += pic->cr.hoffset;
  305.             }
  306.         }
  307.     }
  308.     return (status);
  309. }
  310. // MotionComp263 - perform half-pixel motion compensation for H.263
  311. extern void MotionComp263( MACROBLOCK_DESCR * mb, // Describes block to be motion-compensated
  312.                             PICTURE * prevPic,  // Describes previous picture used to form MC
  313.                             PICTURE * pic       // Output picture where MC block is placed
  314.                             )
  315. {
  316.     int     row, col, cX, cY, picOffset, hdim, nhor, nvert;
  317.     PIXEL   * source, * dest;
  318. void (*pMC) ( int hSize, int vSize, PIXEL *in, PIXEL *out, int hdim, int mvX, int mvY);
  319. #if defined(COMPILE_MMX)
  320. if(cpuid_is_mmx_motion_on()) {
  321. //do mmx if compiler switch AND initialized AND detected
  322. pMC = mcMMX;
  323. } else 
  324. #endif
  325. {
  326. pMC = mc;
  327. }
  328.     // Compute luma pointers
  329.     col = 16 * mb->x;
  330.     row = 16 * mb->y;
  331.     hdim = pic->y.hoffset;
  332.     nhor = pic->y.nhor, nvert = pic->y.nvert;
  333.     picOffset = col + row * hdim;
  334.     dest = pic->y.ptr + picOffset;          // Point to output luma
  335.     source = prevPic->y.ptr + picOffset;    // Point to input luma (without motion comp)
  336.     // Do motion compensation for luma
  337.     if (mb->mtype == MTYPE263_INTER4V) {    // 4 motion vectors
  338.         // Upper left block
  339.         if (PointingOutside( col, col+7, row, row+7, mb->blkMvX[UPPER_LEFT_BLK], 
  340.                             mb->blkMvY[UPPER_LEFT_BLK], nhor, nvert )  ==  NO) {
  341.             pMC( 8, 8, source, dest, hdim, 
  342.                         mb->blkMvX[UPPER_LEFT_BLK], mb->blkMvY[UPPER_LEFT_BLK] );
  343.         } else {
  344.             limitMC( 8, 8, source, dest, hdim,
  345.                         mb->blkMvX[UPPER_LEFT_BLK], mb->blkMvY[UPPER_LEFT_BLK],
  346.                         -col, nhor - 1 - col, -row, nvert - 1 - row );
  347.         }
  348.         // Upper right block
  349.         if (PointingOutside( col+8, col+15, row, row+7, mb->blkMvX[UPPER_RIGHT_BLK], 
  350.                             mb->blkMvY[UPPER_RIGHT_BLK], nhor, nvert )  ==  NO) {
  351.             pMC( 8, 8, source + 8, dest + 8, hdim,
  352.                         mb->blkMvX[UPPER_RIGHT_BLK], mb->blkMvY[UPPER_RIGHT_BLK] );
  353.         } else {
  354.             limitMC( 8, 8, source + 8, dest + 8, hdim,
  355.                         mb->blkMvX[UPPER_RIGHT_BLK], mb->blkMvY[UPPER_RIGHT_BLK],
  356.                         -col - 8, nhor - 1 - col - 8, -row, nvert - 1 - row );
  357.         }
  358.         // Lower left block
  359.         source += 8 * hdim;   // Advance 8 lines
  360.         dest += 8 * hdim;
  361.         if (PointingOutside( col, col+7, row+8, row+15, mb->blkMvX[LOWER_LEFT_BLK], 
  362.                             mb->blkMvY[LOWER_LEFT_BLK], nhor, nvert )  ==  NO) {
  363.             pMC( 8, 8, source, dest, hdim,
  364.                         mb->blkMvX[LOWER_LEFT_BLK], mb->blkMvY[LOWER_LEFT_BLK] );
  365.         } else {
  366.             limitMC( 8, 8, source, dest, hdim,
  367.                         mb->blkMvX[LOWER_LEFT_BLK], mb->blkMvY[LOWER_LEFT_BLK],
  368.                         -col, nhor - 1 - col, -row - 8, nvert - 1 - row - 8 );
  369.         }
  370.         // Lower right block
  371.         if (PointingOutside( col+8, col+15, row+8, row+15, mb->blkMvX[LOWER_RIGHT_BLK],
  372.                             mb->blkMvY[LOWER_RIGHT_BLK], nhor, nvert )  ==  NO) {
  373.             pMC( 8, 8, source + 8, dest + 8, hdim,
  374.                         mb->blkMvX[LOWER_RIGHT_BLK], mb->blkMvY[LOWER_RIGHT_BLK] );
  375.         } else {
  376.             limitMC( 8, 8, source + 8, dest + 8, hdim,
  377.                         mb->blkMvX[LOWER_RIGHT_BLK], mb->blkMvY[LOWER_RIGHT_BLK],
  378.                         -col - 8, nhor - 1 - col - 8, -row - 8, nvert - 1 - row - 8 );
  379.         }
  380.         // Compute chroma mv
  381.         cX = chromaMvComp4V( mb->blkMvX );
  382.         cY = chromaMvComp4V( mb->blkMvY );
  383.     
  384.     } else {    // One motion vector
  385.         if (PointingOutside( col, col+15, row, row+15, mb->mv_x, mb->mv_y,
  386.                                 nhor, nvert )  ==  NO) {
  387.             pMC( 16, 16, source, dest, hdim, mb->mv_x, mb->mv_y );
  388.         } else {    // Pointing outside
  389.             limitMC( 16, 16, source, dest, hdim, mb->mv_x, mb->mv_y,
  390.                         -col, nhor - 1 - col, -row, nvert - 1 - row );
  391.         }
  392.         // Compute chroma mv
  393.         cX = chromaMVComp( mb->mv_x );
  394.         cY = chromaMVComp( mb->mv_y );
  395.     }
  396.     
  397.     // Do motion compensation for chroma
  398.     if (pic->color) {
  399.         // Compute chroma pointers
  400.         col = 8 * mb->x;
  401.         row = 8 * mb->y;
  402.         hdim = pic->cb.hoffset;
  403.         nhor = pic->cb.nhor, nvert = pic->cb.nvert;
  404.         picOffset = col + row * hdim;
  405.         if (PointingOutside( col, col+7, row, row+7, cX, cY, nhor, nvert )  ==  NO) {
  406.             pMC( 8, 8, prevPic->cb.ptr + picOffset, pic->cb.ptr + picOffset, hdim, cX, cY );
  407.             pMC( 8, 8, prevPic->cr.ptr + picOffset, pic->cr.ptr + picOffset, hdim, cX, cY );
  408.         } else {
  409.             limitMC( 8, 8, prevPic->cb.ptr + picOffset, pic->cb.ptr + picOffset,
  410.                     hdim, cX, cY, -col, nhor - 1 - col, -row, nvert - 1 - row );
  411.             limitMC( 8, 8, prevPic->cr.ptr + picOffset, pic->cr.ptr + picOffset,
  412.                     hdim, cX, cY, -col, nhor - 1 - col, -row, nvert - 1 - row );
  413.         }
  414.     }
  415.     return;
  416. }
  417. // printBlk - for debugging
  418. /*static void printBlk( int hSize, int vSize, PIXEL *p, int hdim)
  419. {
  420.     int i,j;
  421.     
  422.     for (i = 0; i < vSize; ++i) {
  423.         for (j = 0; j < hSize; ++j) {
  424.             printf(" %3d", *(p + j));
  425.         }
  426.         printf("n");
  427.         p += hdim;
  428.     }
  429.     return;
  430. }*/
  431. // Enumerate array of motion vectors
  432. #define LEFT        (0)
  433. #define TOP         (1)
  434. #define RIGHT       (2)
  435. #define BOTTOM      (3)
  436. // Do overlapped motion comp. for luma
  437. extern void OverlapMC( MACROBLOCK_DESCR * mb,   // Describes block to be motion-compensated
  438.                         int     PBframe,    // Non-zero if PB frame
  439.                         PICTURE * prevPic,  // Describes previous picture used to form MC
  440.                         PICTURE * pic,      // Output picture where MC block is placed
  441.                         int     mbWidth,    // Macroblocks per row
  442.                         int     mbOffset,   // Row offset; (mb-mbOffset) is neighbor on top
  443.                         int     overlap[4]  // Returns YES or NO to indicate whether overlap
  444.                                             // was done in each 8x8 subblock
  445.                         )
  446. {
  447.     int left, top, right, bottom, mvX, mvY;
  448.     int borderMv[4][2]; // motion vectors for neighbors (left, top, right, bottom)
  449.     
  450.     if (mb->mtype == MTYPE263_INTER4V) {
  451.         // Upper left block
  452.         mvX = mb->blkMvX[UPPER_LEFT_BLK];
  453.         mvY = mb->blkMvY[UPPER_LEFT_BLK];
  454.         if (mb->x == 0)  left = NO;
  455.         else  left = mvDiff( mvX, mvY, mb-1, UPPER_RIGHT_BLK, PBframe, borderMv[LEFT] );
  456.         if (mb->y == 0)  top = NO;
  457.         else  top = mvDiff( mvX, mvY, mb-mbOffset, LOWER_LEFT_BLK, PBframe, borderMv[TOP] );
  458.         right = mvDiff( mvX, mvY, mb, UPPER_RIGHT_BLK, PBframe, borderMv[RIGHT] );
  459.         bottom = mvDiff( mvX, mvY, mb, LOWER_LEFT_BLK, PBframe, borderMv[BOTTOM] );
  460.         if (left == YES || right == YES || top == YES || bottom == YES) {
  461.             doOverlapMC( UPPER_LEFT_BLK, mb, prevPic, pic, borderMv, left,top,right,bottom);
  462.             overlap[UPPER_LEFT_BLK] = YES;
  463.         } else {
  464.             overlap[UPPER_LEFT_BLK] = NO;
  465.         }
  466.         // Upper right block
  467.         mvX = mb->blkMvX[UPPER_RIGHT_BLK];
  468.         mvY = mb->blkMvY[UPPER_RIGHT_BLK];
  469.         left = mvDiff( mvX, mvY, mb, UPPER_LEFT_BLK, PBframe, borderMv[LEFT] );
  470.         if (mb->y == 0)  top = NO;
  471.         else  top = mvDiff( mvX, mvY, mb-mbOffset, LOWER_RIGHT_BLK, PBframe, borderMv[TOP] );
  472.         if (mb->x == mbWidth-1)  right = NO;
  473.         else  right = mvDiff( mvX, mvY, mb+1, UPPER_LEFT_BLK, PBframe, borderMv[RIGHT] );
  474.         bottom = mvDiff( mvX, mvY, mb, LOWER_RIGHT_BLK, PBframe, borderMv[BOTTOM] );
  475.         if (left == YES || right == YES || top == YES || bottom == YES) {
  476.             doOverlapMC( UPPER_RIGHT_BLK, mb, prevPic, pic, borderMv, left,top,right,bottom);
  477.             overlap[UPPER_RIGHT_BLK] = YES;
  478.         } else {
  479.             overlap[UPPER_RIGHT_BLK] = NO;
  480.         }
  481.         // Lower left block
  482.         mvX = mb->blkMvX[LOWER_LEFT_BLK];
  483.         mvY = mb->blkMvY[LOWER_LEFT_BLK];
  484.         if (mb->x == 0)  left = NO;
  485.         else  left = mvDiff( mvX, mvY, mb-1, LOWER_RIGHT_BLK, PBframe, borderMv[LEFT] );
  486.         top = mvDiff( mvX, mvY, mb, UPPER_LEFT_BLK, PBframe, borderMv[TOP] );
  487.         right = mvDiff( mvX, mvY, mb, LOWER_RIGHT_BLK, PBframe, borderMv[RIGHT] );
  488.         if (left == YES || right == YES || top == YES) {
  489.             doOverlapMC( LOWER_LEFT_BLK, mb, prevPic, pic, borderMv, left,top,right,NO);
  490.             overlap[LOWER_LEFT_BLK] = YES;
  491.         } else {
  492.             overlap[LOWER_LEFT_BLK] = NO;
  493.         }
  494.         // Lower right block
  495.         mvX = mb->blkMvX[LOWER_RIGHT_BLK];
  496.         mvY = mb->blkMvY[LOWER_RIGHT_BLK];
  497.         left = mvDiff( mvX, mvY, mb, LOWER_LEFT_BLK, PBframe, borderMv[LEFT] );
  498.         top = mvDiff( mvX, mvY, mb, UPPER_RIGHT_BLK, PBframe, borderMv[TOP] );
  499.         if (mb->x == mbWidth-1)  right = NO;
  500.         else  right = mvDiff( mvX, mvY, mb+1, LOWER_LEFT_BLK, PBframe, borderMv[RIGHT] );
  501.         if (left == YES || right == YES || top == YES) {
  502.             doOverlapMC( LOWER_RIGHT_BLK, mb, prevPic, pic, borderMv, left,top,right,NO);
  503.             overlap[LOWER_RIGHT_BLK] = YES;
  504.         } else {
  505.             overlap[LOWER_RIGHT_BLK] = NO;
  506.         }
  507.         
  508.     } else {    // One motion vector for current macroblock; neighbors can be INTER4V
  509.         mvX = mb->mv_x;
  510.         mvY = mb->mv_y;
  511.         // Upper left block
  512.         if (mb->x == 0)  left = NO;
  513.         else  left = mvDiff( mvX, mvY, mb-1, UPPER_RIGHT_BLK, PBframe, borderMv[LEFT] );
  514.         if (mb->y == 0)  top = NO;
  515.         else  top = mvDiff( mvX, mvY, mb-mbOffset, LOWER_LEFT_BLK, PBframe, borderMv[TOP] );
  516.         if (left == YES || top == YES) {
  517.             doOverlapMC( UPPER_LEFT_BLK, mb, prevPic, pic, borderMv, left,top,NO,NO);
  518.             overlap[UPPER_LEFT_BLK] = YES;
  519.         } else {
  520.             overlap[UPPER_LEFT_BLK] = NO;
  521.         }
  522.         // Upper right block
  523.         if (mb->y == 0)  top = NO;
  524.         else  top = mvDiff( mvX, mvY, mb-mbOffset, LOWER_RIGHT_BLK, PBframe, borderMv[TOP] );
  525.         if (mb->x == mbWidth-1)  right = NO;
  526.         else  right = mvDiff( mvX, mvY, mb+1, UPPER_LEFT_BLK, PBframe, borderMv[RIGHT] );
  527.         if (right == YES || top == YES) {
  528.             doOverlapMC( UPPER_RIGHT_BLK, mb, prevPic, pic, borderMv, NO,top,right,NO);
  529.             overlap[UPPER_RIGHT_BLK] = YES;
  530.         } else {
  531.             overlap[UPPER_RIGHT_BLK] = NO;
  532.         }
  533.         // Lower left block
  534.         if (mb->x == 0)  left = NO;
  535.         else  left = mvDiff( mvX, mvY, mb-1, LOWER_RIGHT_BLK, PBframe, borderMv[LEFT] );
  536.         if (left == YES) {
  537.             doOverlapMC( LOWER_LEFT_BLK, mb, prevPic, pic, borderMv, left,NO,NO,NO);
  538.             overlap[LOWER_LEFT_BLK] = YES;
  539.         } else {
  540.             overlap[LOWER_LEFT_BLK] = NO;
  541.         }
  542.         // Lower right block
  543.         if (mb->x == mbWidth-1)  right = NO;
  544.         else  right = mvDiff( mvX, mvY, mb+1, LOWER_LEFT_BLK, PBframe, borderMv[RIGHT] );
  545.         if (right == YES) {
  546.             doOverlapMC( LOWER_RIGHT_BLK, mb, prevPic, pic, borderMv, NO,NO,right,NO);
  547.             overlap[LOWER_RIGHT_BLK] = YES;
  548.         } else {
  549.             overlap[LOWER_RIGHT_BLK] = NO;
  550.         }
  551.     }
  552.     return;
  553. }
  554. // PointingOutside - determine whether motion-comp routine needs to worry about 
  555. //  the borders of the previous picture (use edge pixels instead of non-existent
  556. //  pixels "outside" the border of the previous picture).
  557. //  Returns YES if the motion-compensated block needs pixels outside the previous
  558. //  picture; NO if picture boundary is not crossed.
  559. extern int PointingOutside( int col1, int col2, // First and last column of block
  560.                             int row1, int row2, // First and last row of block
  561.                             int mvX, int mvY,   // Motion vector; one fractional bit
  562.                             int nCols, int nRows    // Picture size
  563.                             )
  564. {
  565.     if (col1 + (mvX >> 1)  <  0)            // Check left border
  566.         return( YES );
  567.     if (col2 + ((mvX + 1) >> 1)  >=  nCols) // Check right border
  568.         return( YES );
  569.     if (row1 + (mvY >> 1)  <  0)            // Check top border
  570.         return( YES );
  571.     if (row2 + ((mvY + 1) >> 1)  >=  nRows) // Check bottom border
  572.         return( YES );
  573.     return( NO );
  574. }
  575. //  PredBframe - Form prediction for B-frame
  576. extern void PredBframe( MACROBLOCK_DESCR * mb,  // Macroblock to be predicted
  577.                         PICTURE * prevPic,      // Prev. picture (forward pred)
  578.                         PICTURE * nextPic,      // Next P-picture (backward pred)
  579.                         PICTURE * Bpic          // Output picture where pred is placed
  580.                         )
  581. {
  582.     int     i;
  583.     S8      saveMvX[4], saveMvY[4];
  584.     // Perform backward prediction
  585.     if (mb->mtype == MTYPE263_INTER4V) {
  586.         for (i = 0; i < 4; ++i) {
  587.             saveMvX[i] = mb->blkMvX[i];
  588.             mb->blkMvX[i] = mb->blkMvBx[i];
  589.             saveMvY[i] = mb->blkMvY[i];
  590.             mb->blkMvY[i] = mb->blkMvBy[i];
  591.         }
  592.     } else {
  593.         saveMvX[0] = mb->mv_x;
  594.         mb->mv_x = mb->blkMvBx[0];
  595.         saveMvY[0] = mb->mv_y;
  596.         mb->mv_y = mb->blkMvBy[0];
  597.     }
  598.     MotionComp263( mb, nextPic, Bpic );
  599.     // Save backward prediction in temporary area
  600.     saveBackwardPred( mb, Bpic );
  601.     // Perform forward prediction
  602.     if (mb->mtype == MTYPE263_INTER4V) {
  603.         for (i = 0; i < 4; ++i) {
  604.             mb->blkMvX[i] = mb->blkMvFx[i];
  605.             mb->blkMvY[i] = mb->blkMvFy[i];
  606.         }
  607.     } else {
  608.         mb->mv_x = mb->blkMvFx[0];
  609.         mb->mv_y = mb->blkMvFy[0];
  610.     }
  611.     MotionComp263( mb, prevPic, Bpic );
  612.     // Restore parameters
  613.     if (mb->mtype == MTYPE263_INTER4V) {
  614.         for (i = 0; i < 4; ++i) {
  615.             mb->blkMvX[i] = saveMvX[i];
  616.             mb->blkMvY[i] = saveMvY[i];
  617.         }
  618.     } else {
  619.         mb->mv_x = saveMvX[0];
  620.         mb->mv_y = saveMvY[0];
  621.     }
  622.     // Average forward and backward prediction
  623.     averageForBack( mb, Bpic );
  624. }
  625. //  PredBdist - Form prediction for subsampled error computation
  626. extern void PredBdist( MACROBLOCK_DESCR * mb,  // Macroblock to be predicted
  627.                         PICTURE * prevPic,      // Prev. picture (forward pred)
  628.                         PICTURE * nextPic,      // Next P-picture (backward pred)
  629.                         PICTURE * Bpic          // Output picture where pred is placed
  630.                         )
  631. {
  632.     int     i;
  633.     S8      saveMvX[4], saveMvY[4];
  634.     // Perform backward prediction
  635.     if (mb->mtype == MTYPE263_INTER4V) {
  636.         for (i = 0; i < 4; ++i) {
  637.             saveMvX[i] = mb->blkMvX[i];
  638.             mb->blkMvX[i] = mb->blkMvBx[i];
  639.             saveMvY[i] = mb->blkMvY[i];
  640.             mb->blkMvY[i] = mb->blkMvBy[i];
  641.         }
  642.     } else {
  643.         saveMvX[0] = mb->mv_x;
  644.         mb->mv_x = mb->blkMvBx[0];
  645.         saveMvY[0] = mb->mv_y;
  646.         mb->mv_y = mb->blkMvBy[0];
  647.     }
  648.     MotionComp263( mb, nextPic, Bpic );
  649.     // Save backward prediction in temporary area
  650.     saveBackwardPred( mb, Bpic );
  651.     // Perform forward prediction
  652.     if (mb->mtype == MTYPE263_INTER4V) {
  653.         for (i = 0; i < 4; ++i) {
  654.             mb->blkMvX[i] = mb->blkMvFx[i];
  655.             mb->blkMvY[i] = mb->blkMvFy[i];
  656.         }
  657.     } else {
  658.         mb->mv_x = mb->blkMvFx[0];
  659.         mb->mv_y = mb->blkMvFy[0];
  660.     }
  661.     MotionComp263( mb, prevPic, Bpic );
  662.     // Restore parameters
  663.     if (mb->mtype == MTYPE263_INTER4V) {
  664.         for (i = 0; i < 4; ++i) {
  665.             mb->blkMvX[i] = saveMvX[i];
  666.             mb->blkMvY[i] = saveMvY[i];
  667.         }
  668.     } else {
  669.         mb->mv_x = saveMvX[0];
  670.         mb->mv_y = saveMvY[0];
  671.     }
  672.     // Average forward and backward prediction
  673.     averageForBack( mb, Bpic );
  674. }
  675. // chromaMVComp - derive motion component for chroma from luma motion component
  676. static int chromaMVComp( int mvLuma )
  677. {
  678.     int mvChroma, fraction;
  679.     
  680.     mvChroma = 2 * (mvLuma >> 2);    // Truncate fractional part
  681.     fraction = mvLuma & 0x3;    // Two fractional bits
  682.     if (fraction != 0) {
  683.         ++mvChroma;     // Round towards half-pixel
  684.     }
  685.     return( mvChroma );
  686. }
  687. // chromaMvComp4V - derive motion component for chroma from 4 luma motion components
  688. static int chromaMvComp4V( S8 mvLuma[4] )
  689. {
  690.     int sum, mvChroma, fraction;
  691.     
  692.     sum = mvLuma[0] + mvLuma[1] + mvLuma[2] + mvLuma[3];
  693.     mvChroma = 2 * (sum >> 4);  // Truncate fractional part
  694.     fraction = sum & 0xf;       // Four fractional bits
  695.     if (fraction >= 14) {
  696.         mvChroma += 2;  // Round up to next integer value
  697.     } else if (fraction >= 3) {
  698.         ++mvChroma;     // Round towards half-pixel
  699.     } // else round down to integer pixel
  700.     return( mvChroma );
  701. }
  702. // mc - Perform motion compensation for a hSize x vSize block
  703. void mc( int hSize, int vSize, 
  704.                     PIXEL *in, PIXEL *out, int hdim,
  705.                     int mvX, int mvY    // Motion vector
  706.                     )
  707. {
  708.     int intX, intY, fracX, fracY;
  709.     
  710. #ifdef VVPROFILER
  711. S32 nVvProfNb = 2;
  712. if(!pVvProf[nVvProfNb]) pVvProf[nVvProfNb] = newCVvDebugTimer();//memory leak on destruction
  713. pVvProfCount[nVvProfNb]++;
  714. StartTime(pVvProf[nVvProfNb]);
  715. #endif
  716.     intX = mvX >> 1;    // Integer part of motion vector
  717.     intY = mvY >> 1;
  718.     fracX = mvX & 0x1;  // Fractional part of motion vector
  719.     fracY = mvY & 0x1;
  720.     in += intX + intY * hdim;
  721.     if (hSize != 16  &&  hSize != 8  &&  hSize != 4) {
  722.         H261ErrMsg("mc -- hSize not supported");
  723.         exit(0);
  724.     }
  725.     if (fracY == 0) {
  726.         if (fracX == 0) {
  727.             // No interpolation
  728.             if (hSize == 8) {
  729.                 mc8pelsNoInterpol( in, out, hdim, vSize );
  730.             } else if (hSize == 16) {
  731.                 mc16pelsNoInterpol( in, out, hdim, vSize );
  732.             } else {
  733.                 mc4pelsNoInterpol( in, out, hdim, vSize );
  734.             }
  735.         } else {
  736.             // Horizontal interpolation
  737.             if (hSize == 8) {
  738.                 mc8pelsHorInterpol( in, out, hdim, vSize );
  739.             } else if (hSize == 16) {
  740.                 mc16pelsHorInterpol( in, out, hdim, vSize );
  741.             } else {
  742.                 mc4pelsHorInterpol( in, out, hdim, vSize );
  743.             }
  744.         }
  745.     } else if (fracX == 0) {
  746.         // Vertical interpolation
  747.         if (hSize == 8) {
  748.             mc8pelsVertInterpol( in, out, hdim, vSize );
  749.         } else if (hSize == 16) {
  750.             mc16pelsVertInterpol( in, out, hdim, vSize );
  751.         } else {
  752.             mc4pelsVertInterpol( in, out, hdim, vSize );
  753.         }
  754.     } else {    // Bilinear interpolation
  755.         if (hSize == 8) {
  756.             mc8pels2DInterpol( in, out, hdim, vSize );
  757.         } else if (hSize == 16) {
  758.             mc16pels2DInterpol( in, out, hdim, vSize );
  759.         } else {
  760.             mc4pels2DInterpol( in, out, hdim, vSize );
  761.         }
  762.     }
  763. #ifdef VVPROFILER
  764. StopAndAccuTime(pVvProf[nVvProfNb]);
  765. #endif
  766.     return;
  767. }
  768. // Limit x to interval [low,high]
  769. #define LIMIT( low, x, high )    max( low, min( x, high ))
  770. // limitMC - Perform motion compensation; use edge pixels when referring to
  771. //  pixels outside picture
  772. static void limitMC( int hSize, int vSize, 
  773.                     PIXEL const *in, PIXEL *out, int hdim,
  774.                     int mvX, int mvY,   // Motion vector
  775.                     int minX, int maxX, int minY, int maxY // Limits for hor/vert indices
  776.                     )
  777. {
  778. #define MAX_HSIZE   (16)
  779.     int intX, intY, fracX, fracY, outsideTop, outsideBot, repeatTop, repeatBot, x, y;
  780.     static int  mapX[MAX_HSIZE + 1];
  781.     PIXEL *outSave, *outBegin;
  782.     union { // Copy words to speed up routine
  783.         PIXEL   *pix;
  784.         U32     *word;
  785.     } pIn, pOut;
  786.     
  787.     if (hSize & 0x3) {
  788.         H261ErrMsg("limitMC -- hSize must be multiple of 4");
  789.         exit(0);
  790.     }
  791.     if (hSize > MAX_HSIZE) {
  792.         H261ErrMsg("limitMC -- hSize too large");
  793.         exit(0);
  794.     }
  795.     intX = mvX >> 1;    // Integer part of motion vector
  796.     intY = mvY >> 1;
  797.     fracX = mvX & 0x1;  // Fractional part of motion vector
  798.     fracY = mvY & 0x1;
  799.     // Create horizontal mapping vector
  800.     for (x = 0; x <= hSize; ++x) {
  801.         mapX[x] = LIMIT( minX, x + intX, maxX );
  802.     }
  803.     //repeatTop = max( 0, minY - intY);                     // Lines on top that are outside
  804.     //repeatBot = max( 0, vSize - 1 + intY + fracY - maxY); // Lines at bottom that are outside
  805.     outsideTop = max( 0, minY - intY); // Lines on top that are outside
  806.     outsideBot = max( 0, vSize - 1 + intY + fracY - maxY);  // Lines at bottom that are outside
  807. // Don't produce more lines than the blocksize (used to be a nasty bug hidden here)
  808. repeatTop = min( outsideTop, vSize );
  809.     if (outsideBot < vSize) {
  810.         repeatBot = outsideBot;
  811.         in += (intY + outsideTop) * hdim; // Apply vert motion comp. (hor MC thru mapping)
  812.     } else {    // Whole block is "outside" bottom of picture
  813.         repeatBot = vSize;
  814.         in += (vSize - 1) * hdim;   // Point to last line of picture
  815.     }
  816. // Output pointers
  817.     outSave = out; // Upper left corner of output block
  818.     out += repeatTop * hdim; // "Repeated" lines will be filled in later
  819.     outBegin = out; // Save address for first valid output line
  820.     if (fracY == 0) {
  821. // Ensure that at least one output line gets written
  822. if (repeatTop == vSize) {
  823. --repeatTop;
  824. out -= hdim;
  825. outBegin = out;
  826. } else if (repeatBot == vSize) {
  827. --repeatBot;
  828. }
  829.         if (fracX == 0) {
  830.             // No interpolation
  831.             for (y = repeatTop; y < vSize - repeatBot; ++y) {
  832.                 for (x = 0; x < hSize; x += 4) {
  833.                     out[x+0] = in[ mapX[x+0] ];
  834.                     out[x+1] = in[ mapX[x+1] ];
  835.                     out[x+2] = in[ mapX[x+2] ];
  836.                     out[x+3] = in[ mapX[x+3] ];
  837.                 }
  838.                 in += hdim;
  839.                 out += hdim;
  840.             }
  841.         } else {
  842.             // Horizontal interpolation
  843.             for (y = repeatTop; y < vSize - repeatBot; ++y) {
  844.                 for (x = 0; x < hSize; x += 4) {
  845.                     out[x+0] = (in[mapX[x+0]] + in[mapX[x+1]] + 1) >> 1;
  846.                     out[x+1] = (in[mapX[x+1]] + in[mapX[x+2]] + 1) >> 1;
  847.                     out[x+2] = (in[mapX[x+2]] + in[mapX[x+3]] + 1) >> 1;
  848.                     out[x+3] = (in[mapX[x+3]] + in[mapX[x+4]] + 1) >> 1;
  849.                 }
  850.                 in += hdim;
  851.                 out += hdim;
  852.             }
  853.         }
  854.     } else if (fracX == 0) {
  855.         // Vertical interpolation
  856.         if (repeatTop > 0) {    // Produce line to repeat
  857.             outBegin = out - hdim;
  858.             for (x = 0; x < hSize; ++x) {
  859.                 outBegin[x] = in[ mapX[x] ];
  860.             }
  861.         }
  862.         for (y = repeatTop; y < vSize - repeatBot; ++y) {
  863.             for (x = 0; x < hSize; x += 4) {
  864.                 out[x+0] = (in[mapX[x+0]] + in[mapX[x+0] + hdim] + 1) >> 1;
  865.                 out[x+1] = (in[mapX[x+1]] + in[mapX[x+1] + hdim] + 1) >> 1;
  866.                 out[x+2] = (in[mapX[x+2]] + in[mapX[x+2] + hdim] + 1) >> 1;
  867.                 out[x+3] = (in[mapX[x+3]] + in[mapX[x+3] + hdim] + 1) >> 1;
  868.             }
  869.             in += hdim;
  870.             out += hdim;
  871.         }
  872.         if (repeatBot > 0) {    // Produce line to repeat
  873.             for (x = 0; x < hSize; ++x) {
  874.                 out[x] = in[ mapX[x] ];
  875.             }
  876.             out += hdim;
  877.         }
  878.     } else {    // Bilinear interpolation
  879.         if (repeatTop > 0) {    // Produce line to repeat
  880.             outBegin = out - hdim;
  881.             for (x = 0; x < hSize; ++x) {
  882.                 outBegin[x] = (in[mapX[x]] + in[mapX[x+1]] + 1) >> 1;
  883.             }
  884.         }
  885.         for (y = repeatTop; y < vSize - repeatBot; ++y) {
  886.             for (x = 0; x < hSize; x += 4) {
  887.                     out[x+0] = (in[mapX[x+0]] + in[mapX[x+0] + hdim]
  888.                                 + in[mapX[x+1]] + in[mapX[x+1] + hdim] + 2) >> 2;
  889.                     out[x+1] = (in[mapX[x+1]] + in[mapX[x+1] + hdim]
  890.                                 + in[mapX[x+2]] + in[mapX[x+2] + hdim] + 2) >> 2;
  891.                     out[x+2] = (in[mapX[x+2]] + in[mapX[x+2] + hdim]
  892.                                 + in[mapX[x+3]] + in[mapX[x+3] + hdim] + 2) >> 2;
  893.                     out[x+3] = (in[mapX[x+3]] + in[mapX[x+3] + hdim]
  894.                                 + in[mapX[x+4]] + in[mapX[x+4] + hdim] + 2) >> 2;
  895.             }
  896.             in += hdim;
  897.             out += hdim;
  898.         }
  899.         if (repeatBot > 0) {    // Produce line to repeat
  900.             for (x = 0; x < hSize; ++x) {
  901.                 out[x] = (in[mapX[x]] + in[mapX[x+1]] + 1) >> 1;
  902.             }
  903.             out += hdim;
  904.         }
  905.     }
  906.     if (fracY == 1) {
  907.         --repeatTop;    // Already did one line
  908.         --repeatBot;
  909.     }
  910.     // Repeat first line at top
  911.     pIn.pix = outBegin;
  912.     pOut.pix = outSave;
  913.     for (y = 0; y < repeatTop; ++y) {
  914.         for (x = 0; x < (hSize >> 2); ++x) {
  915.             *(pOut.word + x) = *(pIn.word + x);
  916.         }
  917.         pOut.pix += hdim;
  918.     }
  919.     // Repeat last line at the bottom
  920.     pIn.pix = out - hdim;
  921.     pOut.pix = out;
  922.     for (y = 0; y < repeatBot; ++y) {
  923.         for (x = 0; x < (hSize >> 2); ++x) {
  924.             *(pOut.word + x) = *(pIn.word + x);
  925.         }
  926.         pOut.pix += hdim;
  927.     }
  928.     return;
  929. }
  930. // mvDiff - Return YES if motion vector for adjacent block is different, otherwise NO
  931. //  Return NO if adjacent block is INTRA (unless PBframe)
  932. static int mvDiff( int mvX, int mvY,    // motion vector
  933.                 MACROBLOCK_DESCR const *borderMB,   // adjacent macroblock
  934.                 int subBlk, // adjacent subblock (needed if borderMB has 4 motion vectors)
  935.                 int PBframe,    // If PBframe: do overlap also with INTRA neighbor
  936.                 int border[2]   // return motion vector components for adjacent block
  937.                 )
  938. {
  939.     if (borderMB->mtype == MTYPE263_INTER4V) {
  940.         border[0] = borderMB->blkMvX[ subBlk ];
  941.         border[1] = borderMB->blkMvY[ subBlk ];
  942.     } else {
  943.         border[0] = borderMB->mv_x;
  944.         border[1] = borderMB->mv_y;
  945.         if (borderMB->mtype >= MTYPE263_INTRA  &&  PBframe == 0) {
  946.             return( NO );   // No overlap with INTRA neighbor (except in PBframe)
  947.         }
  948.     }
  949.     if (border[0] != mvX  ||  border[1] != mvY) {
  950.         return( YES );
  951.     }
  952.     return( NO );
  953. }
  954. // median3 - return median of 3 values
  955. static int  median3( int x[3] )
  956. {
  957.     int order[2];
  958.     
  959.     if (x[1] < x[0]) {
  960.         order[0] = x[1];
  961.         order[1] = x[0];
  962.     } else {
  963.         order[0] = x[0];
  964.         order[1] = x[1];
  965.     }
  966.     if (x[2] < order[0]) {
  967.         return( order[0] );
  968.     } else if (x[2] < order[1]) {
  969.         return( x[2] );
  970.     }
  971.     return( order[1] );
  972. }
  973. // MvPred - Compute mv predictor (mvX,mvY) for block "blk" of macroblock mb[0].
  974. //  blk = UPPER_LEFT_BLK, UPPER_RIGHT_BLK, LOWER_LEFT_BLK, LOWER_RIGHT_BLK,
  975. //          or WHOLE_MACROBLOCK.
  976. //  If horPredOnly=YES: don't use previous row of macroblocks in prediction
  977. extern void MvPred( MACROBLOCK_DESCR mb[],
  978.                     int blk,        // specify block: UL, UR, LL, LR, or WHOLE 
  979.                     int mbhor,      // offset from previous row of MBs
  980.                     int horPredOnly, 
  981.                     int *mvX, int *mvY )
  982. {
  983.     int x[3], y[3];
  984.     
  985.     switch (blk) {
  986.     case UPPER_RIGHT_BLK:
  987.         x[0] = mb[0].blkMvX[UPPER_LEFT_BLK];
  988.         y[0] = mb[0].blkMvY[UPPER_LEFT_BLK];
  989.         if (horPredOnly == YES) {   // Top border or sending GOB header to resync
  990.             *mvX = x[0], *mvY = y[0];
  991.         } else {
  992.             if (mb[-mbhor].mtype == MTYPE263_INTER4V) {
  993.                 x[1] = mb[-mbhor].blkMvX[LOWER_RIGHT_BLK];
  994.                 y[1] = mb[-mbhor].blkMvY[LOWER_RIGHT_BLK];
  995.             } else {
  996.                 x[1] = mb[-mbhor].mv_x;
  997.                 y[1] = mb[-mbhor].mv_y;
  998.             }
  999.             if (mb[0].x == mbhor - 1) { // Right border
  1000.                 x[2] = 0, y[2] = 0;
  1001.             } else if (mb[1-mbhor].mtype == MTYPE263_INTER4V) {
  1002.                 x[2] = mb[1-mbhor].blkMvX[LOWER_LEFT_BLK];
  1003.                 y[2] = mb[1-mbhor].blkMvY[LOWER_LEFT_BLK];
  1004.             } else {
  1005.                 x[2] = mb[1-mbhor].mv_x;
  1006.                 y[2] = mb[1-mbhor].mv_y;
  1007.             }
  1008.             *mvX = median3( x );
  1009.             *mvY = median3( y );
  1010.         }
  1011.         break;
  1012.         
  1013.     case LOWER_LEFT_BLK:
  1014.         if (mb[0].x == 0) {     // Left border
  1015.             x[0] = 0, y[0] = 0;
  1016.         } else if (mb[-1].mtype == MTYPE263_INTER4V) {
  1017.             x[0] = mb[-1].blkMvX[LOWER_RIGHT_BLK];
  1018.             y[0] = mb[-1].blkMvY[LOWER_RIGHT_BLK];
  1019.         } else {
  1020.             x[0] = mb[-1].mv_x;
  1021.             y[0] = mb[-1].mv_y;
  1022.         }
  1023.         x[1] = mb[0].blkMvX[UPPER_LEFT_BLK];
  1024.         y[1] = mb[0].blkMvY[UPPER_LEFT_BLK];
  1025.         x[2] = mb[0].blkMvX[UPPER_RIGHT_BLK];
  1026.         y[2] = mb[0].blkMvY[UPPER_RIGHT_BLK];
  1027.         *mvX = median3( x );
  1028.         *mvY = median3( y );
  1029.         break;
  1030.         
  1031.     case LOWER_RIGHT_BLK:
  1032.         x[0] = mb[0].blkMvX[LOWER_LEFT_BLK];
  1033.         y[0] = mb[0].blkMvY[LOWER_LEFT_BLK];
  1034.         x[1] = mb[0].blkMvX[UPPER_LEFT_BLK];
  1035.         y[1] = mb[0].blkMvY[UPPER_LEFT_BLK];
  1036.         x[2] = mb[0].blkMvX[UPPER_RIGHT_BLK];
  1037.         y[2] = mb[0].blkMvY[UPPER_RIGHT_BLK];
  1038.         *mvX = median3( x );
  1039.         *mvY = median3( y );
  1040.         break;
  1041.         
  1042.     case WHOLE_MACROBLOCK:
  1043.     case UPPER_LEFT_BLK:
  1044.     default:
  1045.         if (mb[0].x == 0) {     // Left border
  1046.             x[0] = 0, y[0] = 0;
  1047.         } else if (mb[-1].mtype == MTYPE263_INTER4V) {
  1048.             x[0] = mb[-1].blkMvX[UPPER_RIGHT_BLK];
  1049.             y[0] = mb[-1].blkMvY[UPPER_RIGHT_BLK];
  1050.         } else {
  1051.             x[0] = mb[-1].mv_x;
  1052.             y[0] = mb[-1].mv_y;
  1053.         }
  1054.         if (horPredOnly == YES) {   // Top border or sending GOB header to resync
  1055.             *mvX = x[0], *mvY = y[0];
  1056.         } else {
  1057.             if (mb[-mbhor].mtype == MTYPE263_INTER4V) {
  1058.                 x[1] = mb[-mbhor].blkMvX[LOWER_LEFT_BLK];
  1059.                 y[1] = mb[-mbhor].blkMvY[LOWER_LEFT_BLK];
  1060.             } else {
  1061.                 x[1] = mb[-mbhor].mv_x;
  1062.                 y[1] = mb[-mbhor].mv_y;
  1063.             }
  1064.             if (mb[0].x == mbhor - 1) { // Right border
  1065.                 x[2] = 0, y[2] = 0;
  1066.             } else if (mb[1-mbhor].mtype == MTYPE263_INTER4V) {
  1067.                 x[2] = mb[1-mbhor].blkMvX[LOWER_LEFT_BLK];
  1068.                 y[2] = mb[1-mbhor].blkMvY[LOWER_LEFT_BLK];
  1069.             } else {
  1070.                 x[2] = mb[1-mbhor].mv_x;
  1071.                 y[2] = mb[1-mbhor].mv_y;
  1072.             }
  1073.             *mvX = median3( x );
  1074.             *mvY = median3( y );
  1075.         }
  1076.         break;
  1077.     }
  1078.     return;
  1079. }
  1080. // doOverlapMC - Perform overlapped motion compensation on 8x8 block
  1081. static void doOverlapMC( int subBlk,    // Indicates subblock to process (UL, UR, LL, LR)
  1082.                     MACROBLOCK_DESCR *mb,   // Used to determine (x,y) coordinates for block
  1083.                     PICTURE *prevPic,   // Previous picture; used to create overlapping MC
  1084.                     PICTURE *pic, // Contains non-overlapped MC on entry; returns overlapped MC
  1085.                     int borderMv[4][2], // Motion vectors for adjacent blocks (L,Top,R,Bottom)
  1086.                     int left,           // If YES, overlap using LEFT mv
  1087.                     int top,            // If YES, overlap using TOP mv
  1088.                     int right,          // If YES, overlap using RIGHT mv
  1089.                     int bottom          // If YES, overlap using BOTTOM mv
  1090.                     )
  1091. {
  1092. #define LEFT_ADDR           (0)
  1093. #define RIGHT_ADDR          (LEFT_ADDR + 4)
  1094. #define TOP_OFFSET          (8)
  1095. #define TOP_ADDR            (LEFT_ADDR + TOP_OFFSET)
  1096. #define MAX_HDIM            (352)
  1097.     static PIXEL    p[8 * MAX_HDIM];    // MC predictions using neighboring vectors
  1098.         // Only using first 16 columns; line offset chosen to be same as for pictures
  1099.     int     row, col, picOffset, hdim, nhor, nvert, *mv;
  1100.     PIXEL   * source, * dest;
  1101. void (*pMC) ( int hSize, int vSize, PIXEL *in, PIXEL *out, int hdim, int mvX, int mvY);
  1102. #if defined(COMPILE_MMX)
  1103. if(cpuid_is_mmx_motion_on()) {
  1104. //do mmx if compiler switch AND initialized AND detected
  1105. pMC = mcMMX;
  1106. } else 
  1107. #endif
  1108. {
  1109. pMC = mc;
  1110. }
  1111.     // Compute luma pointers
  1112.     col = 16 * mb->x;
  1113.     row = 16 * mb->y;
  1114.     if (subBlk == UPPER_RIGHT_BLK  ||  subBlk == LOWER_RIGHT_BLK)  col += 8;
  1115.     if (subBlk == LOWER_LEFT_BLK  ||  subBlk == LOWER_RIGHT_BLK)  row += 8;
  1116.     hdim = pic->y.hoffset;
  1117.     nhor = pic->y.nhor, nvert = pic->y.nvert;
  1118.     picOffset = col + row * hdim;
  1119.     dest = pic->y.ptr + picOffset;          // Point to output luma (non-overlapped MC)
  1120.     source = prevPic->y.ptr + picOffset;    // Point to input luma (without motion comp)
  1121.     if (hdim > MAX_HDIM) {
  1122.         H261ErrMsg("doOverlapMC - Increase size of internal array");
  1123.         exit(0);
  1124.     }
  1125.     // Create motion compensated blocks using neighboring motion vectors
  1126.     if (left == YES) {  // Produce left 4 columns
  1127.         mv = borderMv[LEFT];
  1128.         if (PointingOutside( col, col+3, row, row+7, *mv, *(mv+1), nhor, nvert)  ==  NO) {
  1129.             pMC( 4,8, source, &p[LEFT_ADDR], hdim, *mv, *(mv+1) );
  1130.         } else {
  1131.             limitMC( 4,8, source, &p[LEFT_ADDR], hdim, *mv, *(mv+1),
  1132.                     -col, nhor - 1 - col, -row, nvert - 1 - row );
  1133.         }
  1134.     }
  1135.     if (right == YES) { // Produce right 4 columns
  1136.         mv = borderMv[RIGHT];
  1137.         if (PointingOutside( col+4, col+7, row, row+7, *mv, *(mv+1), nhor, nvert)  ==  NO) {
  1138.             pMC( 4,8, source + 4, &p[RIGHT_ADDR], hdim, *mv, *(mv+1) );
  1139.         } else {
  1140.             limitMC( 4,8, source + 4, &p[RIGHT_ADDR], hdim, *mv, *(mv+1),
  1141.                     -col - 4, nhor - 1 - col - 4, -row, nvert - 1 - row );
  1142.         }
  1143.     }
  1144.     if (top == YES) {   // Produce top 4 rows
  1145.         mv = borderMv[TOP];
  1146.         if (PointingOutside( col, col+7, row, row+3, *mv, *(mv+1), nhor, nvert)  ==  NO) {
  1147.             pMC( 8,4, source, &p[TOP_ADDR], hdim, *mv, *(mv+1) );
  1148.         } else {
  1149.             limitMC( 8,4, source, &p[TOP_ADDR], hdim, *mv, *(mv+1),
  1150.                     -col, nhor - 1 - col, -row, nvert - 1 - row );
  1151.         }
  1152.     }
  1153.     if (bottom == YES) {    // Produce bottom 4 rows
  1154.         mv = borderMv[BOTTOM];
  1155.         if (PointingOutside( col, col+7, row+4, row+7, *mv, *(mv+1), nhor, nvert)  ==  NO) {
  1156.             pMC( 8,4, source + 4*hdim, &p[TOP_ADDR + 4*hdim], hdim, *mv, *(mv+1) );
  1157.         } else {
  1158.             limitMC( 8,4, source + 4*hdim, &p[TOP_ADDR + 4*hdim], hdim, *mv, *(mv+1),
  1159.                     -col, nhor - 1 - col, -row - 4, nvert - 1 - row - 4 );
  1160.         }
  1161.     }
  1162.     // Produce weighted ("overlapped") MC prediction
  1163.     weigh8x4( dest, &p[LEFT_ADDR], hdim, top, left, right );    // Top 4 rows
  1164.     weigh8x4( dest + 7*hdim, &p[LEFT_ADDR + 7*hdim], -hdim, bottom, left, right );  // Bottom 4 rows
  1165.     return;
  1166. }
  1167. // weigh8x4
  1168. static void weigh8x4( PIXEL *dest, PIXEL const *p, int hdim, int vert, int left, int right )
  1169. {
  1170.     if (vert == YES) {  // Use top/bottom MV
  1171.         if (left == YES) {
  1172.             weighLeft_Vert( dest, &p[LEFT_ADDR], hdim );
  1173.         } else {
  1174.             weighNoLeft_Vert( dest, &p[LEFT_ADDR], hdim );
  1175.         }
  1176.         if (right == YES) {
  1177.             weighRight_Vert( dest + 4, &p[RIGHT_ADDR], hdim );
  1178.         } else {
  1179.             weighNoRight_Vert( dest + 4, &p[RIGHT_ADDR], hdim );
  1180.         }
  1181.     } else {
  1182.         if (left == YES) {
  1183.             weighLeft( dest, &p[LEFT_ADDR], hdim );
  1184.         }
  1185.         if (right == YES) {
  1186.             weighRight( dest + 4, &p[RIGHT_ADDR], hdim );
  1187.         }
  1188.     }
  1189.     return;
  1190. }
  1191. // weighLeft_Vert - Overlap three MC predictions for upper left 4x4 pixels
  1192. static void weighLeft_Vert( PIXEL *dest,    // Non-overlapped MC; overlapped by this routine
  1193.                             PIXEL const *p, // p: MC using left motion vector
  1194.                                             // &p[TOP_OFFSET]: MC using top/bottom MV
  1195.                             int hdim )      // Line offset
  1196. {
  1197.     // First row
  1198.     dest[0] = (2 * dest[0] +     p[0] +     p[TOP_OFFSET + 0] + 2) >> 2;
  1199.     dest[1] = (5 * dest[1] +     p[1] + 2 * p[TOP_OFFSET + 1] + 4) >> 3;
  1200.     dest[2] = (5 * dest[2] +     p[2] + 2 * p[TOP_OFFSET + 2] + 4) >> 3;
  1201.     dest[3] = (5 * dest[3] +     p[3] + 2 * p[TOP_OFFSET + 3] + 4) >> 3;
  1202.     // Second row
  1203.     dest += hdim, p += hdim;
  1204.     dest[0] = (5 * dest[0] + 2 * p[0] +     p[TOP_OFFSET + 0] + 4) >> 3;
  1205.     dest[1] = (5 * dest[1] + 2 * p[1] +     p[TOP_OFFSET + 1] + 4) >> 3;
  1206.     dest[2] = (5 * dest[2] +     p[2] + 2 * p[TOP_OFFSET + 2] + 4) >> 3;
  1207.     dest[3] = (5 * dest[3] +     p[3] + 2 * p[TOP_OFFSET + 3] + 4) >> 3;
  1208.     // Third row
  1209.     dest += hdim, p += hdim;
  1210.     dest[0] = (5 * dest[0] + 2 * p[0] +     p[TOP_OFFSET + 0] + 4) >> 3;
  1211.     dest[1] = (5 * dest[1] + 2 * p[1] +     p[TOP_OFFSET + 1] + 4) >> 3;
  1212.     dest[2] = (6 * dest[2] +     p[2] +     p[TOP_OFFSET + 2] + 4) >> 3;
  1213.     dest[3] = (6 * dest[3] +     p[3] +     p[TOP_OFFSET + 3] + 4) >> 3;
  1214.     // Fourth row (identical to third row)
  1215.     dest += hdim, p += hdim;
  1216.     dest[0] = (5 * dest[0] + 2 * p[0] +     p[TOP_OFFSET + 0] + 4) >> 3;
  1217.     dest[1] = (5 * dest[1] + 2 * p[1] +     p[TOP_OFFSET + 1] + 4) >> 3;
  1218.     dest[2] = (6 * dest[2] +     p[2] +     p[TOP_OFFSET + 2] + 4) >> 3;
  1219.     dest[3] = (6 * dest[3] +     p[3] +     p[TOP_OFFSET + 3] + 4) >> 3;
  1220.     return;
  1221. }
  1222. // weighNoLeft_Vert - Overlap with MV from vert. neighbor for upper left 4x4 pixels
  1223. static void weighNoLeft_Vert( PIXEL *dest, PIXEL const *p, int hdim )
  1224. {
  1225.     // First row
  1226.     dest[0] = (3 * dest[0] +  p[TOP_OFFSET + 0] + 2) >> 2;
  1227.     dest[1] = (3 * dest[1] +  p[TOP_OFFSET + 1] + 2) >> 2;
  1228.     dest[2] = (3 * dest[2] +  p[TOP_OFFSET + 2] + 2) >> 2;
  1229.     dest[3] = (3 * dest[3] +  p[TOP_OFFSET + 3] + 2) >> 2;
  1230.     // Second row
  1231.     dest += hdim, p += hdim;
  1232.     dest[0] = (7 * dest[0] +  p[TOP_OFFSET + 0] + 4) >> 3;
  1233.     dest[1] = (7 * dest[1] +  p[TOP_OFFSET + 1] + 4) >> 3;
  1234.     dest[2] = (3 * dest[2] +  p[TOP_OFFSET + 2] + 2) >> 2;
  1235.     dest[3] = (3 * dest[3] +  p[TOP_OFFSET + 3] + 2) >> 2;
  1236.     // Third row
  1237.     dest += hdim, p += hdim;
  1238.     dest[0] = (7 * dest[0] +  p[TOP_OFFSET + 0] + 4) >> 3;
  1239.     dest[1] = (7 * dest[1] +  p[TOP_OFFSET + 1] + 4) >> 3;
  1240.     dest[2] = (7 * dest[2] +  p[TOP_OFFSET + 2] + 4) >> 3;
  1241.     dest[3] = (7 * dest[3] +  p[TOP_OFFSET + 3] + 4) >> 3;
  1242.     // Fourth row (identical to third row)
  1243.     dest += hdim, p += hdim;
  1244.     dest[0] = (7 * dest[0] +  p[TOP_OFFSET + 0] + 4) >> 3;
  1245.     dest[1] = (7 * dest[1] +  p[TOP_OFFSET + 1] + 4) >> 3;
  1246.     dest[2] = (7 * dest[2] +  p[TOP_OFFSET + 2] + 4) >> 3;
  1247.     dest[3] = (7 * dest[3] +  p[TOP_OFFSET + 3] + 4) >> 3;
  1248.     return;
  1249. }
  1250. // weighLeft - Overlap with MV from left neighbor for upper left 4x4 pixels
  1251. static void weighLeft( PIXEL *dest, PIXEL const *p, int hdim )
  1252. {
  1253.     // First row
  1254.     dest[0] = (3 * dest[0] +  p[0] + 2) >> 2;
  1255.     dest[1] = (7 * dest[1] +  p[1] + 4) >> 3;
  1256.     dest[2] = (7 * dest[2] +  p[2] + 4) >> 3;
  1257.     dest[3] = (7 * dest[3] +  p[3] + 4) >> 3;
  1258.     // Second row
  1259.     dest += hdim, p += hdim;
  1260.     dest[0] = (3 * dest[0] +  p[0] + 2) >> 2;
  1261.     dest[1] = (3 * dest[1] +  p[1] + 2) >> 2;
  1262.     dest[2] = (7 * dest[2] +  p[2] + 4) >> 3;
  1263.     dest[3] = (7 * dest[3] +  p[3] + 4) >> 3;
  1264.     // Third row (identical to second row)
  1265.     dest += hdim, p += hdim;
  1266.     dest[0] = (3 * dest[0] +  p[0] + 2) >> 2;
  1267.     dest[1] = (3 * dest[1] +  p[1] + 2) >> 2;
  1268.     dest[2] = (7 * dest[2] +  p[2] + 4) >> 3;
  1269.     dest[3] = (7 * dest[3] +  p[3] + 4) >> 3;
  1270.     // Fourth row (identical to third row)
  1271.     dest += hdim, p += hdim;
  1272.     dest[0] = (3 * dest[0] +  p[0] + 2) >> 2;
  1273.     dest[1] = (3 * dest[1] +  p[1] + 2) >> 2;
  1274.     dest[2] = (7 * dest[2] +  p[2] + 4) >> 3;
  1275.     dest[3] = (7 * dest[3] +  p[3] + 4) >> 3;
  1276.     return;
  1277. }
  1278. // weighRight_Vert - Derived from weighLeft_Vert by reversing indices
  1279. //  This means that the assembler routine can be easily derived from the other
  1280. static void weighRight_Vert( PIXEL *dest,   // Non-overlapped MC; overlapped by this routine
  1281.                             PIXEL const *p, // p: MC using right motion vector
  1282.                                             // &p[TOP_OFFSET]: MC using top/bottom MV
  1283.                             int hdim )      // Line offset
  1284. {
  1285.     // First row
  1286.     dest[3] = (2 * dest[3] +     p[3] +     p[TOP_OFFSET + 3] + 2) >> 2;
  1287.     dest[2] = (5 * dest[2] +     p[2] + 2 * p[TOP_OFFSET + 2] + 4) >> 3;
  1288.     dest[1] = (5 * dest[1] +     p[1] + 2 * p[TOP_OFFSET + 1] + 4) >> 3;
  1289.     dest[0] = (5 * dest[0] +     p[0] + 2 * p[TOP_OFFSET + 0] + 4) >> 3;
  1290.     // Second row
  1291.     dest += hdim, p += hdim;
  1292.     dest[3] = (5 * dest[3] + 2 * p[3] +     p[TOP_OFFSET + 3] + 4) >> 3;
  1293.     dest[2] = (5 * dest[2] + 2 * p[2] +     p[TOP_OFFSET + 2] + 4) >> 3;
  1294.     dest[1] = (5 * dest[1] +     p[1] + 2 * p[TOP_OFFSET + 1] + 4) >> 3;
  1295.     dest[0] = (5 * dest[0] +     p[0] + 2 * p[TOP_OFFSET + 0] + 4) >> 3;
  1296.     // Third row
  1297.     dest += hdim, p += hdim;
  1298.     dest[3] = (5 * dest[3] + 2 * p[3] +     p[TOP_OFFSET + 3] + 4) >> 3;
  1299.     dest[2] = (5 * dest[2] + 2 * p[2] +     p[TOP_OFFSET + 2] + 4) >> 3;
  1300.     dest[1] = (6 * dest[1] +     p[1] +     p[TOP_OFFSET + 1] + 4) >> 3;
  1301.     dest[0] = (6 * dest[0] +     p[0] +     p[TOP_OFFSET + 0] + 4) >> 3;
  1302.     // Fourth row (identical to third row)
  1303.     dest += hdim, p += hdim;
  1304.     dest[3] = (5 * dest[3] + 2 * p[3] +     p[TOP_OFFSET + 3] + 4) >> 3;
  1305.     dest[2] = (5 * dest[2] + 2 * p[2] +     p[TOP_OFFSET + 2] + 4) >> 3;
  1306.     dest[1] = (6 * dest[1] +     p[1] +     p[TOP_OFFSET + 1] + 4) >> 3;
  1307.     dest[0] = (6 * dest[0] +     p[0] +     p[TOP_OFFSET + 0] + 4) >> 3;
  1308.     return;
  1309. }
  1310. // weighNoRight_Vert - Derived from weighNoLeft_Vert by reversing indices
  1311. //  This means that the assembler routine can be easily derived from the other
  1312. static void weighNoRight_Vert( PIXEL *dest, PIXEL const *p, int hdim )
  1313. {
  1314.     // First row
  1315.     dest[3] = (3 * dest[3] +  p[TOP_OFFSET + 3] + 2) >> 2;
  1316.     dest[2] = (3 * dest[2] +  p[TOP_OFFSET + 2] + 2) >> 2;
  1317.     dest[1] = (3 * dest[1] +  p[TOP_OFFSET + 1] + 2) >> 2;
  1318.     dest[0] = (3 * dest[0] +  p[TOP_OFFSET + 0] + 2) >> 2;
  1319.     // Second row
  1320.     dest += hdim, p += hdim;
  1321.     dest[3] = (7 * dest[3] +  p[TOP_OFFSET + 3] + 4) >> 3;
  1322.     dest[2] = (7 * dest[2] +  p[TOP_OFFSET + 2] + 4) >> 3;
  1323.     dest[1] = (3 * dest[1] +  p[TOP_OFFSET + 1] + 2) >> 2;
  1324.     dest[0] = (3 * dest[0] +  p[TOP_OFFSET + 0] + 2) >> 2;
  1325.     // Third row
  1326.     dest += hdim, p += hdim;
  1327.     dest[3] = (7 * dest[3] +  p[TOP_OFFSET + 3] + 4) >> 3;
  1328.     dest[2] = (7 * dest[2] +  p[TOP_OFFSET + 2] + 4) >> 3;
  1329.     dest[1] = (7 * dest[1] +  p[TOP_OFFSET + 1] + 4) >> 3;
  1330.     dest[0] = (7 * dest[0] +  p[TOP_OFFSET + 0] + 4) >> 3;
  1331.     // Fourth row (identical to third row)
  1332.     dest += hdim, p += hdim;
  1333.     dest[3] = (7 * dest[3] +  p[TOP_OFFSET + 3] + 4) >> 3;
  1334.     dest[2] = (7 * dest[2] +  p[TOP_OFFSET + 2] + 4) >> 3;
  1335.     dest[1] = (7 * dest[1] +  p[TOP_OFFSET + 1] + 4) >> 3;
  1336.     dest[0] = (7 * dest[0] +  p[TOP_OFFSET + 0] + 4) >> 3;
  1337.     return;
  1338. }
  1339. // weighRight - Derived from weighLeft by reversing indices
  1340. //  This means that the assembler routine can be easily derived from the other
  1341. static void weighRight( PIXEL *dest, PIXEL const *p, int hdim )
  1342. {
  1343.     // First row
  1344.     dest[3] = (3 * dest[3] +  p[3] + 2) >> 2;
  1345.     dest[2] = (7 * dest[2] +  p[2] + 4) >> 3;
  1346.     dest[1] = (7 * dest[1] +  p[1] + 4) >> 3;
  1347.     dest[0] = (7 * dest[0] +  p[0] + 4) >> 3;
  1348.     // Second row
  1349.     dest += hdim, p += hdim;
  1350.     dest[3] = (3 * dest[3] +  p[3] + 2) >> 2;
  1351.     dest[2] = (3 * dest[2] +  p[2] + 2) >> 2;
  1352.     dest[1] = (7 * dest[1] +  p[1] + 4) >> 3;
  1353.     dest[0] = (7 * dest[0] +  p[0] + 4) >> 3;
  1354.     // Third row (identical to second row)
  1355.     dest += hdim, p += hdim;
  1356.     dest[3] = (3 * dest[3] +  p[3] + 2) >> 2;
  1357.     dest[2] = (3 * dest[2] +  p[2] + 2) >> 2;
  1358.     dest[1] = (7 * dest[1] +  p[1] + 4) >> 3;
  1359.     dest[0] = (7 * dest[0] +  p[0] + 4) >> 3;
  1360.     // Fourth row (identical to third row)
  1361.     dest += hdim, p += hdim;
  1362.     dest[3] = (3 * dest[3] +  p[3] + 2) >> 2;
  1363.     dest[2] = (3 * dest[2] +  p[2] + 2) >> 2;
  1364.     dest[1] = (7 * dest[1] +  p[1] + 4) >> 3;
  1365.     dest[0] = (7 * dest[0] +  p[0] + 4) >> 3;
  1366.     return;
  1367. }
  1368. static void mc16pelsNoInterpol( PIXEL *in, PIXEL *out, int hdim, int vSize )
  1369. {
  1370. #ifndef FOR_UNIX
  1371.     union { // Copy words to speed up routine
  1372.         PIXEL   *pix;
  1373.         U32     *word;
  1374.     } pIn, pOut;
  1375.     pIn.pix = in;
  1376.     pOut.pix = out;
  1377.     while (vSize > 0) {
  1378.         *(pOut.word + 0) = *(pIn.word + 0);
  1379.         *(pOut.word + 1) = *(pIn.word + 1);
  1380.         *(pOut.word + 2) = *(pIn.word + 2);
  1381.         *(pOut.word + 3) = *(pIn.word + 3);
  1382.         pIn.pix += hdim;
  1383.         pOut.pix += hdim;
  1384.         --vSize;
  1385.     }
  1386.     return;
  1387. #else
  1388.     union { // PIXELs are not always word-aligned! Gotta copy bytes in UNIX
  1389.         PIXEL   *pix;
  1390.         BYTE    *byte;
  1391.     } pIn, pOut;
  1392.     BYTE    *pInbyte;
  1393.     BYTE    *pOutbyte;
  1394.     int     i;
  1395.     pIn.pix = in;
  1396.     pOut.pix = out;
  1397.     while (vSize > 0) {
  1398.         pInbyte = pIn.byte;
  1399.         pOutbyte = pOut.byte;
  1400.         for (i=0; i<16; i++)
  1401.   *(pOutbyte++) = *(pInbyte++);
  1402.         pIn.pix += hdim;
  1403.         pOut.pix += hdim;
  1404.         --vSize;
  1405.     }
  1406.     return;
  1407. #endif
  1408. }
  1409. static void mc8pelsNoInterpol( PIXEL *in, PIXEL *out, int hdim, int vSize )
  1410. {
  1411. #ifndef FOR_UNIX
  1412.     union { // Copy words to speed up routine
  1413.         PIXEL   *pix;
  1414.         U32     *word;
  1415.     } pIn, pOut;
  1416.     pIn.pix = in;
  1417.     pOut.pix = out;
  1418.     while (vSize > 0) {
  1419.         *(pOut.word + 0) = *(pIn.word + 0);
  1420.         *(pOut.word + 1) = *(pIn.word + 1);
  1421.         pIn.pix += hdim;
  1422.         pOut.pix += hdim;
  1423.         --vSize;
  1424.     }
  1425.     return;
  1426. #else
  1427.     union { // PIXELs are not always word-aligned! Gotta copy bytes in UNIX
  1428.         PIXEL   *pix;
  1429.         BYTE    *byte;
  1430.     } pIn, pOut;
  1431.     pIn.pix = in;
  1432.     pOut.pix = out;
  1433.     while (vSize > 0) {
  1434.         *(pOut.byte + 0) = *(pIn.byte + 0);
  1435.         *(pOut.byte + 1) = *(pIn.byte + 1);
  1436.         *(pOut.byte + 2) = *(pIn.byte + 2);
  1437.         *(pOut.byte + 3) = *(pIn.byte + 3);
  1438.         *(pOut.byte + 4) = *(pIn.byte + 4);
  1439.         *(pOut.byte + 5) = *(pIn.byte + 5);
  1440.         *(pOut.byte + 6) = *(pIn.byte + 6);
  1441.         *(pOut.byte + 7) = *(pIn.byte + 7);
  1442.         pIn.pix += hdim;
  1443.         pOut.pix += hdim;
  1444.         --vSize;
  1445.     }
  1446.     return;
  1447. #endif
  1448. }
  1449. static void mc4pelsNoInterpol( PIXEL *in, PIXEL *out, int hdim, int vSize )
  1450. {
  1451. #ifndef FOR_UNIX
  1452.     union { // Copy words to speed up routine
  1453.         PIXEL   *pix;
  1454.         U32     *word;
  1455.     } pIn, pOut;
  1456.     pIn.pix = in;
  1457.     pOut.pix = out;
  1458.     while (vSize > 0) {
  1459.         *(pOut.word + 0) = *(pIn.word + 0);
  1460.         pIn.pix += hdim;
  1461.         pOut.pix += hdim;
  1462.         --vSize;
  1463.     }
  1464.     return;
  1465. #else
  1466.     union { // PIXELs are not always word-aligned! Gotta copy bytes in UNIX
  1467.         PIXEL   *pix;
  1468.         BYTE    *byte;
  1469.     } pIn, pOut;
  1470.     pIn.pix = in;
  1471.     pOut.pix = out;
  1472.     while (vSize > 0) {
  1473.         *(pOut.byte + 0) = *(pIn.byte + 0);
  1474.         *(pOut.byte + 1) = *(pIn.byte + 1);
  1475.         *(pOut.byte + 2) = *(pIn.byte + 2);
  1476.         *(pOut.byte + 3) = *(pIn.byte + 3);
  1477.         pIn.pix += hdim;
  1478.         pOut.pix += hdim;
  1479.         --vSize;
  1480.     }
  1481.     return;
  1482. #endif
  1483. }
  1484. static void mc16pelsHorInterpol( PIXEL const *in, PIXEL *out, int hdim, int vSize )
  1485. {
  1486.     while (vSize > 0) {
  1487.         out[0] = (in[0] + in[1] + 1) >> 1;
  1488.         out[1] = (in[1] + in[2] + 1) >> 1;
  1489.         out[2] = (in[2] + in[3] + 1) >> 1;
  1490.         out[3] = (in[3] + in[4] + 1) >> 1;
  1491.         out[4] = (in[4] + in[5] + 1) >> 1;
  1492.         out[5] = (in[5] + in[6] + 1) >> 1;
  1493.         out[6] = (in[6] + in[7] + 1) >> 1;
  1494.         out[7] = (in[7] + in[8] + 1) >> 1;
  1495.         out[8] = (in[8] + in[9] + 1) >> 1;
  1496.         out[9] = (in[9] + in[10] + 1) >> 1;
  1497.         out[10] = (in[10] + in[11] + 1) >> 1;
  1498.         out[11] = (in[11] + in[12] + 1) >> 1;
  1499.         out[12] = (in[12] + in[13] + 1) >> 1;
  1500.         out[13] = (in[13] + in[14] + 1) >> 1;
  1501.         out[14] = (in[14] + in[15] + 1) >> 1;
  1502.         out[15] = (in[15] + in[16] + 1) >> 1;
  1503.         in += hdim;
  1504.         out += hdim;
  1505.         --vSize;
  1506.     }
  1507.     return;
  1508. }
  1509. static void mc8pelsHorInterpol( PIXEL const *in, PIXEL *out, int hdim, int vSize )
  1510. {
  1511.     while (vSize > 0) {
  1512.         out[0] = (in[0] + in[1] + 1) >> 1;
  1513.         out[1] = (in[1] + in[2] + 1) >> 1;
  1514.         out[2] = (in[2] + in[3] + 1) >> 1;
  1515.         out[3] = (in[3] + in[4] + 1) >> 1;
  1516.         out[4] = (in[4] + in[5] + 1) >> 1;
  1517.         out[5] = (in[5] + in[6] + 1) >> 1;
  1518.         out[6] = (in[6] + in[7] + 1) >> 1;
  1519.         out[7] = (in[7] + in[8] + 1) >> 1;
  1520.         in += hdim;
  1521.         out += hdim;
  1522.         --vSize;
  1523.     }
  1524.     return;
  1525. }
  1526. static void mc4pelsHorInterpol( PIXEL const *in, PIXEL *out, int hdim, int vSize )
  1527. {
  1528.     while (vSize > 0) {
  1529.         out[0] = (in[0] + in[1] + 1) >> 1;
  1530.         out[1] = (in[1] + in[2] + 1) >> 1;
  1531.         out[2] = (in[2] + in[3] + 1) >> 1;
  1532.         out[3] = (in[3] + in[4] + 1) >> 1;
  1533.         in += hdim;
  1534.         out += hdim;
  1535.         --vSize;
  1536.     }
  1537.     return;
  1538. }
  1539. static void mc16pelsVertInterpol( PIXEL const *in, PIXEL *out, int hdim, int vSize )
  1540. {
  1541.     while (vSize > 0) {
  1542.         out[0] = (in[0] + in[hdim+0] + 1) >> 1;
  1543.         out[1] = (in[1] + in[hdim+1] + 1) >> 1;
  1544.         out[2] = (in[2] + in[hdim+2] + 1) >> 1;
  1545.         out[3] = (in[3] + in[hdim+3] + 1) >> 1;
  1546.         out[4] = (in[4] + in[hdim+4] + 1) >> 1;
  1547.         out[5] = (in[5] + in[hdim+5] + 1) >> 1;
  1548.         out[6] = (in[6] + in[hdim+6] + 1) >> 1;
  1549.         out[7] = (in[7] + in[hdim+7] + 1) >> 1;
  1550.         out[8] = (in[8] + in[hdim+8] + 1) >> 1;
  1551.         out[9] = (in[9] + in[hdim+9] + 1) >> 1;
  1552.         out[10] = (in[10] + in[hdim+10] + 1) >> 1;
  1553.         out[11] = (in[11] + in[hdim+11] + 1) >> 1;
  1554.         out[12] = (in[12] + in[hdim+12] + 1) >> 1;
  1555.         out[13] = (in[13] + in[hdim+13] + 1) >> 1;
  1556.         out[14] = (in[14] + in[hdim+14] + 1) >> 1;
  1557.         out[15] = (in[15] + in[hdim+15] + 1) >> 1;
  1558.         in += hdim;
  1559.         out += hdim;
  1560.         --vSize;
  1561.     }
  1562.     return;
  1563. }
  1564. static void mc8pelsVertInterpol( PIXEL const *in, PIXEL *out, int hdim, int vSize )
  1565. {
  1566.     while (vSize > 0) {
  1567.         out[0] = (in[0] + in[hdim+0] + 1) >> 1;
  1568.         out[1] = (in[1] + in[hdim+1] + 1) >> 1;
  1569.         out[2] = (in[2] + in[hdim+2] + 1) >> 1;
  1570.         out[3] = (in[3] + in[hdim+3] + 1) >> 1;
  1571.         out[4] = (in[4] + in[hdim+4] + 1) >> 1;
  1572.         out[5] = (in[5] + in[hdim+5] + 1) >> 1;
  1573.         out[6] = (in[6] + in[hdim+6] + 1) >> 1;
  1574.         out[7] = (in[7] + in[hdim+7] + 1) >> 1;
  1575.         in += hdim;
  1576.         out += hdim;
  1577.         --vSize;
  1578.     }
  1579.     return;
  1580. }
  1581. static void mc4pelsVertInterpol( PIXEL const *in, PIXEL *out, int hdim, int vSize )
  1582. {
  1583.     while (vSize > 0) {
  1584.         out[0] = (in[0] + in[hdim+0] + 1) >> 1;
  1585.         out[1] = (in[1] + in[hdim+1] + 1) >> 1;
  1586.         out[2] = (in[2] + in[hdim+2] + 1) >> 1;
  1587.         out[3] = (in[3] + in[hdim+3] + 1) >> 1;
  1588.         in += hdim;
  1589.         out += hdim;
  1590.         --vSize;
  1591.     }
  1592.     return;
  1593. }
  1594. static void mc16pels2DInterpol( PIXEL const *in, PIXEL *out, int hdim, int vSize )
  1595. {
  1596.     while (vSize > 0) {
  1597.         out[0] = (in[0] + in[1] + in[hdim+0] + in[hdim+1] + 2) >> 2;
  1598.         out[1] = (in[1] + in[2] + in[hdim+1] + in[hdim+2] + 2) >> 2;
  1599.         out[2] = (in[2] + in[3] + in[hdim+2] + in[hdim+3] + 2) >> 2;
  1600.         out[3] = (in[3] + in[4] + in[hdim+3] + in[hdim+4] + 2) >> 2;
  1601.         out[4] = (in[4] + in[5] + in[hdim+4] + in[hdim+5] + 2) >> 2;
  1602.         out[5] = (in[5] + in[6] + in[hdim+5] + in[hdim+6] + 2) >> 2;
  1603.         out[6] = (in[6] + in[7] + in[hdim+6] + in[hdim+7] + 2) >> 2;
  1604.         out[7] = (in[7] + in[8] + in[hdim+7] + in[hdim+8] + 2) >> 2;
  1605.         out[8] = (in[8] + in[9] + in[hdim+8] + in[hdim+9] + 2) >> 2;
  1606.         out[9] = (in[9] + in[10] + in[hdim+9] + in[hdim+10] + 2) >> 2;
  1607.         out[10] = (in[10] + in[11] + in[hdim+10] + in[hdim+11] + 2) >> 2;
  1608.         out[11] = (in[11] + in[12] + in[hdim+11] + in[hdim+12] + 2) >> 2;
  1609.         out[12] = (in[12] + in[13] + in[hdim+12] + in[hdim+13] + 2) >> 2;
  1610.         out[13] = (in[13] + in[14] + in[hdim+13] + in[hdim+14] + 2) >> 2;
  1611.         out[14] = (in[14] + in[15] + in[hdim+14] + in[hdim+15] + 2) >> 2;
  1612.         out[15] = (in[15] + in[16] + in[hdim+15] + in[hdim+16] + 2) >> 2;
  1613.         in += hdim;
  1614.         out += hdim;
  1615.         --vSize;
  1616.     }
  1617.     return;
  1618. }
  1619. static void mc8pels2DInterpol( PIXEL const *in, PIXEL *out, int hdim, int vSize )
  1620. {
  1621.     while (vSize > 0) {
  1622.         out[0] = (in[0] + in[1] + in[hdim+0] + in[hdim+1] + 2) >> 2;
  1623.         out[1] = (in[1] + in[2] + in[hdim+1] + in[hdim+2] + 2) >> 2;
  1624.         out[2] = (in[2] + in[3] + in[hdim+2] + in[hdim+3] + 2) >> 2;
  1625.         out[3] = (in[3] + in[4] + in[hdim+3] + in[hdim+4] + 2) >> 2;
  1626.         out[4] = (in[4] + in[5] + in[hdim+4] + in[hdim+5] + 2) >> 2;
  1627.         out[5] = (in[5] + in[6] + in[hdim+5] + in[hdim+6] + 2) >> 2;
  1628.         out[6] = (in[6] + in[7] + in[hdim+6] + in[hdim+7] + 2) >> 2;
  1629.         out[7] = (in[7] + in[8] + in[hdim+7] + in[hdim+8] + 2) >> 2;
  1630.         in += hdim;
  1631.         out += hdim;
  1632.         --vSize;
  1633.     }
  1634.     return;
  1635. }
  1636. static void mc4pels2DInterpol( PIXEL const *in, PIXEL *out, int hdim, int vSize )
  1637. {
  1638.     while (vSize > 0) {
  1639.         out[0] = (in[0] + in[1] + in[hdim+0] + in[hdim+1] + 2) >> 2;
  1640.         out[1] = (in[1] + in[2] + in[hdim+1] + in[hdim+2] + 2) >> 2;
  1641.         out[2] = (in[2] + in[3] + in[hdim+2] + in[hdim+3] + 2) >> 2;
  1642.         out[3] = (in[3] + in[4] + in[hdim+3] + in[hdim+4] + 2) >> 2;
  1643.         in += hdim;
  1644.         out += hdim;
  1645.         --vSize;
  1646.     }
  1647.     return;
  1648. }
  1649. // Temporary arrays for backwards prediction (using next P-picture)
  1650. static  PIXEL   yBack[16*16], cbBack[8*8], crBack[8*8];
  1651. // saveBackwardPred - save macroblock to temporary area
  1652. static void saveBackwardPred( MACROBLOCK_DESCR * mb,    // Describes block to be saved
  1653.                               PICTURE * pic // Picture with pixels to be saved
  1654.                               )
  1655. {
  1656.     int     row, col, picOffset, hdim;
  1657.     // Compute luma pointer
  1658.     col = 16 * mb->x;
  1659.     row = 16 * mb->y;
  1660.     hdim = pic->y.hoffset;
  1661.     picOffset = col + row * hdim;
  1662.     // Copy luma block
  1663.     copyBlock( (S32 *)(pic->y.ptr + picOffset), 16>>2, 16, hdim>>2, (S32 *)yBack, 16>>2 );
  1664.     // Compute chroma pointer
  1665.     col = 8 * mb->x;
  1666.     row = 8 * mb->y;
  1667.     hdim = pic->cb.hoffset;
  1668.     picOffset = col + row * hdim;
  1669.     // Copy chroma blocks
  1670.     copyBlock( (S32 *)(pic->cb.ptr + picOffset), 8>>2, 8, hdim>>2, (S32 *)cbBack, 8>>2 );
  1671.     copyBlock( (S32 *)(pic->cr.ptr + picOffset), 8>>2, 8, hdim>>2, (S32 *)crBack, 8>>2 );
  1672. }
  1673. // averageForBack - Compute B-frame prediction from forward and backward predictions
  1674. static void averageForBack( MACROBLOCK_DESCR * mb,  // Describes block to be averaged
  1675.                             PICTURE * pic   // Input: contains forward prediction
  1676.                                             // Output: contains B-frame prediction
  1677.                             )
  1678. {
  1679.     int row, col, hdim, blk, firstCol, lastCol, firstRow, lastRow, cX, cY;
  1680. void (*pAverageBlockFunction)( PIXEL forPred[], int hSize, int vSize, int forOffset,
  1681.                           PIXEL backPred[], int backOffset );
  1682. #if defined(COMPILE_MMX)
  1683. if(cpuid_is_mmx_motion_on()) {
  1684. //do mmx if compiler switch AND initialized AND detected
  1685. pAverageBlockFunction = averageBlockMMX;
  1686. } else 
  1687. #endif
  1688. {
  1689. pAverageBlockFunction = averageBlock;
  1690. }
  1691.     // Process luma
  1692.     col = 16 * mb->x;
  1693.     row = 16 * mb->y;
  1694.     hdim = pic->y.hoffset;
  1695.     if (mb->mtype == MTYPE263_INTER4V) {
  1696.         for (blk = 0; blk < 4; ++blk) { // Treat each 8x8 block separately
  1697.             // Only use pixels in current MB for backwards prediction
  1698.             if (blk & 0x1) {
  1699.                 firstCol = 8, lastCol = 15; // Block 1 and 3
  1700.             } else {
  1701.                 firstCol = 0, lastCol = 7;  // Block 0 and 2
  1702.             }
  1703.             if (blk & 0x2) {
  1704.                 firstRow = 8, lastRow = 15; // Block 2 and 3
  1705.             } else {
  1706.                 firstRow = 0, lastRow = 7;  // Block 0 and 1
  1707.             }
  1708.             firstCol = max( firstCol,     (-mb->blkMvBx[blk] + 1) >> 1 );
  1709.             lastCol  = min( lastCol, 15 - ((mb->blkMvBx[blk] + 1) >> 1));
  1710.             firstRow = max( firstRow,     (-mb->blkMvBy[blk] + 1) >> 1 );
  1711.             lastRow  = min( lastRow, 15 - ((mb->blkMvBy[blk] + 1) >> 1));
  1712.             pAverageBlockFunction( pic->y.ptr + col + firstCol + (row + firstRow) * hdim,
  1713.                           lastCol - firstCol + 1,
  1714.                           lastRow - firstRow + 1, hdim,
  1715.                           yBack + firstCol + firstRow * 16, 16 );
  1716.         }
  1717.         // Determine motion vector for chroma block
  1718.         cX = chromaMvComp4V( mb->blkMvBx );
  1719.         cY = chromaMvComp4V( mb->blkMvBy );
  1720.     } else {
  1721.         // Only use pixels in current MB for backwards prediction
  1722.         firstCol = max( 0,       (-mb->blkMvBx[0] + 1) >> 1 );
  1723.         lastCol  = min( 15, 15 - ((mb->blkMvBx[0] + 1) >> 1));
  1724.         firstRow = max( 0,       (-mb->blkMvBy[0] + 1) >> 1 );
  1725.         lastRow  = min( 15, 15 - ((mb->blkMvBy[0] + 1) >> 1));
  1726. //#define MMX_AVERAGE_TEST01
  1727. #ifdef MMX_AVERAGE_TEST01
  1728. {
  1729. int crow, ccol;
  1730. PIXEL *forPred = pic->y.ptr + col + firstCol + (row + firstRow) * hdim;
  1731. int hSize = lastCol - firstCol + 1;
  1732. int vSize = lastRow - firstRow + 1;
  1733. int forOffset = hdim;
  1734. PIXEL *backPred = yBack + firstCol + firstRow * 16;
  1735. int backOffset = 16;
  1736. PIXEL forPred_org[16*352];
  1737. PIXEL backPred_org[16*16];
  1738. PIXEL forPred_temp[16*352];
  1739. PIXEL backPred_temp[16*16];
  1740. int countForOffset; 
  1741. int countBackOffset; 
  1742. int bError = 0;
  1743. countForOffset = 0; 
  1744. countBackOffset = 0; 
  1745. for (crow = 0; crow < vSize; ++crow) {
  1746. for (ccol = 0; ccol < hSize; ++ccol) {//from smaller multiple of 4
  1747. forPred_org[ccol + countForOffset] = forPred[ccol + countForOffset];
  1748. backPred_org[ccol + countBackOffset] = backPred[ccol + countBackOffset];
  1749. forPred_temp[ccol + countForOffset] = forPred[ccol + countForOffset];
  1750. backPred_temp[ccol + countBackOffset] = backPred[ccol + countBackOffset];
  1751. }
  1752. countForOffset  += forOffset;
  1753. countBackOffset += backOffset;
  1754. }
  1755. averageBlock( forPred_org,
  1756.   lastCol - firstCol + 1,
  1757.   lastRow - firstRow + 1, hdim,
  1758.   backPred_org, 16 );
  1759. #endif
  1760.         pAverageBlockFunction( pic->y.ptr + col + firstCol + (row + firstRow) * hdim,
  1761.                       lastCol - firstCol + 1,
  1762.                       lastRow - firstRow + 1, hdim,
  1763.                       yBack + firstCol + firstRow * 16, 16 );
  1764. #ifdef MMX_AVERAGE_TEST01
  1765.     countForOffset  =0;
  1766.     countBackOffset = 0;
  1767.     for (crow = 0; crow < vSize; ++crow) {
  1768.         for (ccol = 0; ccol < hSize; ++ccol) {//from smaller multiple of 4
  1769.             if( (forPred_org[ccol + countForOffset] != forPred[ccol + countForOffset])) {//((hSize==8) || (hSize==16)) &&
  1770. bError = 1;
  1771. }
  1772.         }
  1773.         countForOffset  += forOffset;
  1774.         countBackOffset += backOffset;
  1775.     }
  1776. if(bError!=0) {
  1777. countForOffset = 0; 
  1778. countBackOffset = 0; 
  1779. for (crow = 0; crow < vSize; ++crow) {
  1780. for (ccol = 0; ccol < hSize; ++ccol) {//from smaller multiple of 4
  1781. forPred_org[ccol + countForOffset] = forPred[ccol + countForOffset] = forPred_temp[ccol + countForOffset];
  1782. backPred_org[ccol + countBackOffset] = backPred[ccol + countBackOffset] = backPred_temp[ccol + countBackOffset];
  1783. }
  1784. countForOffset  += forOffset;
  1785. countBackOffset += backOffset;
  1786. }
  1787. averageBlock( forPred_org,
  1788.   lastCol - firstCol + 1,
  1789.   lastRow - firstRow + 1, hdim,
  1790.   backPred_org, 16 );
  1791. pAverageBlockFunction( pic->y.ptr + col + firstCol + (row + firstRow) * hdim,
  1792.   lastCol - firstCol + 1,
  1793.   lastRow - firstRow + 1, hdim,
  1794.   yBack + firstCol + firstRow * 16, 16 );
  1795. }
  1796. }
  1797. #endif
  1798.     
  1799.         // Determine motion vector for chroma block
  1800.         cX = chromaMVComp( mb->blkMvBx[0] );
  1801.         cY = chromaMVComp( mb->blkMvBy[0] );
  1802.     }
  1803.     // Process chroma
  1804.     col = 8 * mb->x;
  1805.     row = 8 * mb->y;
  1806.     hdim = pic->cb.hoffset;
  1807.     // Only use pixels in current MB for backwards prediction
  1808.     firstCol = max( 0,     (-cX + 1) >> 1 );
  1809.     lastCol  = min( 7, 7 - ((cX + 1) >> 1));
  1810.     firstRow = max( 0,     (-cY + 1) >> 1 );
  1811.     lastRow  = min( 7, 7 - ((cY + 1) >> 1));
  1812. //#define MMX_AVERAGE_TEST02
  1813. #ifdef MMX_AVERAGE_TEST02
  1814. {
  1815. int crow, ccol;
  1816. PIXEL *forPred = pic->cb.ptr + col + firstCol + (row + firstRow) * hdim;
  1817. int hSize = lastCol - firstCol + 1;
  1818. int vSize = lastRow - firstRow + 1;
  1819. int forOffset = hdim;
  1820. PIXEL *backPred = cbBack + firstCol + firstRow * 8;
  1821. int backOffset = 8;
  1822. PIXEL forPred_org[16*352];
  1823. PIXEL backPred_org[16*8];
  1824. int countForOffset = 0; 
  1825. int countBackOffset = 0; 
  1826.     for (crow = 0; crow < vSize; ++crow) {
  1827.         for (ccol = 0; ccol < hSize; ++ccol) {//from smaller multiple of 4
  1828.             forPred_org[ccol + countForOffset] = forPred[ccol + countForOffset];
  1829. backPred_org[ccol + countBackOffset] = backPred[ccol + countBackOffset];
  1830.         }
  1831.         countForOffset  += forOffset;
  1832.         countBackOffset += backOffset;
  1833.     }
  1834.     averageBlock( forPred_org,
  1835.                   lastCol - firstCol + 1,
  1836.                   lastRow - firstRow + 1, hdim,
  1837.                   backPred_org, 8 );
  1838. #endif
  1839.     pAverageBlockFunction( pic->cb.ptr + col + firstCol + (row + firstRow) * hdim,
  1840.                   lastCol - firstCol + 1,
  1841.                   lastRow - firstRow + 1, hdim,
  1842.                   cbBack + firstCol + firstRow * 8, 8 );
  1843. #ifdef MMX_AVERAGE_TEST02
  1844.     countForOffset  =0;
  1845.     countBackOffset = 0;
  1846.     for (crow = 0; crow < vSize; ++crow) {
  1847.         for (ccol = 0; ccol < hSize; ++ccol) {//from smaller multiple of 4
  1848.             if(((hSize==8) || (hSize==16)) && (forPred_org[ccol + countForOffset] != forPred[ccol + countForOffset])) {
  1849. averageBlock( forPred_org,
  1850.   lastCol - firstCol + 1,
  1851.   lastRow - firstRow + 1, hdim,
  1852.   backPred_org, 8 );
  1853. pAverageBlockFunction( pic->cb.ptr + col + firstCol + (row + firstRow) * hdim,
  1854.   lastCol - firstCol + 1,
  1855.   lastRow - firstRow + 1, hdim,
  1856.   cbBack + firstCol + firstRow * 8, 8 );
  1857. }
  1858.         }
  1859.         countForOffset  += forOffset;
  1860.         countBackOffset += backOffset;
  1861.     }
  1862. }
  1863. #endif
  1864.     
  1865. pAverageBlockFunction( pic->cr.ptr + col + firstCol + (row + firstRow) * hdim,
  1866.                   lastCol - firstCol + 1,
  1867.                   lastRow - firstRow + 1, hdim,
  1868.                   crBack + firstCol + firstRow * 8, 8 );
  1869. }
  1870. // copyBlock - copy 2-D array of 32-bit integers
  1871. static void copyBlock( S32 source[], int hSize, int vSize, int sourceOffset,
  1872.                        S32 dest[], int destOffset )
  1873. {
  1874.     int row, col;
  1875.     for (row = 0; row < vSize; ++row) {
  1876.         for (col = 0; col < hSize; ++col) {
  1877.             dest[col] = source[col];
  1878.         }
  1879.         source += sourceOffset;
  1880.         dest   += destOffset;
  1881.     }
  1882. }
  1883. // averageBlock - compute average of two hSize*vSize pixel arrays
  1884. void averageBlock( PIXEL forPred[], int hSize, int vSize, int forOffset,
  1885.                           PIXEL backPred[], int backOffset )
  1886. {
  1887.     int row, col;
  1888. #ifdef VVPROFILER
  1889. S32 nVvProfNb = 3;
  1890. if(!pVvProf[nVvProfNb]) pVvProf[nVvProfNb] = newCVvDebugTimer();//memory leak on destruction
  1891. pVvProfCount[nVvProfNb]++;
  1892. StartTime(pVvProf[nVvProfNb]);
  1893. #endif
  1894.     for (row = 0; row < vSize; ++row) {
  1895.         for (col = 0; col < hSize; ++col) {
  1896.             forPred[col] = (forPred[col] + backPred[col]) >> 1;
  1897.         }
  1898.         forPred  += forOffset;
  1899.         backPred += backOffset;
  1900.     }
  1901. #ifdef VVPROFILER
  1902. StopAndAccuTime(pVvProf[nVvProfNb]);
  1903. #endif
  1904. }