mcomp.c
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:79k
源码类别:

Symbian

开发平台:

Visual C++

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