[svn] / branches / dev-api-4 / xvidcore / src / motion / motion_est.c Repository:
ViewVC logotype

Diff of /branches/dev-api-4/xvidcore/src/motion/motion_est.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

trunk/xvidcore/src/motion/motion_est.c revision 346, Sun Jul 28 02:55:41 2002 UTC branches/dev-api-4/xvidcore/src/motion/motion_est.c revision 963, Sat Mar 29 12:01:36 2003 UTC
# Line 28  Line 28 
28   *   *
29   *************************************************************************/   *************************************************************************/
30    
 /**************************************************************************  
  *  
  *  Modifications:  
  *  
  *      01.05.2002      updated MotionEstimationBVOP  
  *      25.04.2002 partial prevMB conversion  
  *  22.04.2002 remove some compile warning by chenm001 <chenm001@163.com>  
  *  14.04.2002 added MotionEstimationBVOP()  
  *  02.04.2002 add EPZS(^2) as ME algorithm, use PMV_USESQUARES to choose between  
  *             EPZS and EPZS^2  
  *  08.02.2002 split up PMVfast into three routines: PMVFast, PMVFast_MainLoop  
  *             PMVFast_Refine to support multiple searches with different start points  
  *  07.01.2002 uv-block-based interpolation  
  *  06.01.2002 INTER/INTRA-decision is now done before any SEARCH8 (speedup)  
  *             changed INTER_BIAS to 150 (as suggested by suxen_drol)  
  *             removed halfpel refinement step in PMVfastSearch8 + quality=5  
  *             added new quality mode = 6 which performs halfpel refinement  
  *             filesize difference between quality 5 and 6 is smaller than 1%  
  *             (Isibaar)  
  *  31.12.2001 PMVfastSearch16 and PMVfastSearch8 (gruel)  
  *  30.12.2001 get_range/MotionSearchX simplified; blue/green bug fix  
  *  22.12.2001 commented best_point==99 check  
  *  19.12.2001 modified get_range (purple bug fix)  
  *  15.12.2001 moved pmv displacement from mbprediction  
  *  02.12.2001 motion estimation/compensation split (Isibaar)  
  *  16.11.2001 rewrote/tweaked search algorithms; pross@cs.rmit.edu.au  
  *  10.11.2001 support for sad16/sad8 functions  
  *  28.08.2001 reactivated MODE_INTER4V for EXT_MODE  
  *  24.08.2001 removed MODE_INTER4V_Q, disabled MODE_INTER4V for EXT_MODE  
  *  22.08.2001 added MODE_INTER4V_Q  
  *  20.08.2001 added pragma to get rid of internal compiler error with VC6  
  *             idea by Cyril. Thanks.  
  *  
  *  Michael Militzer <isibaar@videocoding.de>  
  *  
  **************************************************************************/  
   
31  #include <assert.h>  #include <assert.h>
32  #include <stdio.h>  #include <stdio.h>
33  #include <stdlib.h>  #include <stdlib.h>
34    #include <string.h>     // memcpy
35    #include <math.h>       // lrint
36    
37  #include "../encoder.h"  #include "../encoder.h"
38  #include "../utils/mbfunctions.h"  #include "../utils/mbfunctions.h"
39  #include "../prediction/mbprediction.h"  #include "../prediction/mbprediction.h"
40  #include "../global.h"  #include "../global.h"
41  #include "../utils/timer.h"  #include "../utils/timer.h"
42    #include "../image/interpolate8x8.h"
43    #include "motion_est.h"
44  #include "motion.h"  #include "motion.h"
45  #include "sad.h"  #include "sad.h"
46    #include "../utils/emms.h"
47    #include "../dct/fdct.h"
48    
49    /*****************************************************************************
50     * Modified rounding tables -- declared in motion.h
51  static int32_t lambda_vec16[32] =       /* rounded values for lambda param for weight of motion bits as in modified H.26L */   * Original tables see ISO spec tables 7-6 -> 7-9
52  { 0, (int) (1.00235 + 0.5), (int) (1.15582 + 0.5), (int) (1.31976 + 0.5),   ****************************************************************************/
53                  (int) (1.49591 + 0.5), (int) (1.68601 + 0.5),  
54          (int) (1.89187 + 0.5), (int) (2.11542 + 0.5), (int) (2.35878 + 0.5),  const uint32_t roundtab[16] =
55                  (int) (2.62429 + 0.5), (int) (2.91455 + 0.5),  {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2 };
56          (int) (3.23253 + 0.5), (int) (3.58158 + 0.5), (int) (3.96555 + 0.5),  
57                  (int) (4.38887 + 0.5), (int) (4.85673 + 0.5),  /* K = 4 */
58          (int) (5.37519 + 0.5), (int) (5.95144 + 0.5), (int) (6.59408 + 0.5),  const uint32_t roundtab_76[16] =
59                  (int) (7.31349 + 0.5), (int) (8.12242 + 0.5),  { 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1 };
60          (int) (9.03669 + 0.5), (int) (10.0763 + 0.5), (int) (11.2669 + 0.5),  
61                  (int) (12.6426 + 0.5), (int) (14.2493 + 0.5),  /* K = 2 */
62          (int) (16.1512 + 0.5), (int) (18.442 + 0.5), (int) (21.2656 + 0.5),  const uint32_t roundtab_78[8] =
63                  (int) (24.8580 + 0.5), (int) (29.6436 + 0.5),  { 0, 0, 1, 1, 0, 0, 0, 1  };
64          (int) (36.4949 + 0.5)  
65  };  /* K = 1 */
66    const uint32_t roundtab_79[4] =
67  static int32_t *lambda_vec8 = lambda_vec16;     /* same table for INTER and INTER4V for now */  { 0, 1, 0, 0 };
68    
69    #define INITIAL_SKIP_THRESH     (10)
70    #define FINAL_SKIP_THRESH       (50)
71  // mv.length table  #define MAX_SAD00_FOR_SKIP      (20)
72  static const uint32_t mvtab[33] = {  #define MAX_CHROMA_SAD_FOR_SKIP (22)
73          1, 2, 3, 4, 6, 7, 7, 7,  
74          9, 9, 9, 10, 10, 10, 10, 10,  #define CHECK_CANDIDATE(X,Y,D) { \
75          10, 10, 10, 10, 10, 10, 10, 10,  CheckCandidate((X),(Y), (D), &iDirection, data ); }
76          10, 11, 11, 11, 11, 11, 11, 12, 12  
77  };  /*****************************************************************************
78     * Code
79     ****************************************************************************/
80    
81  static __inline uint32_t  static __inline uint32_t
82  mv_bits(int32_t component,  d_mv_bits(int x, int y, const VECTOR pred, const uint32_t iFcode, const int qpel, const int rrv)
                 const uint32_t iFcode)  
83  {  {
84          if (component == 0)          int xb, yb;
85                  return 1;          x = qpel ? x<<1 : x;
86            y = qpel ? y<<1 : y;
87          if (component < 0)          if (rrv) { x = RRV_MV_SCALEDOWN(x); y = RRV_MV_SCALEDOWN(y); }
88                  component = -component;  
89            x -= pred.x;
90          if (iFcode == 1) {          y -= pred.y;
91                  if (component > 32)  
92                          component = 32;          if (x) {
93                    x = ABS(x);
94                  return mvtab[component] + 1;                  x += (1 << (iFcode - 1)) - 1;
95          }                  x >>= (iFcode - 1);
96                    if (x > 32) x = 32;
97          component += (1 << (iFcode - 1)) - 1;                  xb = mvtab[x] + iFcode;
98          component >>= (iFcode - 1);          } else xb = 1;
99    
100          if (component > 32)          if (y) {
101                  component = 32;                  y = ABS(y);
102                    y += (1 << (iFcode - 1)) - 1;
103          return mvtab[component] + 1 + iFcode - 1;                  y >>= (iFcode - 1);
104  }                  if (y > 32) y = 32;
105                    yb = mvtab[y] + iFcode;
106            } else yb = 1;
107  static __inline uint32_t          return xb + yb;
108  calc_delta_16(const int32_t dx,  }
109                            const int32_t dy,  
110                            const uint32_t iFcode,  static int32_t ChromaSAD2(int fx, int fy, int bx, int by, const SearchData * const data)
111                            const uint32_t iQuant)  {
112  {          int sad;
113          return NEIGH_TEND_16X16 * lambda_vec16[iQuant] * (mv_bits(dx, iFcode) +          const uint32_t stride = data->iEdgedWidth/2;
114                                                                                                            mv_bits(dy, iFcode));          uint8_t * f_refu = data->RefQ,
115  }                  * f_refv = data->RefQ + 8,
116                    * b_refu = data->RefQ + 16,
117  static __inline uint32_t                  * b_refv = data->RefQ + 24;
118  calc_delta_8(const int32_t dx,  
119                           const int32_t dy,          switch (((fx & 1) << 1) | (fy & 1))     {
120                           const uint32_t iFcode,                  case 0:
121                           const uint32_t iQuant)                          fx = fx / 2; fy = fy / 2;
122  {                          f_refu = (uint8_t*)data->RefCU + fy * stride + fx, stride;
123          return NEIGH_TEND_8X8 * lambda_vec8[iQuant] * (mv_bits(dx, iFcode) +                          f_refv = (uint8_t*)data->RefCV + fy * stride + fx, stride;
124                                                                                                     mv_bits(dy, iFcode));                          break;
 }  
   
 bool  
 MotionEstimation(MBParam * const pParam,  
                                  FRAMEINFO * const current,  
                                  FRAMEINFO * const reference,  
                                  const IMAGE * const pRefH,  
                                  const IMAGE * const pRefV,  
                                  const IMAGE * const pRefHV,  
                                  const uint32_t iLimit)  
 {  
         const uint32_t iWcount = pParam->mb_width;  
         const uint32_t iHcount = pParam->mb_height;  
         MACROBLOCK *const pMBs = current->mbs;  
         MACROBLOCK *const prevMBs = reference->mbs;  
         const IMAGE *const pCurrent = &current->image;  
         const IMAGE *const pRef = &reference->image;  
   
         static const VECTOR zeroMV = { 0, 0 };  
         VECTOR predMV;  
   
         int32_t x, y;  
         int32_t iIntra = 0;  
         VECTOR pmv;  
   
         if (sadInit)  
                 (*sadInit) ();  
   
         for (y = 0; y < iHcount; y++)   {  
                 for (x = 0; x < iWcount; x ++)  {  
   
                         MACROBLOCK *const pMB = &pMBs[x + y * iWcount];  
   
                         predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);  
   
                         pMB->sad16 =  
                                 SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,  
                                                  x, y, predMV.x, predMV.y, predMV.x, predMV.y,  
                                                  current->motion_flags, current->quant,  
                                                  current->fcode, pParam, pMBs, prevMBs, &pMB->mv16,  
                                                  &pMB->pmvs[0]);  
   
                         if (0 < (pMB->sad16 - MV16_INTER_BIAS)) {  
                                 int32_t deviation;  
   
                                 deviation =  
                                         dev16(pCurrent->y + x * 16 + y * 16 * pParam->edged_width,  
                                                   pParam->edged_width);  
   
                                 if (deviation < (pMB->sad16 - MV16_INTER_BIAS)) {  
                                         pMB->mode = MODE_INTRA;  
                                         pMB->mv16 = pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =  
                                                 pMB->mvs[3] = zeroMV;  
                                         pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =  
                                                 pMB->sad8[3] = 0;  
   
                                         iIntra++;  
                                         if (iIntra >= iLimit)  
                                                 return 1;  
   
                                         continue;  
                                 }  
                         }  
   
                         pmv = pMB->pmvs[0];  
                         if (current->global_flags & XVID_INTER4V)  
                                 if ((!(current->global_flags & XVID_LUMIMASKING) ||  
                                          pMB->dquant == NO_CHANGE)) {  
                                         int32_t sad8 = IMV16X16 * current->quant;  
   
                                         if (sad8 < pMB->sad16) {  
                                                 sad8 += pMB->sad8[0] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x, 2 * y,  
                                                                         pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,  
                                                                         current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[0],  
                                                                         &pMB->pmvs[0]);  
                                         }  
                                         if (sad8 < pMB->sad16) {  
   
                                                 predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 1);  
                                                 sad8 += pMB->sad8[1] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x + 1, 2 * y,  
                                                                         pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,  
                                                                         current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[1],  
                                                                         &pMB->pmvs[1]);  
                                         }  
                                         if (sad8 < pMB->sad16) {  
                                                 predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 2);  
                                                 sad8 += pMB->sad8[2] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x, 2 * y + 1,  
                                                                         pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,  
                                                                         current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[2],  
                                                                         &pMB->pmvs[2]);  
                                         }  
                                         if (sad8 < pMB->sad16) {  
                                                 predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 3);  
                                                 sad8 += pMB->sad8[3] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x + 1, 2 * y + 1,  
                                                                         pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,  
                                                                         current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs,  
                                                                         &pMB->mvs[3],  
                                                                         &pMB->pmvs[3]);  
                                         }  
   
                                         /* decide: MODE_INTER or MODE_INTER4V  
                                            mpeg4:   if (sad8 < pMB->sad16 - nb/2+1) use_inter4v  
                                          */  
   
                                         if (sad8 < pMB->sad16) {  
                                                 pMB->mode = MODE_INTER4V;  
                                                 pMB->sad8[0] *= 4;  
                                                 pMB->sad8[1] *= 4;  
                                                 pMB->sad8[2] *= 4;  
                                                 pMB->sad8[3] *= 4;  
                                                 continue;  
                                         }  
   
                                 }  
   
                         pMB->mode = MODE_INTER;  
                         pMB->pmvs[0] = pmv;     /* pMB->pmvs[1] = pMB->pmvs[2] = pMB->pmvs[3]  are not needed for INTER */  
                         pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mv16;  
                         pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] =  
                                 pMB->sad16;  
                         }  
                         }  
   
         return 0;  
 }  
   
   
 #define CHECK_MV16_ZERO {\  
   if ( (0 <= max_dx) && (0 >= min_dx) \  
     && (0 <= max_dy) && (0 >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \  
     iSAD += calc_delta_16(-center_x, -center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=0; currMV->y=0; }  }     \  
 }  
   
 #define NOCHECK_MV16_CANDIDATE(X,Y) { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \  
 }  
   
 #define CHECK_MV16_CANDIDATE(X,Y) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_CANDIDATE_DIR(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \  
 }  
   
 #define CHECK_MV16_CANDIDATE_FOUND(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
 }  
   
   
 #define CHECK_MV8_ZERO {\  
   iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, 0, 0 , iEdgedWidth), iEdgedWidth); \  
   iSAD += calc_delta_8(-center_x, -center_y, (uint8_t)iFcode, iQuant);\  
   if (iSAD < iMinSAD) \  
   { iMinSAD=iSAD; currMV->x=0; currMV->y=0; } \  
 }  
   
 #define NOCHECK_MV8_CANDIDATE(X,Y) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \  
 }  
   
 #define CHECK_MV8_CANDIDATE(X,Y) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV8_CANDIDATE_DIR(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \  
 }  
   
 #define CHECK_MV8_CANDIDATE_FOUND(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
 }  
   
 /* too slow and not fully functional at the moment */  
 /*  
 int32_t ZeroSearch16(  
                                         const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const IMAGE * const pCur,  
                                         const int x, const int y,  
                                         const uint32_t MotionFlags,  
                                         const uint32_t iQuant,  
                                         const uint32_t iFcode,  
                                         MBParam * const pParam,  
                                         const MACROBLOCK * const pMBs,  
                                         const MACROBLOCK * const prevMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
 {  
         const int32_t iEdgedWidth = pParam->edged_width;  
         const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;  
         int32_t iSAD;  
         VECTOR pred;  
   
   
         pred = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);  
   
         iSAD = sad16( cur,  
                 get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth),  
                 iEdgedWidth, MV_MAX_ERROR);  
         if (iSAD <= iQuant * 96)  
                 iSAD -= MV16_00_BIAS;  
   
         currMV->x = 0;  
         currMV->y = 0;  
         currPMV->x = -pred.x;  
         currPMV->y = -pred.y;  
   
         return iSAD;  
   
 }  
 */  
   
 int32_t  
 Diamond16_MainSearch(const uint8_t * const pRef,  
                                          const uint8_t * const pRefH,  
                                          const uint8_t * const pRefV,  
                                          const uint8_t * const pRefHV,  
                                          const uint8_t * const cur,  
                                          const int x,  
                                          const int y,  
                                    const int start_x,  
                                    const int start_y,  
                                    int iMinSAD,  
                                    VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                          const int32_t min_dx,  
                                          const int32_t max_dx,  
                                          const int32_t min_dy,  
                                          const int32_t max_dy,  
                                          const int32_t iEdgedWidth,  
                                          const int32_t iDiamondSize,  
                                          const int32_t iFcode,  
                                          const int32_t iQuant,  
                                          int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iDirectionBackup;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
   
         if (iDirection) {  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;  
                         iDirectionBackup = iDirection;  
   
                         if (iDirectionBackup != 2)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                    backupMV.y, 1);  
                         if (iDirectionBackup != 1)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                    backupMV.y, 2);  
                         if (iDirectionBackup != 4)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,  
                                                                                    backupMV.y - iDiamondSize, 3);  
                         if (iDirectionBackup != 3)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,  
                                                                                    backupMV.y + iDiamondSize, 4);  
                 }  
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
         }  
         return iMinSAD;  
 }  
   
 int32_t  
 Square16_MainSearch(const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x,  
                                         const int y,  
                                    const int start_x,  
                                    const int start_y,  
                                    int iMinSAD,  
                                    VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a square search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* It's one search with full square pattern, and new parts for all following diamonds */  
   
 /*   new direction are extra, so 1-4 is normal diamond  
       537  
       1*2  
       648  
 */  
   
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
   
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 5);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 6);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 7);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 8);  
   
   
         if (iDirection) {  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;  
   
                         switch (iDirection) {  
125                          case 1:                          case 1:
126                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          fx = fx / 2; fy = (fy - 1) / 2;
127                                                                                     backupMV.y, 1);                          interpolate8x8_halfpel_v(f_refu, data->RefCU + fy * stride + fx, stride, data->rounding);
128                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          interpolate8x8_halfpel_v(f_refv, data->RefCV + fy * stride + fx, stride, data->rounding);
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
129                                  break;                                  break;
130                          case 2:                          case 2:
131                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,                          fx = (fx - 1) / 2; fy = fy / 2;
132                                                                                   2);                          interpolate8x8_halfpel_h(f_refu, data->RefCU + fy * stride + fx, stride, data->rounding);
133                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          interpolate8x8_halfpel_h(f_refv, data->RefCV + fy * stride + fx, stride, data->rounding);
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
134                                  break;                                  break;
135                    default:
136                          case 3:                          fx = (fx - 1) / 2; fy = (fy - 1) / 2;
137                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                          interpolate8x8_halfpel_hv(f_refu, data->RefCU + fy * stride + fx, stride, data->rounding);
138                                                                                   4);                          interpolate8x8_halfpel_hv(f_refv, data->RefCV + fy * stride + fx, stride, data->rounding);
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
139                                  break;                                  break;
140            }
141    
142                          case 4:          switch (((bx & 1) << 1) | (by & 1))     {
143                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,                  case 0:
144                                                                                   3);                          bx = bx / 2; by = by / 2;
145                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          b_refu = (uint8_t*)data->b_RefCU + by * stride + bx, stride;
146                                                                                   backupMV.y - iDiamondSize, 5);                          b_refv = (uint8_t*)data->b_RefCV + by * stride + bx, stride;
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 break;  
   
                         case 5:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
   
                         case 6:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
   
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
   
147                                  break;                                  break;
148                    case 1:
149                          case 7:                          bx = bx / 2; by = (by - 1) / 2;
150                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          interpolate8x8_halfpel_v(b_refu, data->b_RefCU + by * stride + bx, stride, data->rounding);
151                                                                                     backupMV.y, 1);                          interpolate8x8_halfpel_v(b_refv, data->b_RefCV + by * stride + bx, stride, data->rounding);
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
152                                  break;                                  break;
153                    case 2:
154                          case 8:                          bx = (bx - 1) / 2; by = by / 2;
155                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,                          interpolate8x8_halfpel_h(b_refu, data->b_RefCU + by * stride + bx, stride, data->rounding);
156                                                                                   2);                          interpolate8x8_halfpel_h(b_refv, data->b_RefCV + by * stride + bx, stride, data->rounding);
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
157                                  break;                                  break;
158                          default:                          default:
159                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,                          bx = (bx - 1) / 2; by = (by - 1) / 2;
160                                                                                   1);                          interpolate8x8_halfpel_hv(b_refu, data->b_RefCU + by * stride + bx, stride, data->rounding);
161                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,                          interpolate8x8_halfpel_hv(b_refv, data->b_RefCV + by * stride + bx, stride, data->rounding);
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
   
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
162                                  break;                                  break;
163                          }                          }
                 }  
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
         }  
         return iMinSAD;  
 }  
164    
165            sad = sad8bi(data->CurU, b_refu, f_refu, stride);
166            sad += sad8bi(data->CurV, b_refv, f_refv, stride);
167    
168  int32_t          return sad;
 Full16_MainSearch(const uint8_t * const pRef,  
                                   const uint8_t * const pRefH,  
                                   const uint8_t * const pRefV,  
                                   const uint8_t * const pRefHV,  
                                   const uint8_t * const cur,  
                                   const int x,  
                                   const int y,  
                                    const int start_x,  
                                    const int start_y,  
                                    int iMinSAD,  
                                    VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                   const int32_t min_dx,  
                                   const int32_t max_dx,  
                                   const int32_t min_dy,  
                                   const int32_t max_dy,  
                                   const int32_t iEdgedWidth,  
                                   const int32_t iDiamondSize,  
                                   const int32_t iFcode,  
                                   const int32_t iQuant,  
                                   int iFound)  
 {  
         int32_t iSAD;  
         int32_t dx, dy;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV16_CANDIDATE(dx, dy);  
   
         return iMinSAD;  
169  }  }
170    
 int32_t  
 AdvDiamond16_MainSearch(const uint8_t * const pRef,  
                                                 const uint8_t * const pRefH,  
                                                 const uint8_t * const pRefV,  
                                                 const uint8_t * const pRefHV,  
                                                 const uint8_t * const cur,  
                                                 const int x,  
                                                 const int y,  
                                            int start_x,  
                                            int start_y,  
                                            int iMinSAD,  
                                            VECTOR * const currMV,  
                                            const int center_x,  
                                            const int center_y,  
                                                 const int32_t min_dx,  
                                                 const int32_t max_dx,  
                                                 const int32_t min_dy,  
                                                 const int32_t max_dy,  
                                                 const int32_t iEdgedWidth,  
                                                 const int32_t iDiamondSize,  
                                                 const int32_t iFcode,  
                                                 const int32_t iQuant,  
                                                 int iDirection)  
 {  
171    
172          int32_t iSAD;  static int32_t
173    ChromaSAD(int dx, int dy, const SearchData * const data)
 /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */  
   
         if (iDirection) {  
                 CHECK_MV16_CANDIDATE(start_x - iDiamondSize, start_y);  
                 CHECK_MV16_CANDIDATE(start_x + iDiamondSize, start_y);  
                 CHECK_MV16_CANDIDATE(start_x, start_y - iDiamondSize);  
                 CHECK_MV16_CANDIDATE(start_x, start_y + iDiamondSize);  
         } else {  
                 int bDirection = 1 + 2 + 4 + 8;  
   
                 do {  
                         iDirection = 0;  
                         if (bDirection & 1)     //we only want to check left if we came from the right (our last motion was to the left, up-left or down-left)  
                                 CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
   
                         if (bDirection & 2)  
                                 CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
   
                         if (bDirection & 4)  
                                 CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);  
   
                         if (bDirection & 8)  
                                 CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
   
                         /* now we're doing diagonal checks near our candidate */  
   
                         if (iDirection)         //checking if anything found  
174                          {                          {
175                                  bDirection = iDirection;          int sad;
176                                  iDirection = 0;          const uint32_t stride = data->iEdgedWidth/2;
                                 start_x = currMV->x;  
                                 start_y = currMV->y;  
                                 if (bDirection & 3)     //our candidate is left or right  
                                 {  
                                         CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);  
                                 } else                  // what remains here is up or down  
                                 {  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
                                 }  
177    
178                                  if (iDirection) {          if (dx == data->temp[5] && dy == data->temp[6]) return data->temp[7]; //it has been checked recently
179                                          bDirection += iDirection;          data->temp[5] = dx; data->temp[6] = dy; // backup
                                         start_x = currMV->x;  
                                         start_y = currMV->y;  
                                 }  
                         } else                          //about to quit, eh? not so fast....  
                         {  
                                 switch (bDirection) {  
                                 case 2:  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1:  
180    
181                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,          switch (((dx & 1) << 1) | (dy & 1))     {
182                                                                                           start_y - iDiamondSize, 1 + 4);                  case 0:
183                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                          dx = dx / 2; dy = dy / 2;
184                                                                                           start_y + iDiamondSize, 1 + 8);                          sad = sad8(data->CurU, data->RefCU + dy * stride + dx, stride);
185                            sad += sad8(data->CurV, data->RefCV + dy * stride + dx, stride);
186                                          break;                                          break;
187                                  case 2 + 4:                  case 1:
188                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                          dx = dx / 2; dy = (dy - 1) / 2;
189                                                                                           start_y - iDiamondSize, 1 + 4);                          sad = sad8bi(data->CurU, data->RefCU + dy * stride + dx, data->RefCU + (dy+1) * stride + dx, stride);
190                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                          sad += sad8bi(data->CurV, data->RefCV + dy * stride + dx, data->RefCV + (dy+1) * stride + dx, stride);
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 4:  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         break;  
                                 case 8:  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 1 + 4:  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         break;  
                                 case 2 + 8:  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
191                                          break;                                          break;
192                                  case 1 + 8:                  case 2:
193                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                          dx = (dx - 1) / 2; dy = dy / 2;
194                                                                                           start_y - iDiamondSize, 2 + 4);                          sad = sad8bi(data->CurU, data->RefCU + dy * stride + dx, data->RefCU + dy * stride + dx+1, stride);
195                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                          sad += sad8bi(data->CurV, data->RefCV + dy * stride + dx, data->RefCV + dy * stride + dx+1, stride);
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
196                                          break;                                          break;
197                                  default:                //1+2+4+8 == we didn't find anything at all                  default:
198                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                          dx = (dx - 1) / 2; dy = (dy - 1) / 2;
199                                                                                           start_y - iDiamondSize, 1 + 4);                          interpolate8x8_halfpel_hv(data->RefQ, data->RefCU + dy * stride + dx, stride, data->rounding);
200                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                          sad = sad8(data->CurU, data->RefQ, stride);
201                                                                                           start_y + iDiamondSize, 1 + 8);  
202                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                          interpolate8x8_halfpel_hv(data->RefQ, data->RefCV + dy * stride + dx, stride, data->rounding);
203                                                                                           start_y - iDiamondSize, 2 + 4);                          sad += sad8(data->CurV, data->RefQ, stride);
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
204                                          break;                                          break;
205                                  }                                  }
206                                  if (!iDirection)          data->temp[7] = sad; //backup, part 2
207                                          break;          //ok, the end. really          return sad;
                                 else {  
                                         bDirection = iDirection;  
                                         start_x = currMV->x;  
                                         start_y = currMV->y;  
                                 }  
                         }  
                 }  
                 while (1);                              //forever  
208          }          }
         return iMinSAD;  
 }  
   
 #define CHECK_MV16_F_INTERPOL(X,Y) { \  
   if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \  
     && ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, b_currMV->x, b_currMV->y, iEdgedWidth),   \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16((X) - f_center_x, (Y) - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16(b_currMV->x - b_center_x, b_currMV->y - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; f_currMV->x=(X); f_currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_F_INTERPOL_FOUND(X,Y) { \  
   if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \  
     && ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, b_currMV->x, b_currMV->y, iEdgedWidth),   \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16((X) - f_center_x, (Y) - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16(b_currMV->x - b_center_x, b_currMV->y - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; f_currMV->x=(X); f_currMV->y=(Y); iFound=0;} } \  
 }  
   
 #define CHECK_MV16_B_INTERPOL(X,Y) { \  
   if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \  
     && ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth),   \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16((X) - b_center_x, (Y) - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; b_currMV->x=(X); b_currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_B_INTERPOL_FOUND(X,Y) { \  
   if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \  
     && ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth),   \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16((X) - b_center_x, (Y) - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; b_currMV->x=(X); b_currMV->y=(Y); iFound=0;} } \  
 }  
   
 int32_t  
 Diamond16_InterpolMainSearch(  
                                         const uint8_t * const f_pRef,  
                                          const uint8_t * const f_pRefH,  
                                          const uint8_t * const f_pRefV,  
                                          const uint8_t * const f_pRefHV,  
   
                                          const uint8_t * const cur,  
   
                                         const uint8_t * const b_pRef,  
                                          const uint8_t * const b_pRefH,  
                                          const uint8_t * const b_pRefV,  
                                          const uint8_t * const b_pRefHV,  
   
                                          const int x,  
                                          const int y,  
   
                                    const int f_start_x,  
                                    const int f_start_y,  
                                    const int b_start_x,  
                                    const int b_start_y,  
   
                                    int iMinSAD,  
                                    VECTOR * const f_currMV,  
                                    VECTOR * const b_currMV,  
   
                                    const int f_center_x,  
                                    const int f_center_y,  
                                    const int b_center_x,  
                                    const int b_center_y,  
   
                                     const int32_t f_min_dx,  
                                         const int32_t f_max_dx,  
                                         const int32_t f_min_dy,  
                                         const int32_t f_max_dy,  
   
                                     const int32_t b_min_dx,  
                                         const int32_t b_max_dx,  
                                         const int32_t b_min_dy,  
                                         const int32_t b_max_dy,  
   
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
   
                                         const int32_t f_iFcode,  
                                         const int32_t b_iFcode,  
   
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iSAD;  
   
         VECTOR f_backupMV;  
         VECTOR b_backupMV;  
   
         f_currMV->x = f_start_x;  
         f_currMV->y = f_start_y;  
         b_currMV->x = b_start_x;  
         b_currMV->y = b_start_y;  
   
         do  
         {  
                 iFound = 1;  
   
                 f_backupMV = *f_currMV;  
   
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x - iDiamondSize, f_backupMV.y);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x + iDiamondSize, f_backupMV.y);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y - iDiamondSize);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y + iDiamondSize);  
   
                 b_backupMV = *b_currMV;  
   
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x - iDiamondSize, b_backupMV.y);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x + iDiamondSize, b_backupMV.y);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y - iDiamondSize);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y + iDiamondSize);  
   
         } while (!iFound);  
   
         return iMinSAD;  
 }  
   
 /* Sorry, these MACROS really got too large... I'll turn them into function soon! */  
   
 #define CHECK_MV16_DIRECT_FOUND(X,Y) \  
         if ( (X)>=(-32) && (X)<=(31) && ((Y)>=-32) && ((Y)<=31) ) \  
         { int k;\  
         VECTOR mvs,b_mvs;       \  
         iSAD = 0;\  
         for (k = 0; k < 4; k++) {       \  
                                         mvs.x = (int32_t) ((TRB * directmv[k].x) / TRD + (X));          \  
                     b_mvs.x = (int32_t) (((X) == 0)                                                     \  
                                                                                 ? ((TRB - TRD) * directmv[k].x) / TRD   \  
                                             : mvs.x - directmv[k].x);                           \  
                                                                                                                                                                 \  
                     mvs.y = (int32_t) ((TRB * directmv[k].y) / TRD + (Y));              \  
                         b_mvs.y = (int32_t) (((Y) == 0)                                                         \  
                                                                                 ? ((TRB - TRD) * directmv[k].y) / TRD   \  
                                             : mvs.y - directmv[k].y);                           \  
                                                                                                                                                                 \  
   if ( (mvs.x <= max_dx) && (mvs.x >= min_dx) \  
     && (mvs.y <= max_dy) && (mvs.y >= min_dy)  \  
         && (b_mvs.x <= max_dx) && (b_mvs.x >= min_dx)  \  
     && (b_mvs.y <= max_dy) && (b_mvs.y >= min_dy) ) { \  
             iSAD += sad8bi( cur + 8*(k&1) + 8*(k>>1)*iEdgedWidth,                                                                                                       \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \  
                                         mvs.x, mvs.y, iEdgedWidth),                                                             \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \  
                                         b_mvs.x, b_mvs.y, iEdgedWidth),                                                         \  
                         iEdgedWidth); \  
                 }       \  
         else    \  
                 iSAD = 65535;   \  
         } \  
         iSAD += calc_delta_16((X),(Y), 1, iQuant);\  
         if (iSAD < iMinSAD) \  
             {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iFound=0; } \  
 }  
   
   
   
 int32_t  
 Diamond16_DirectMainSearch(  
                                         const uint8_t * const f_pRef,  
                                         const uint8_t * const f_pRefH,  
                                         const uint8_t * const f_pRefV,  
                                         const uint8_t * const f_pRefHV,  
   
                                         const uint8_t * const cur,  
   
                                         const uint8_t * const b_pRef,  
                                         const uint8_t * const b_pRefH,  
                                         const uint8_t * const b_pRefV,  
                                         const uint8_t * const b_pRefHV,  
   
                                         const int x,  
                                         const int y,  
   
                                         const int TRB,  
                                         const int TRD,  
   
                                     const int start_x,  
                                     const int start_y,  
209    
210                                      int iMinSAD,  static __inline const uint8_t *
211                                      VECTOR * const currMV,  GetReferenceB(const int x, const int y, const uint32_t dir, const SearchData * const data)
                                         const VECTOR * const directmv,  
   
                                     const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
   
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
   
                                         const int32_t iQuant,  
                                         int iFound)  
212  {  {
213  /* Do a diamond search around given starting point, return SAD of best */  //      dir : 0 = forward, 1 = backward
214            switch ( (dir << 2) | ((x&1)<<1) | (y&1) ) {
215          int32_t iSAD;                  case 0 : return data->Ref + x/2 + (y/2)*(data->iEdgedWidth);
216                    case 1 : return data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth);
217          VECTOR backupMV;                  case 2 : return data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth);
218                    case 3 : return data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth);
219          currMV->x = start_x;                  case 4 : return data->bRef + x/2 + (y/2)*(data->iEdgedWidth);
220          currMV->y = start_y;                  case 5 : return data->bRefV + x/2 + ((y-1)/2)*(data->iEdgedWidth);
221                    case 6 : return data->bRefH + (x-1)/2 + (y/2)*(data->iEdgedWidth);
222  /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */                  default : return data->bRefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth);
223            }
224    }
225    
226          do  // this is a simpler copy of GetReferenceB, but as it's __inline anyway, we can keep the two separate
227    static __inline const uint8_t *
228    GetReference(const int x, const int y, const SearchData * const data)
229          {          {
230                  iFound = 1;          switch ( ((x&1)<<1) | (y&1) ) {
231                    case 0 : return data->Ref + x/2 + (y/2)*(data->iEdgedWidth);
232                  backupMV = *currMV;                  case 3 : return data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth);
233                    case 1 : return data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth);
234                  CHECK_MV16_DIRECT_FOUND(backupMV.x - iDiamondSize, backupMV.y);                  default : return data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth);      //case 2
235                  CHECK_MV16_DIRECT_FOUND(backupMV.x + iDiamondSize, backupMV.y);          }
                 CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y - iDiamondSize);  
                 CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y + iDiamondSize);  
   
         } while (!iFound);  
   
         return iMinSAD;  
236  }  }
237    
238    static uint8_t *
239  int32_t  Interpolate8x8qpel(const int x, const int y, const uint32_t block, const uint32_t dir, const SearchData * const data)
 AdvDiamond8_MainSearch(const uint8_t * const pRef,  
                                            const uint8_t * const pRefH,  
                                            const uint8_t * const pRefV,  
                                            const uint8_t * const pRefHV,  
                                            const uint8_t * const cur,  
                                            const int x,  
                                            const int y,  
                                            int start_x,  
                                            int start_y,  
                                            int iMinSAD,  
                                            VECTOR * const currMV,  
                                            const int center_x,  
                                            const int center_y,  
                                            const int32_t min_dx,  
                                            const int32_t max_dx,  
                                            const int32_t min_dy,  
                                            const int32_t max_dy,  
                                            const int32_t iEdgedWidth,  
                                            const int32_t iDiamondSize,  
                                            const int32_t iFcode,  
                                            const int32_t iQuant,  
                                            int iDirection)  
240  {  {
241    // create or find a qpel-precision reference picture; return pointer to it
242            uint8_t * Reference = data->RefQ + 16*dir;
243            const uint32_t iEdgedWidth = data->iEdgedWidth;
244            const uint32_t rounding = data->rounding;
245            const int halfpel_x = x/2;
246            const int halfpel_y = y/2;
247            const uint8_t *ref1, *ref2, *ref3, *ref4;
248    
249          int32_t iSAD;          ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
250            ref1 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
251  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */          switch( ((x&1)<<1) + (y&1) ) {
252            case 3: // x and y in qpel resolution - the "corners" (top left/right and
253          if (iDirection) {                          // bottom left/right) during qpel refinement
254                  CHECK_MV8_CANDIDATE(start_x - iDiamondSize, start_y);                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
255                  CHECK_MV8_CANDIDATE(start_x + iDiamondSize, start_y);                  ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
256                  CHECK_MV8_CANDIDATE(start_x, start_y - iDiamondSize);                  ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);
257                  CHECK_MV8_CANDIDATE(start_x, start_y + iDiamondSize);                  ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
258          } else {                  ref3 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
259                  int bDirection = 1 + 2 + 4 + 8;                  ref4 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
260                    interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
261                  do {                  break;
                         iDirection = 0;  
                         if (bDirection & 1)     //we only want to check left if we came from the right (our last motion was to the left, up-left or down-left)  
                                 CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
   
                         if (bDirection & 2)  
                                 CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
262    
263                          if (bDirection & 4)          case 1: // x halfpel, y qpel - top or bottom during qpel refinement
264                                  CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
265                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
266                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
267                    break;
268    
269                          if (bDirection & 8)          case 2: // x qpel, y halfpel - left or right during qpel refinement
270                                  CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);                  ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
271                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
272                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
273                    break;
274    
275                          /* now we're doing diagonal checks near our candidate */          default: // pure halfpel position
276                    return (uint8_t *) ref1;
277    
                         if (iDirection)         //checking if anything found  
                         {  
                                 bDirection = iDirection;  
                                 iDirection = 0;  
                                 start_x = currMV->x;  
                                 start_y = currMV->y;  
                                 if (bDirection & 3)     //our candidate is left or right  
                                 {  
                                         CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);  
                                 } else                  // what remains here is up or down  
                                 {  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
278                                  }                                  }
279            return Reference;
                                 if (iDirection) {  
                                         bDirection += iDirection;  
                                         start_x = currMV->x;  
                                         start_y = currMV->y;  
280                                  }                                  }
281                          } else                          //about to quit, eh? not so fast....  
282    static uint8_t *
283    Interpolate16x16qpel(const int x, const int y, const uint32_t dir, const SearchData * const data)
284                          {                          {
285                                  switch (bDirection) {  // create or find a qpel-precision reference picture; return pointer to it
286                                  case 2:          uint8_t * Reference = data->RefQ + 16*dir;
287                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,          const uint32_t iEdgedWidth = data->iEdgedWidth;
288                                                                                          start_y - iDiamondSize, 2 + 4);          const uint32_t rounding = data->rounding;
289                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,          const int halfpel_x = x/2;
290                                                                                          start_y + iDiamondSize, 2 + 8);          const int halfpel_y = y/2;
291                                          break;          const uint8_t *ref1, *ref2, *ref3, *ref4;
292                                  case 1:  
293                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,          ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
294                                                                                          start_y - iDiamondSize, 1 + 4);          switch( ((x&1)<<1) + (y&1) ) {
295                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,          case 3: // x and y in qpel resolution - the "corners" (top left/right and
296                                                                                          start_y + iDiamondSize, 1 + 8);                           // bottom left/right) during qpel refinement
297                                          break;                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
298                                  case 2 + 4:                  ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
299                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                  ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);
300                                                                                          start_y - iDiamondSize, 1 + 4);                  interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
301                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                  interpolate8x8_avg4(Reference+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, rounding);
302                                                                                          start_y - iDiamondSize, 2 + 4);                  interpolate8x8_avg4(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, rounding);
303                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                  interpolate8x8_avg4(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, rounding);
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 4:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         break;  
                                 case 8:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 1 + 4:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         break;  
                                 case 2 + 8:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
304                                          break;                                          break;
305                                  case 1 + 8:  
306                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,          case 1: // x halfpel, y qpel - top or bottom during qpel refinement
307                                                                                          start_y - iDiamondSize, 2 + 4);                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
308                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
309                                                                                          start_y + iDiamondSize, 2 + 8);                  interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
310                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                  interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
311                                                                                          start_y + iDiamondSize, 1 + 8);                  interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
312                                          break;                                          break;
313                                  default:                //1+2+4+8 == we didn't find anything at all  
314                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,          case 2: // x qpel, y halfpel - left or right during qpel refinement
315                                                                                          start_y - iDiamondSize, 1 + 4);                  ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
316                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
317                                                                                          start_y + iDiamondSize, 1 + 8);                  interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
318                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                  interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
319                                                                                          start_y - iDiamondSize, 2 + 4);                  interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
320                                          break;                                          break;
321    
322            default: // pure halfpel position
323                    return (uint8_t *) ref1;
324                                  }                                  }
325                                  if (!(iDirection))          return Reference;
                                         break;          //ok, the end. really  
                                 else {  
                                         bDirection = iDirection;  
                                         start_x = currMV->x;  
                                         start_y = currMV->y;  
                                 }  
                         }  
                 }  
                 while (1);                              //forever  
         }  
         return iMinSAD;  
326  }  }
327    
328    /* CHECK_CANDIATE FUNCTIONS START */
329    
330  int32_t  static void
331  Full8_MainSearch(const uint8_t * const pRef,  CheckCandidate16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
332                                   const uint8_t * const pRefH,  {
333                                   const uint8_t * const pRefV,          int xc, yc;
334                                   const uint8_t * const pRefHV,          const uint8_t * Reference;
335                                   const uint8_t * const cur,          VECTOR * current;
336                                   const int x,          int32_t sad; uint32_t t;
                                  const int y,  
                            const int start_x,  
                            const int start_y,  
                            int iMinSAD,  
                            VECTOR * const currMV,  
                            const int center_x,  
                            const int center_y,  
                                  const int32_t min_dx,  
                                  const int32_t max_dx,  
                                  const int32_t min_dy,  
                                  const int32_t max_dy,  
                                  const int32_t iEdgedWidth,  
                                  const int32_t iDiamondSize,  
                                  const int32_t iFcode,  
                                  const int32_t iQuant,  
                                  int iFound)  
 {  
         int32_t iSAD;  
         int32_t dx, dy;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV8_CANDIDATE(dx, dy);  
337    
338          return iMinSAD;          if ( (x > data->max_dx) || (x < data->min_dx)
339  }                  || (y > data->max_dy) || (y < data->min_dy) ) return;
340    
341  Halfpel8_RefineFuncPtr Halfpel8_Refine;          if (!data->qpel_precision) {
342                    Reference = GetReference(x, y, data);
343                    current = data->currentMV;
344                    xc = x; yc = y;
345            } else { // x and y are in 1/4 precision
346                    Reference = Interpolate16x16qpel(x, y, 0, data);
347                    xc = x/2; yc = y/2; //for chroma sad
348                    current = data->currentQMV;
349            }
350    
351  int32_t          sad = sad16v(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
352  Halfpel16_Refine(const uint8_t * const pRef,          t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
                                  const uint8_t * const pRefH,  
                                  const uint8_t * const pRefV,  
                                  const uint8_t * const pRefHV,  
                                  const uint8_t * const cur,  
                                  const int x,  
                                  const int y,  
                                  VECTOR * const currMV,  
                                  int32_t iMinSAD,  
                            const int center_x,  
                            const int center_y,  
                                  const int32_t min_dx,  
                                  const int32_t max_dx,  
                                  const int32_t min_dy,  
                                  const int32_t max_dy,  
                                  const int32_t iFcode,  
                                  const int32_t iQuant,  
                                  const int32_t iEdgedWidth)  
 {  
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
353    
354          int32_t iSAD;          sad += (data->lambda16 * t * sad)>>10;
355          VECTOR backupMV = *currMV;          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;
356    
357          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y - 1);          if (data->chroma) sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
358          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y - 1);                                                                             (yc >> 1) + roundtab_79[yc & 0x3], data);
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y - 1);  
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y + 1);  
         CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y + 1);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y + 1);  
359    
360          return iMinSAD;          if (sad < data->iMinSAD[0]) {
361                    data->iMinSAD[0] = sad;
362                    current[0].x = x; current[0].y = y;
363                    *dir = Direction;
364  }  }
365    
366  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)          if (data->temp[1] < data->iMinSAD[1]) {
367                    data->iMinSAD[1] = data->temp[1]; current[1].x = x; current[1].y = y; }
368            if (data->temp[2] < data->iMinSAD[2]) {
369                    data->iMinSAD[2] = data->temp[2]; current[2].x = x; current[2].y = y; }
370            if (data->temp[3] < data->iMinSAD[3]) {
371                    data->iMinSAD[3] = data->temp[3]; current[3].x = x; current[3].y = y; }
372            if (data->temp[4] < data->iMinSAD[4]) {
373                    data->iMinSAD[4] = data->temp[4]; current[4].x = x; current[4].y = y; }
374    
375    }
376    
377  int32_t  static void
378  PMVfastSearch16(const uint8_t * const pRef,  CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                                 const uint8_t * const pRefH,  
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const IMAGE * const pCur,  
                                 const int x,  
                                 const int y,  
                                 const int start_x,      /* start is searched first, so it should contain the most */  
                                 const int start_y,  /* likely motion vector for this block */  
                                 const int center_x,     /* center is from where length of MVs is measured */  
                                 const int center_y,  
                                 const uint32_t MotionFlags,  
                                 const uint32_t iQuant,  
                                 const uint32_t iFcode,  
                                 const MBParam * const pParam,  
                                 const MACROBLOCK * const pMBs,  
                                 const MACROBLOCK * const prevMBs,  
                                 VECTOR * const currMV,  
                                 VECTOR * const currPMV)  
379  {  {
380          const uint32_t iWcount = pParam->mb_width;          int32_t sad; uint32_t t;
381          const int32_t iWidth = pParam->width;          const uint8_t * Reference;
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
382    
383          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          if ( (x > data->max_dx) || (x < data->min_dx)
384                    || (y > data->max_dy) || (y < data->min_dy) ) return;
385    
386          int32_t iDiamondSize;          if (!data->qpel_precision) Reference = GetReference(x, y, data);
387            else Reference = Interpolate8x8qpel(x, y, 0, 0, data);
388    
389          int32_t min_dx;          sad = sad8(data->Cur, Reference, data->iEdgedWidth);
390          int32_t max_dx;          t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
         int32_t min_dy;  
         int32_t max_dy;  
391    
392          int32_t iFound;          sad += (data->lambda8 * t * (sad+NEIGH_8X8_BIAS))>>10;
393    
394            if (sad < *(data->iMinSAD)) {
395                    *(data->iMinSAD) = sad;
396                    data->currentMV->x = x; data->currentMV->y = y;
397                    *dir = Direction;
398            }
399    }
400    
         VECTOR newMV;  
         VECTOR backupMV;                        /* just for PMVFAST */  
401    
402          VECTOR pmv[4];  static void
403          int32_t psad[4];  CheckCandidate32(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
404    {
405            uint32_t t;
406            const uint8_t * Reference;
407    
408          MainSearch16FuncPtr MainSearchPtr;          if ( (!(x&1) && x !=0) || (!(y&1) && y !=0) || //non-zero even value
409                    (x > data->max_dx) || (x < data->min_dx)
410                    || (y > data->max_dy) || (y < data->min_dy) ) return;
411    
412          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;          Reference = GetReference(x, y, data);
413            t = d_mv_bits(x, y, data->predMV, data->iFcode, 0, 1);
414    
415          int32_t threshA, threshB;          data->temp[0] = sad32v_c(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD;  
416    
417  /* Get maximum range */          data->temp[0] += (data->lambda16 * t * data->temp[0]) >> 10;
418          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;
                           iFcode);  
419    
420  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          if (data->temp[0] < data->iMinSAD[0]) {
421                    data->iMinSAD[0] = data->temp[0];
422                    data->currentMV[0].x = x; data->currentMV[0].y = y;
423                    *dir = Direction; }
424    
425          if (!(MotionFlags & PMV_HALFPEL16)) {          if (data->temp[1] < data->iMinSAD[1]) {
426                  min_dx = EVEN(min_dx);                  data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
427                  max_dx = EVEN(max_dx);          if (data->temp[2] < data->iMinSAD[2]) {
428                  min_dy = EVEN(min_dy);                  data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
429                  max_dy = EVEN(max_dy);          if (data->temp[3] < data->iMinSAD[3]) {
430                    data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
431            if (data->temp[4] < data->iMinSAD[4]) {
432                    data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
433          }          }
434    
435          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  static void
436          //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  CheckCandidate16no4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
437          bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);  {
438            int32_t sad, xc, yc;
439            const uint8_t * Reference;
440            uint32_t t;
441            VECTOR * current;
442    
443          if ((x == 0) && (y == 0)) {          if ( (x > data->max_dx) || ( x < data->min_dx)
444                  threshA = 512;                  || (y > data->max_dy) || (y < data->min_dy) ) return;
445                  threshB = 1024;  
446            if (data->rrv && (!(x&1) && x !=0) | (!(y&1) && y !=0) ) return; //non-zero even value
447    
448            if (data->qpel_precision) { // x and y are in 1/4 precision
449                    Reference = Interpolate16x16qpel(x, y, 0, data);
450                    current = data->currentQMV;
451                    xc = x/2; yc = y/2;
452          } else {          } else {
453                  threshA = psad[0];                  Reference = GetReference(x, y, data);
454                  threshB = threshA + 256;                  current = data->currentMV;
455                  if (threshA < 512)                  xc = x; yc = y;
                         threshA = 512;  
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
456          }          }
457            t = d_mv_bits(x, y, data->predMV, data->iFcode,
458                                            data->qpel^data->qpel_precision, data->rrv);
459    
460          iFound = 0;          sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
461            sad += (data->lambda16 * t * sad)>>10;
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
   
         currMV->x = start_x;  
         currMV->y = start_y;  
462    
463          if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */          if (data->chroma) sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
464                  currMV->x = EVEN(currMV->x);                                                                                  (yc >> 1) + roundtab_79[yc & 0x3], data);
                 currMV->y = EVEN(currMV->y);  
         }  
465    
466          if (currMV->x > max_dx) {          if (sad < *(data->iMinSAD)) {
467                  currMV->x = max_dx;                  *(data->iMinSAD) = sad;
468          }                  current->x = x; current->y = y;
469          if (currMV->x < min_dx) {                  *dir = Direction;
                 currMV->x = min_dx;  
         }  
         if (currMV->y > max_dy) {  
                 currMV->y = max_dy;  
470          }          }
         if (currMV->y < min_dy) {  
                 currMV->y = min_dy;  
471          }          }
472    
473          iMinSAD =  static void
474                  sad16(cur,  CheckCandidate32I(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
475                  {                  {
476                          if (!MVzero(*currMV)) {  // maximum speed - for P/B/I decision
477                                  iMinSAD += MV16_00_BIAS;          int32_t sad;
                                 CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures  
                                 iMinSAD -= MV16_00_BIAS;  
                         }  
                 }  
478    
479                  if (MotionFlags & PMV_QUICKSTOP16)          if ( (x > data->max_dx) || (x < data->min_dx)
480                          goto PMVfast16_Terminate_without_Refine;                  || (y > data->max_dy) || (y < data->min_dy) ) return;
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
         }  
481    
482            sad = sad32v_c(data->Cur, data->Ref + x/2 + (y/2)*(data->iEdgedWidth),
483                                                            data->iEdgedWidth, data->temp+1);
484    
485  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion          if (sad < *(data->iMinSAD)) {
486     vector of the median.                  *(data->iMinSAD) = sad;
487     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2                  data->currentMV[0].x = x; data->currentMV[0].y = y;
488  */                  *dir = Direction;
489            }
490            if (data->temp[1] < data->iMinSAD[1]) {
491                    data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
492            if (data->temp[2] < data->iMinSAD[2]) {
493                    data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
494            if (data->temp[3] < data->iMinSAD[3]) {
495                    data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
496            if (data->temp[4] < data->iMinSAD[4]) {
497                    data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
498    
499          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[0])))  }
                 iFound = 2;  
500    
501  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.  static void
502     Otherwise select large Diamond Search.  CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)
503  */  {
504            int32_t sad, xb, yb, xcf, ycf, xcb, ycb;
505            uint32_t t;
506            const uint8_t *ReferenceF, *ReferenceB;
507            VECTOR *current;
508    
509          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))          if ((xf > data->max_dx) || (xf < data->min_dx) ||
510                  iDiamondSize = 1;               // halfpel!                  (yf > data->max_dy) || (yf < data->min_dy))
511          else                  return;
                 iDiamondSize = 2;               // halfpel!  
512    
513          if (!(MotionFlags & PMV_HALFPELDIAMOND16))          if (!data->qpel_precision) {
514                  iDiamondSize *= 2;                  ReferenceF = GetReference(xf, yf, data);
515                    xb = data->currentMV[1].x; yb = data->currentMV[1].y;
516                    ReferenceB = GetReferenceB(xb, yb, 1, data);
517                    current = data->currentMV;
518                    xcf = xf; ycf = yf;
519                    xcb = xb; ycb = yb;
520            } else {
521                    ReferenceF = Interpolate16x16qpel(xf, yf, 0, data);
522                    xb = data->currentQMV[1].x; yb = data->currentQMV[1].y;
523                    current = data->currentQMV;
524                    ReferenceB = Interpolate16x16qpel(xb, yb, 1, data);
525                    xcf = xf/2; ycf = yf/2;
526                    xcb = xb/2; ycb = yb/2;
527            }
528    
529  /*          t = d_mv_bits(xf, yf, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0)
530     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.                   + d_mv_bits(xb, yb, data->bpredMV, data->iFcode, data->qpel^data->qpel_precision, 0);
    Also calculate (0,0) but do not subtract offset.  
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset.  
 */  
531    
532  // (0,0) is always possible          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
533            sad += (data->lambda16 * t * sad)>>10;
534    
535          if (!MVzero(pmv[0]))          if (data->chroma) sad += ChromaSAD2((xcf >> 1) + roundtab_79[xcf & 0x3],
536                  CHECK_MV16_ZERO;                                                                                  (ycf >> 1) + roundtab_79[ycf & 0x3],
537                                                                                    (xcb >> 1) + roundtab_79[xcb & 0x3],
538                                                                                    (ycb >> 1) + roundtab_79[ycb & 0x3], data);
539    
540  // previous frame MV is always possible          if (sad < *(data->iMinSAD)) {
541                    *(data->iMinSAD) = sad;
542                    current->x = xf; current->y = yf;
543                    *dir = Direction;
544            }
545    }
546    
547          if (!MVzero(prevMB->mvs[0]))  static void
548                  if (!MVequal(prevMB->mvs[0], pmv[0]))  CheckCandidateDirect(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
549                          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);  {
550            int32_t sad = 0, xcf = 0, ycf = 0, xcb = 0, ycb = 0;
551            uint32_t k;
552            const uint8_t *ReferenceF;
553            const uint8_t *ReferenceB;
554            VECTOR mvs, b_mvs;
555    
556  // left neighbour, if allowed          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
557    
558          if (!MVzero(pmv[1]))          for (k = 0; k < 4; k++) {
559                  if (!MVequal(pmv[1], prevMB->mvs[0]))                  mvs.x = data->directmvF[k].x + x;
560                          if (!MVequal(pmv[1], pmv[0])) {                  b_mvs.x = ((x == 0) ?
561                                  if (!(MotionFlags & PMV_HALFPEL16)) {                          data->directmvB[k].x
562                                          pmv[1].x = EVEN(pmv[1].x);                          : mvs.x - data->referencemv[k].x);
563                                          pmv[1].y = EVEN(pmv[1].y);  
564                    mvs.y = data->directmvF[k].y + y;
565                    b_mvs.y = ((y == 0) ?
566                            data->directmvB[k].y
567                            : mvs.y - data->referencemv[k].y);
568    
569                    if ((mvs.x > data->max_dx)   || (mvs.x < data->min_dx)   ||
570                            (mvs.y > data->max_dy)   || (mvs.y < data->min_dy)   ||
571                            (b_mvs.x > data->max_dx) || (b_mvs.x < data->min_dx) ||
572                            (b_mvs.y > data->max_dy) || (b_mvs.y < data->min_dy) )
573                            return;
574    
575                    if (data->qpel) {
576                            xcf += mvs.x/2; ycf += mvs.y/2;
577                            xcb += b_mvs.x/2; ycb += b_mvs.y/2;
578                    } else {
579                            xcf += mvs.x; ycf += mvs.y;
580                            xcb += b_mvs.x; ycb += b_mvs.y;
581                            mvs.x *= 2; mvs.y *= 2; //we move to qpel precision anyway
582                            b_mvs.x *= 2; b_mvs.y *= 2;
583                                  }                                  }
584    
585                                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);                  ReferenceF = Interpolate8x8qpel(mvs.x, mvs.y, k, 0, data);
586                          }                  ReferenceB = Interpolate8x8qpel(b_mvs.x, b_mvs.y, k, 1, data);
 // top neighbour, if allowed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], prevMB->mvs[0]))  
                         if (!MVequal(pmv[2], pmv[0]))  
                                 if (!MVequal(pmv[2], pmv[1])) {  
                                         if (!(MotionFlags & PMV_HALFPEL16)) {  
                                                 pmv[2].x = EVEN(pmv[2].x);  
                                                 pmv[2].y = EVEN(pmv[2].y);  
                                         }  
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
587    
588  // top right neighbour, if allowed                  sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
589                                          if (!MVzero(pmv[3]))                                                  ReferenceF, ReferenceB, data->iEdgedWidth);
590                                                  if (!MVequal(pmv[3], prevMB->mvs[0]))                  if (sad > *(data->iMinSAD)) return;
                                                         if (!MVequal(pmv[3], pmv[0]))  
                                                                 if (!MVequal(pmv[3], pmv[1]))  
                                                                         if (!MVequal(pmv[3], pmv[2])) {  
                                                                                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                                                                                         pmv[3].x = EVEN(pmv[3].x);  
                                                                                         pmv[3].y = EVEN(pmv[3].y);  
591                                                                                  }                                                                                  }
592                                                                                  CHECK_MV16_CANDIDATE(pmv[3].x,  
593                                                                                                                           pmv[3].y);          sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;
594    
595            if (data->chroma) sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],
596                                                                                    (ycf >> 3) + roundtab_76[ycf & 0xf],
597                                                                                    (xcb >> 3) + roundtab_76[xcb & 0xf],
598                                                                                    (ycb >> 3) + roundtab_76[ycb & 0xf], data);
599    
600            if (sad < *(data->iMinSAD)) {
601                    *(data->iMinSAD) = sad;
602                    data->currentMV->x = x; data->currentMV->y = y;
603                    *dir = Direction;
604                                                                          }                                                                          }
605                                  }                                  }
606    
607          if ((MVzero(*currMV)) &&  static void
608                  (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  CheckCandidateDirectno4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
609                  iMinSAD -= MV16_00_BIAS;  {
610            int32_t sad, xcf, ycf, xcb, ycb;
611            const uint8_t *ReferenceF;
612            const uint8_t *ReferenceB;
613            VECTOR mvs, b_mvs;
614    
615            if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
616    
617  /* Step 6: If MinSAD <= thresa goto Step 10.          mvs.x = data->directmvF[0].x + x;
618     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.          b_mvs.x = ((x == 0) ?
619  */                  data->directmvB[0].x
620                    : mvs.x - data->referencemv[0].x);
621    
622          if ((iMinSAD <= threshA) ||          mvs.y = data->directmvF[0].y + y;
623                  (MVequal(*currMV, prevMB->mvs[0]) &&          b_mvs.y = ((y == 0) ?
624                   ((int32_t) iMinSAD < prevMB->sad16))) {                  data->directmvB[0].y
625                  if (MotionFlags & PMV_QUICKSTOP16)                  : mvs.y - data->referencemv[0].y);
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
         }  
626    
627            if ( (mvs.x > data->max_dx) || (mvs.x < data->min_dx)
628                    || (mvs.y > data->max_dy) || (mvs.y < data->min_dy)
629                    || (b_mvs.x > data->max_dx) || (b_mvs.x < data->min_dx)
630                    || (b_mvs.y > data->max_dy) || (b_mvs.y < data->min_dy) ) return;
631    
632  /************ (Diamond Search)  **************/          if (data->qpel) {
633  /*                  xcf = 4*(mvs.x/2); ycf = 4*(mvs.y/2);
634     Step 7: Perform Diamond search, with either the small or large diamond.                  xcb = 4*(b_mvs.x/2); ycb = 4*(b_mvs.y/2);
635     If Found=2 only examine one Diamond pattern, and afterwards goto step 10                  ReferenceF = Interpolate16x16qpel(mvs.x, mvs.y, 0, data);
636     Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.                  ReferenceB = Interpolate16x16qpel(b_mvs.x, b_mvs.y, 1, data);
637     If center then goto step 10.          } else {
638     Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.                  xcf = 4*mvs.x; ycf = 4*mvs.y;
639     Refine by using small diamond and goto step 10.                  xcb = 4*b_mvs.x; ycb = 4*b_mvs.y;
640  */                  ReferenceF = GetReference(mvs.x, mvs.y, data);
641                    ReferenceB = GetReferenceB(b_mvs.x, b_mvs.y, 1, data);
642            }
643    
644          if (MotionFlags & PMV_USESQUARES16)          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
645                  MainSearchPtr = Square16_MainSearch;          sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
646    
647          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          if (data->chroma) sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],
648                                                                                    (ycf >> 3) + roundtab_76[ycf & 0xf],
649                                                                                    (xcb >> 3) + roundtab_76[xcb & 0xf],
650                                                                                    (ycb >> 3) + roundtab_76[ycb & 0xf], data);
651    
652            if (sad < *(data->iMinSAD)) {
653                    *(data->iMinSAD) = sad;
654                    data->currentMV->x = x; data->currentMV->y = y;
655                    *dir = Direction;
656            }
657    }
658    
 /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                   currMV->x, currMV->y, iMinSAD, &newMV, center_x, center_y,  
                                                   min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
659    
660          if (iSAD < iMinSAD) {  static void
661                  *currMV = newMV;  CheckCandidateBits16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
662                  iMinSAD = iSAD;  {
         }  
663    
664          if (MotionFlags & PMV_EXTSEARCH16) {          int16_t *in = data->dctSpace, *coeff = data->dctSpace + 64;
665  /* extended: search (up to) two more times: orignal prediction and (0,0) */          int32_t bits = 0, sum;
666            VECTOR * current;
667            const uint8_t * ptr;
668            int i, cbp = 0, t, xc, yc;
669    
670                  if (!(MVequal(pmv[0], backupMV))) {          if ( (x > data->max_dx) || (x < data->min_dx)
671                          iSAD =                  || (y > data->max_dy) || (y < data->min_dy) ) return;
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                                   center_x, center_y, iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
672    
673                          if (iSAD < iMinSAD) {          if (!data->qpel_precision) {
674                                  *currMV = newMV;                  ptr = GetReference(x, y, data);
675                                  iMinSAD = iSAD;                  current = data->currentMV;
676                    xc = x; yc = y;
677            } else { // x and y are in 1/4 precision
678                    ptr = Interpolate16x16qpel(x, y, 0, data);
679                    current = data->currentQMV;
680                    xc = x/2; yc = y/2;
681                          }                          }
682    
683            for(i = 0; i < 4; i++) {
684                    int s = 8*((i&1) + (i>>1)*data->iEdgedWidth);
685                    transfer_8to16subro(in, data->Cur + s, ptr + s, data->iEdgedWidth);
686                    fdct(in);
687                    if (data->lambda8 == 0) sum = quant_inter(coeff, in, data->lambda16);
688                    else sum = quant4_inter(coeff, in, data->lambda16);
689                    if (sum > 0) {
690                            cbp |= 1 << (5 - i);
691                            bits += data->temp[i] = CodeCoeffInter_CalcBits(coeff, scan_tables[0]);
692                    } else data->temp[i] = 0;
693                  }                  }
694    
695                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          bits += t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
696                          iSAD =  
697                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,          if (bits < data->iMinSAD[0]) { // there is still a chance, adding chroma
698                                                                    iMinSAD, &newMV, center_x, center_y,                  xc = (xc >> 1) + roundtab_79[xc & 0x3];
699                                                                    min_dx, max_dx, min_dy, max_dy,                  yc = (yc >> 1) + roundtab_79[yc & 0x3];
                                                                   iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
700    
701                          if (iSAD < iMinSAD) {                  //chroma U
702                                  *currMV = newMV;                  ptr = interpolate8x8_switch2(data->RefQ + 64, data->RefCU, 0, 0, xc, yc,  data->iEdgedWidth/2, data->rounding);
703                                  iMinSAD = iSAD;                  transfer_8to16subro(in, ptr, data->CurU, data->iEdgedWidth/2);
704                    fdct(in);
705                    if (data->lambda8 == 0) sum = quant_inter(coeff, in, data->lambda16);
706                    else sum = quant4_inter(coeff, in, data->lambda16);
707                    if (sum > 0) {
708                            cbp |= 1 << (5 - 4);
709                            bits += CodeCoeffInter_CalcBits(coeff, scan_tables[0]);
710                    }
711    
712                    if (bits < data->iMinSAD[0]) {
713                            //chroma V
714                            ptr = interpolate8x8_switch2(data->RefQ + 64, data->RefCV, 0, 0, xc, yc,  data->iEdgedWidth/2, data->rounding);
715                            transfer_8to16subro(in, ptr, data->CurV, data->iEdgedWidth/2);
716                            fdct(in);
717                            if (data->lambda8 == 0) sum = quant_inter(coeff, in, data->lambda16);
718                            else sum = quant4_inter(coeff, in, data->lambda16);
719                            if (sum > 0) {
720                                    cbp |= 1 << (5 - 5);
721                                    bits += CodeCoeffInter_CalcBits(coeff, scan_tables[0]);
722                          }                          }
723                  }                  }
724          }          }
725    
726  /*          bits += xvid_cbpy_tab[15-(cbp>>2)].len;
727     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.          bits += mcbpc_inter_tab[(MODE_INTER & 7) | ((cbp & 3) << 3)].len;
 */  
   
   PMVfast16_Terminate_with_Refine:  
         if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step  
                 iMinSAD =  
                         Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
728    
729    PMVfast16_Terminate_without_Refine:          if (bits < data->iMinSAD[0]) {
730          currPMV->x = currMV->x - center_x;                  data->iMinSAD[0] = bits;
731          currPMV->y = currMV->y - center_y;                  current[0].x = x; current[0].y = y;
732          return iMinSAD;                  *dir = Direction;
733  }  }
734    
735            if (data->temp[0] + t < data->iMinSAD[1]) {
736                    data->iMinSAD[1] = data->temp[0] + t; current[1].x = x; current[1].y = y; }
737            if (data->temp[1] < data->iMinSAD[2]) {
738                    data->iMinSAD[2] = data->temp[1]; current[2].x = x; current[2].y = y; }
739            if (data->temp[2] < data->iMinSAD[3]) {
740                    data->iMinSAD[3] = data->temp[2]; current[3].x = x; current[3].y = y; }
741            if (data->temp[3] < data->iMinSAD[4]) {
742                    data->iMinSAD[4] = data->temp[3]; current[4].x = x; current[4].y = y; }
743    
744    }
745    static void
746    CheckCandidateBits8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
747    {
748    
749            int16_t *in = data->dctSpace, *coeff = data->dctSpace + 64;
750            int32_t sum, bits;
751            VECTOR * current;
752            const uint8_t * ptr;
753            int cbp;
754    
755            if ( (x > data->max_dx) || (x < data->min_dx)
756                    || (y > data->max_dy) || (y < data->min_dy) ) return;
757    
758            if (!data->qpel_precision) {
759                    ptr = GetReference(x, y, data);
760                    current = data->currentMV;
761            } else { // x and y are in 1/4 precision
762                    ptr = Interpolate8x8qpel(x, y, 0, 0, data);
763                    current = data->currentQMV;
764            }
765    
766  int32_t          transfer_8to16subro(in, data->Cur, ptr, data->iEdgedWidth);
767  Diamond8_MainSearch(const uint8_t * const pRef,          fdct(in);
768                                          const uint8_t * const pRefH,          if (data->lambda8 == 0) sum = quant_inter(coeff, in, data->lambda16);
769                                          const uint8_t * const pRefV,          else sum = quant4_inter(coeff, in, data->lambda16);
770                                          const uint8_t * const pRefHV,          if (sum > 0) {
771                                          const uint8_t * const cur,                  bits = CodeCoeffInter_CalcBits(coeff, scan_tables[0]);
772                                          const int x,                  cbp = 1;
773                                          const int y,          } else cbp = bits = 0;
                                         int32_t start_x,  
                                         int32_t start_y,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iDirectionBackup;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
774    
775          if (iDirection) {          bits += sum = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
776                  while (!iFound) {  
777                          iFound = 1;          if (bits < data->iMinSAD[0]) {
778                          backupMV = *currMV;     // since iDirection!=0, this is well defined!                  data->temp[0] = cbp;
779                          iDirectionBackup = iDirection;                  data->iMinSAD[0] = bits;
780                    current[0].x = x; current[0].y = y;
781                          if (iDirectionBackup != 2)                  *dir = Direction;
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                   backupMV.y, 1);  
                         if (iDirectionBackup != 1)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                   backupMV.y, 2);  
                         if (iDirectionBackup != 4)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y - iDiamondSize, 3);  
                         if (iDirectionBackup != 3)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y + iDiamondSize, 4);  
                 }  
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
782          }          }
         return iMinSAD;  
783  }  }
784    
785    /* CHECK_CANDIATE FUNCTIONS END */
786    
787    /* MAINSEARCH FUNCTIONS START */
788    
789    static void
790    AdvDiamondSearch(int x, int y, const SearchData * const data, int bDirection)
791    {
792    
793  int32_t  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
 Square8_MainSearch(const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x,  
                                         const int y,  
                                         int32_t start_x,  
                                         int32_t start_y,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a square search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* It's one search with full square pattern, and new parts for all following diamonds */  
   
 /*   new direction are extra, so 1-4 is normal diamond  
       537  
       1*2  
       648  
 */  
794    
795          CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);          int iDirection;
         CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
   
         CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 5);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 6);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 7);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 8);  
796    
797            for(;;) { //forever
798                    iDirection = 0;
799                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
800                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
801                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
802                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
803    
804          if (iDirection) {                  /* now we're doing diagonal checks near our candidate */
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;  
805    
806                          switch (iDirection) {                  if (iDirection) {               //if anything found
807                          case 1:                          bDirection = iDirection;
808                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          iDirection = 0;
809                                                                                     backupMV.y, 1);                          x = data->currentMV->x; y = data->currentMV->y;
810                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          if (bDirection & 3) {   //our candidate is left or right
811                                                                                   backupMV.y - iDiamondSize, 5);                                  CHECK_CANDIDATE(x, y + iDiamondSize, 8);
812                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                                  CHECK_CANDIDATE(x, y - iDiamondSize, 4);
813                                                                                   backupMV.y - iDiamondSize, 7);                          } else {                        // what remains here is up or down
814                                  break;                                  CHECK_CANDIDATE(x + iDiamondSize, y, 2);
815                                    CHECK_CANDIDATE(x - iDiamondSize, y, 1);
816                            }
817    
818                            if (iDirection) {
819                                    bDirection += iDirection;
820                                    x = data->currentMV->x; y = data->currentMV->y;
821                            }
822                    } else {                                //about to quit, eh? not so fast....
823                            switch (bDirection) {
824                          case 2:                          case 2:
825                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
826                                                                                   2);                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
827                                  break;                                  break;
828                            case 1:
829                          case 3:                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
830                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                                                                  4);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
831                                  break;                                  break;
832                            case 2 + 4:
833                          case 4:                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
834                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
835                                                                                   3);                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 break;  
   
                         case 5:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
   
                         case 6:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
   
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
   
836                                  break;                                  break;
837                            case 4:
838                          case 7:                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
839                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
                                                                                    backupMV.y, 1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
840                                  break;                                  break;
   
841                          case 8:                          case 8:
842                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
843                                                                                   2);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
844                                  break;                                  break;
845                          default:                          case 1 + 4:
846                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
847                                                                                   1);                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
848                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
849                                                                                   2);                                  break;
850                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,                          case 2 + 8:
851                                                                                   3);                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
852                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
853                                                                                   4);                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
854                                    break;
855                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          case 1 + 8:
856                                                                                   backupMV.y - iDiamondSize, 5);                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
857                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
858                                                                                   backupMV.y + iDiamondSize, 6);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
859                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                                  break;
860                                                                                   backupMV.y - iDiamondSize, 7);                          default:                //1+2+4+8 == we didn't find anything at all
861                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
862                                                                                   backupMV.y + iDiamondSize, 8);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
863                                    CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
864                                    CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
865                                  break;                                  break;
866                          }                          }
867                            if (!iDirection) break;         //ok, the end. really
868                            bDirection = iDirection;
869                            x = data->currentMV->x; y = data->currentMV->y;
870                  }                  }
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
871          }          }
         return iMinSAD;  
872  }  }
873    
874    static void
875    SquareSearch(int x, int y, const SearchData * const data, int bDirection)
876    {
877            int iDirection;
878    
879            do {
880                    iDirection = 0;
881                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);
882                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);
883                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);
884                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128);
885                    if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64);
886                    if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128);
887                    if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128);
888                    if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128);
889    
890                    bDirection = iDirection;
891                    x = data->currentMV->x; y = data->currentMV->y;
892  int32_t          } while (iDirection);
 Halfpel8_Refine_c(const uint8_t * const pRef,  
                                 const uint8_t * const pRefH,  
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const uint8_t * const cur,  
                                 const int x,  
                                 const int y,  
                                 VECTOR * const currMV,  
                                 int32_t iMinSAD,  
                            const int center_x,  
                            const int center_y,  
                                 const int32_t min_dx,  
                                 const int32_t max_dx,  
                                 const int32_t min_dy,  
                                 const int32_t max_dy,  
                                 const int32_t iFcode,  
                                 const int32_t iQuant,  
                                 const int32_t iEdgedWidth)  
 {  
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
   
         int32_t iSAD;  
         VECTOR backupMV = *currMV;  
   
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y + 1);  
         CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y + 1);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y + 1);  
   
         return iMinSAD;  
893  }  }
894    
895    static void
896  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)  DiamondSearch(int x, int y, const SearchData * const data, int bDirection)
   
 int32_t  
 PMVfastSearch8(const uint8_t * const pRef,  
                            const uint8_t * const pRefH,  
                            const uint8_t * const pRefV,  
                            const uint8_t * const pRefHV,  
                            const IMAGE * const pCur,  
                            const int x,  
                            const int y,  
                            const int start_x,  
                            const int start_y,  
                                 const int center_x,  
                                 const int center_y,  
                            const uint32_t MotionFlags,  
                            const uint32_t iQuant,  
                            const uint32_t iFcode,  
                            const MBParam * const pParam,  
                            const MACROBLOCK * const pMBs,  
                            const MACROBLOCK * const prevMBs,  
                            VECTOR * const currMV,  
                            VECTOR * const currPMV)  
897  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
898    
899          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
900    
901            int iDirection;
902    
903          int32_t iDiamondSize;          do {
904                    iDirection = 0;
905                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
906                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
907                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
908                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
909    
910          int32_t min_dx;                  /* now we're doing diagonal checks near our candidate */
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
911    
912          VECTOR pmv[4];                  if (iDirection) {               //checking if anything found
913          int32_t psad[4];                          bDirection = iDirection;
914          VECTOR newMV;                          iDirection = 0;
915          VECTOR backupMV;                          x = data->currentMV->x; y = data->currentMV->y;
916          VECTOR startMV;                          if (bDirection & 3) {   //our candidate is left or right
917                                    CHECK_CANDIDATE(x, y + iDiamondSize, 8);
918                                    CHECK_CANDIDATE(x, y - iDiamondSize, 4);
919                            } else {                        // what remains here is up or down
920                                    CHECK_CANDIDATE(x + iDiamondSize, y, 2);
921                                    CHECK_CANDIDATE(x - iDiamondSize, y, 1);
922                            }
923                            bDirection += iDirection;
924                            x = data->currentMV->x; y = data->currentMV->y;
925                    }
926            }
927            while (iDirection);
928    }
929    
930  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;  /* MAINSEARCH FUNCTIONS END */
         const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;  
931    
932           int32_t threshA, threshB;  static void
933          int32_t iFound, bPredEq;  SubpelRefine(const SearchData * const data)
934          int32_t iMinSAD, iSAD;  {
935    /* Do a half-pel or q-pel refinement */
936            const VECTOR centerMV = data->qpel_precision ? *data->currentQMV : *data->currentMV;
937            int iDirection; //only needed because macro expects it
938    
939          int32_t iSubBlock = (y & 1) + (y & 1) + (x & 1);          CHECK_CANDIDATE(centerMV.x, centerMV.y - 1, 0);
940            CHECK_CANDIDATE(centerMV.x + 1, centerMV.y - 1, 0);
941            CHECK_CANDIDATE(centerMV.x + 1, centerMV.y, 0);
942            CHECK_CANDIDATE(centerMV.x + 1, centerMV.y + 1, 0);
943            CHECK_CANDIDATE(centerMV.x, centerMV.y + 1, 0);
944            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y + 1, 0);
945            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y, 0);
946            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y - 1, 0);
947    }
948    
949          MainSearch8FuncPtr MainSearchPtr;  static __inline int
950    SkipDecisionP(const IMAGE * current, const IMAGE * reference,
951                                                            const int x, const int y,
952                                                            const uint32_t stride, const uint32_t iQuant, int rrv)
953    
954          /* Init variables */  {
955          startMV.x = start_x;          int offset = (x + y*stride)*8;
956          startMV.y = start_y;          if(!rrv) {
957                    uint32_t sadC = sad8(current->u + offset,
958                                                    reference->u + offset, stride);
959                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
960                    sadC += sad8(current->v + offset,
961                                                    reference->v + offset, stride);
962                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
963                    return 1;
964    
965          /* Get maximum range */          } else {
966          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,                  uint32_t sadC = sad16(current->u + 2*offset,
967                            iFcode);                                                  reference->u + 2*offset, stride, 256*4096);
968                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
969                    sadC += sad16(current->v + 2*offset,
970                                                    reference->v + 2*offset, stride, 256*4096);
971                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
972                    return 1;
973            }
974    }
975    
976          if (!(MotionFlags & PMV_HALFPELDIAMOND8)) {  static __inline void
977                  min_dx = EVEN(min_dx);  SkipMacroblockP(MACROBLOCK *pMB, const int32_t sad)
978                  max_dx = EVEN(max_dx);  {
979                  min_dy = EVEN(min_dy);          pMB->mode = MODE_NOT_CODED;
980                  max_dy = EVEN(max_dy);          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = zeroMV;
981            pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] = pMB->qmvs[3] = zeroMV;
982            pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
983          }          }
984    
985          /* because we might use IF (dx>max_dx) THEN dx=max_dx; */  bool
986          //bPredEq = get_pmvdata(pMBs, (x >> 1), (y >> 1), iWcount, iSubBlock, pmv, psad);  MotionEstimation(MBParam * const pParam,
987          bPredEq = get_pmvdata2(pMBs, iWcount, 0, (x >> 1), (y >> 1), iSubBlock, pmv, psad);                                   FRAMEINFO * const current,
988                                     FRAMEINFO * const reference,
989                                     const IMAGE * const pRefH,
990                                     const IMAGE * const pRefV,
991                                     const IMAGE * const pRefHV,
992                                     const uint32_t iLimit)
993    {
994            MACROBLOCK *const pMBs = current->mbs;
995            const IMAGE *const pCurrent = &current->image;
996            const IMAGE *const pRef = &reference->image;
997    
998            uint32_t mb_width = pParam->mb_width;
999            uint32_t mb_height = pParam->mb_height;
1000            const uint32_t iEdgedWidth = pParam->edged_width;
1001            const uint32_t MotionFlags = MakeGoodMotionFlags(current->motion_flags, current->vop_flags, current->vol_flags);
1002    
1003            uint32_t x, y;
1004            uint32_t iIntra = 0;
1005            int32_t quant = current->quant, sad00;
1006            int skip_thresh = \
1007                    INITIAL_SKIP_THRESH * \
1008                    (current->vop_flags & XVID_VOP_REDUCED ? 4:1) * \
1009                    (current->vop_flags & XVID_VOP_MODEDECISION_BITS ? 2:1);
1010    
1011            // some pre-initialized thingies for SearchP
1012            int32_t temp[8];
1013            VECTOR currentMV[5];
1014            VECTOR currentQMV[5];
1015            int32_t iMinSAD[5];
1016            DECLARE_ALIGNED_MATRIX(dct_space, 2, 64, int16_t, CACHE_LINE);
1017            SearchData Data;
1018            memset(&Data, 0, sizeof(SearchData));
1019            Data.iEdgedWidth = iEdgedWidth;
1020            Data.currentMV = currentMV;
1021            Data.currentQMV = currentQMV;
1022            Data.iMinSAD = iMinSAD;
1023            Data.temp = temp;
1024            Data.iFcode = current->fcode;
1025            Data.rounding = pParam->m_rounding_type;
1026            Data.qpel = (current->vol_flags & XVID_VOL_QUARTERPEL ? 1:0);
1027            Data.chroma = MotionFlags & XVID_ME_CHROMA16;
1028            Data.rrv = (current->vop_flags & XVID_VOP_REDUCED ? 1:0);
1029            Data.dctSpace = dct_space;
1030    
1031            if ((current->vop_flags & XVID_VOP_REDUCED)) {
1032                    mb_width = (pParam->width + 31) / 32;
1033                    mb_height = (pParam->height + 31) / 32;
1034                    Data.qpel = 0;
1035            }
1036    
1037            Data.RefQ = pRefV->u; // a good place, also used in MC (for similar purpose)
1038            if (sadInit) (*sadInit) ();
1039    
1040            for (y = 0; y < mb_height; y++) {
1041                    for (x = 0; x < mb_width; x++)  {
1042                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1043    
1044                            if (!Data.rrv) pMB->sad16 =
1045                                    sad16v(pCurrent->y + (x + y * iEdgedWidth) * 16,
1046                                                            pRef->y + (x + y * iEdgedWidth) * 16,
1047                                                            pParam->edged_width, pMB->sad8 );
1048    
1049                            else pMB->sad16 =
1050                                    sad32v_c(pCurrent->y + (x + y * iEdgedWidth) * 32,
1051                                                            pRef->y + (x + y * iEdgedWidth) * 32,
1052                                                            pParam->edged_width, pMB->sad8 );
1053    
1054                            if (Data.chroma) {
1055                                    Data.temp[7] = sad8(pCurrent->u + x*8 + y*(iEdgedWidth/2)*8,
1056                                                                            pRef->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2)
1057                                                                    + sad8(pCurrent->v + (x + y*(iEdgedWidth/2))*8,
1058                                                                            pRef->v + (x + y*(iEdgedWidth/2))*8, iEdgedWidth/2);
1059                                    pMB->sad16 += Data.temp[7];
1060                            }
1061    
1062                            sad00 = pMB->sad16;
1063    
1064                            if (pMB->dquant != 0) {
1065                                    quant += DQtab[pMB->dquant];
1066                                    if (quant > 31) quant = 31;
1067                                    else if (quant < 1) quant = 1;
1068                            }
1069    
1070                            pMB->quant = current->quant;
1071    
1072    //initial skip decision
1073    /* no early skip for GMC (global vector = skip vector is unknown!)  */
1074                            if (!(current->vol_flags & XVID_VOL_GMC))       { /* no fast SKIP for S(GMC)-VOPs */
1075                                    if (pMB->dquant == 0 && sad00 < pMB->quant * skip_thresh)
1076                                            if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, iEdgedWidth/2, pMB->quant, Data.rrv)) {
1077                                                    SkipMacroblockP(pMB, sad00);
1078                                                    continue;
1079                                            }
1080                            }
1081    
1082          if ((x == 0) && (y == 0)) {                          SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1083                  threshA = 512 / 4;                                                  y, MotionFlags, current->vol_flags, pMB->quant,
1084                  threshB = 1024 / 4;                                                  &Data, pParam, pMBs, reference->mbs,
1085                                                    current->vop_flags & XVID_VOP_INTER4V, pMB);
1086    
1087          } else {  /* final skip decision, a.k.a. "the vector you found, really that good?" */
1088                  threshA = psad[0] / 4;  /* good estimate? */                          if (!(current->vol_flags & XVID_VOL_GMC || current->vop_flags & XVID_VOP_MODEDECISION_BITS)) {
1089                  threshB = threshA + 256 / 4;                                  if ( pMB->dquant == 0 && sad00 < pMB->quant * MAX_SAD00_FOR_SKIP) {
1090                  if (threshA < 512 / 4)                                          if ( (100*pMB->sad16)/(sad00+1) > FINAL_SKIP_THRESH * (Data.rrv ? 4:1) )
1091                          threshA = 512 / 4;                                                  if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, iEdgedWidth/2, pMB->quant, Data.rrv))
1092                  if (threshA > 1024 / 4)                                                          SkipMacroblockP(pMB, sad00);
1093                          threshA = 1024 / 4;                                  }
1094                  if (threshB > 1792 / 4)                          }
1095                          threshB = 1792 / 4;                          if (pMB->mode == MODE_INTRA)
1096          }                                  if (++iIntra > iLimit) return 1;
1097                    }
1098          iFound = 0;          }
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
1099    
1100            if (current->vol_flags & XVID_VOL_GMC ) /* GMC only for S(GMC)-VOPs */
1101                    current->warp = GlobalMotionEst( pMBs, pParam, current, reference, pRefH, pRefV, pRefHV);
1102    
1103  // Prepare for main loop          return 0;
1104    }
1105    
   if (MotionFlags & PMV_USESQUARES8)  
       MainSearchPtr = Square8_MainSearch;  
   else  
1106    
1107          if (MotionFlags & PMV_ADVANCEDDIAMOND8)  static __inline int
1108                  MainSearchPtr = AdvDiamond8_MainSearch;  make_mask(const VECTOR * const pmv, const int i)
1109          else  {
1110                  MainSearchPtr = Diamond8_MainSearch;          int mask = 255, j;
1111            for (j = 0; j < i; j++) {
1112                    if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already
1113                    if (pmv[i].x == pmv[j].x) {
1114                            if (pmv[i].y == pmv[j].y + iDiamondSize) mask &= ~4;
1115                            else if (pmv[i].y == pmv[j].y - iDiamondSize) mask &= ~8;
1116                    } else
1117                            if (pmv[i].y == pmv[j].y) {
1118                                    if (pmv[i].x == pmv[j].x + iDiamondSize) mask &= ~1;
1119                                    else if (pmv[i].x == pmv[j].x - iDiamondSize) mask &= ~2;
1120                            }
1121            }
1122            return mask;
1123    }
1124    
1125    static __inline void
1126    PreparePredictionsP(VECTOR * const pmv, int x, int y, int iWcount,
1127                            int iHcount, const MACROBLOCK * const prevMB, int rrv)
1128    {
1129    
1130          *currMV = startMV;  //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself
1131            if (rrv) { iWcount /= 2; iHcount /= 2; }
1132    
1133          iMinSAD =          if ( (y != 0) && (x < (iWcount-1)) ) {          // [5] top-right neighbour
1134                  sad8(cur,                  pmv[5].x = EVEN(pmv[3].x);
1135                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,                  pmv[5].y = EVEN(pmv[3].y);
1136                                                  iEdgedWidth), iEdgedWidth);          } else pmv[5].x = pmv[5].y = 0;
         iMinSAD +=  
                 calc_delta_8(currMV->x - center_x, currMV->y - center_y,  
                                          (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256 / 4) || ((MVequal(*currMV, prevMB->mvs[iSubBlock]))  
                                                                 && ((int32_t) iMinSAD <  
                                                                         prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  
    vector of the median.  
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
1137    
1138          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[iSubBlock])))          if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }// pmv[3] is left neighbour
1139                  iFound = 2;          else pmv[3].x = pmv[3].y = 0;
1140    
1141  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }// [4] top neighbour
1142     Otherwise select large Diamond Search.          else pmv[4].x = pmv[4].y = 0;
 */  
1143    
1144          if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))          // [1] median prediction
1145                  iDiamondSize = 1;               // 1 halfpel!          pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
         else  
                 iDiamondSize = 2;               // 2 halfpel = 1 full pixel!  
1146    
1147          if (!(MotionFlags & PMV_HALFPELDIAMOND8))          pmv[0].x = pmv[0].y = 0; // [0] is zero; not used in the loop (checked before) but needed here for make_mask
                 iDiamondSize *= 2;  
1148    
1149            pmv[2].x = EVEN(prevMB->mvs[0].x); // [2] is last frame
1150            pmv[2].y = EVEN(prevMB->mvs[0].y);
1151    
1152  /*          if ((x < iWcount-1) && (y < iHcount-1)) {
1153     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.                  pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); //[6] right-down neighbour in last frame
1154     Also calculate (0,0) but do not subtract offset.                  pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
1155     Let MinSAD be the smallest SAD up to this point.          } else pmv[6].x = pmv[6].y = 0;
    If MV is (0,0) subtract offset.  
 */  
1156    
1157  // the median prediction might be even better than mv16          if (rrv) {
1158                    int i;
1159                    for (i = 0; i < 7; i++) {
1160                            pmv[i].x = RRV_MV_SCALEUP(pmv[i].x);
1161                            pmv[i].y = RRV_MV_SCALEUP(pmv[i].y);
1162                    }
1163            }
1164    }
1165    
1166          if (!MVequal(pmv[0], startMV))  static int
1167                  CHECK_MV8_CANDIDATE(center_x, center_y);  ModeDecision(const uint32_t iQuant, SearchData * const Data,
1168                    int inter4v,
1169                    MACROBLOCK * const pMB,
1170                    const MACROBLOCK * const pMBs,
1171                    const int x, const int y,
1172                    const MBParam * const pParam,
1173                    const uint32_t MotionFlags,
1174                    const uint32_t VopFlags)
1175    {
1176    
1177  // (0,0) if needed          int mode = MODE_INTER;
         if (!MVzero(pmv[0]))  
                 if (!MVzero(startMV))  
                         CHECK_MV8_ZERO;  
   
 // previous frame MV if needed  
         if (!MVzero(prevMB->mvs[iSubBlock]))  
                 if (!MVequal(prevMB->mvs[iSubBlock], startMV))  
                         if (!MVequal(prevMB->mvs[iSubBlock], pmv[0]))  
                                 CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x,  
                                                                         prevMB->mvs[iSubBlock].y);  
   
         if ((iMinSAD <= threshA) ||  
                 (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&  
                  ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 // left neighbour, if allowed and needed  
         if (!MVzero(pmv[1]))  
                 if (!MVequal(pmv[1], startMV))  
                         if (!MVequal(pmv[1], prevMB->mvs[iSubBlock]))  
                                 if (!MVequal(pmv[1], pmv[0])) {  
                                         if (!(MotionFlags & PMV_HALFPEL8)) {  
                                                 pmv[1].x = EVEN(pmv[1].x);  
                                                 pmv[1].y = EVEN(pmv[1].y);  
                                         }  
                                         CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);  
                                 }  
 // top neighbour, if allowed and needed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], startMV))  
                         if (!MVequal(pmv[2], prevMB->mvs[iSubBlock]))  
                                 if (!MVequal(pmv[2], pmv[0]))  
                                         if (!MVequal(pmv[2], pmv[1])) {  
                                                 if (!(MotionFlags & PMV_HALFPEL8)) {  
                                                         pmv[2].x = EVEN(pmv[2].x);  
                                                         pmv[2].y = EVEN(pmv[2].y);  
                                                 }  
                                                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed and needed  
                                                 if (!MVzero(pmv[3]))  
                                                         if (!MVequal(pmv[3], startMV))  
                                                                 if (!MVequal(pmv[3], prevMB->mvs[iSubBlock]))  
                                                                         if (!MVequal(pmv[3], pmv[0]))  
                                                                                 if (!MVequal(pmv[3], pmv[1]))  
                                                                                         if (!MVequal(pmv[3], pmv[2])) {  
                                                                                                 if (!  
                                                                                                         (MotionFlags &  
                                                                                                          PMV_HALFPEL8)) {  
                                                                                                         pmv[3].x = EVEN(pmv[3].x);  
                                                                                                         pmv[3].y = EVEN(pmv[3].y);  
                                                                                                 }  
                                                                                                 CHECK_MV8_CANDIDATE(pmv[3].x,  
                                                                                                                                         pmv[3].y);  
                                                                                         }  
                                         }  
   
         if ((MVzero(*currMV)) &&  
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV8_00_BIAS;  
1178    
1179            if (!(VopFlags & XVID_VOP_MODEDECISION_BITS)) { //normal, fast, SAD-based mode decision
1180                    int sad;
1181                    int InterBias = MV16_INTER_BIAS;
1182                    if (inter4v == 0 || Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
1183                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant) {
1184                            mode = MODE_INTER;
1185                            sad = Data->iMinSAD[0];
1186                    } else {
1187                            mode = MODE_INTER4V;
1188                            sad = Data->iMinSAD[1] + Data->iMinSAD[2] +
1189                                                    Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant;
1190                            Data->iMinSAD[0] = sad;
1191                    }
1192    
1193  /* Step 6: If MinSAD <= thresa goto Step 10.                  /* intra decision */
    If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
 */  
1194    
1195          if ((iMinSAD <= threshA) ||                  if (iQuant > 8) InterBias += 100 * (iQuant - 8); // to make high quants work
1196                  (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&                  if (y != 0)
1197                   ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {                          if ((pMB - pParam->mb_width)->mode == MODE_INTRA ) InterBias -= 80;
1198                  if (MotionFlags & PMV_QUICKSTOP16)                  if (x != 0)
1199                          goto PMVfast8_Terminate_without_Refine;                          if ((pMB - 1)->mode == MODE_INTRA ) InterBias -= 80;
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 /************ (Diamond Search)  **************/  
 /*  
    Step 7: Perform Diamond search, with either the small or large diamond.  
    If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
    Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
    If center then goto step 10.  
    Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
    Refine by using small diamond and goto step 10.  
 */  
1200    
1201          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                  if (Data->chroma) InterBias += 50; // to compensate bigger SAD
1202                    if (Data->rrv) InterBias *= 4;
1203    
1204  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                  if (InterBias < pMB->sad16) {
1205          iSAD =                          int32_t deviation;
1206                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,                          if (!Data->rrv) deviation = dev16(Data->Cur, Data->iEdgedWidth);
1207                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,                          else deviation = dev16(Data->Cur, Data->iEdgedWidth) +
1208                                                    min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,                                  dev16(Data->Cur+8, Data->iEdgedWidth) +
1209                                                    iQuant, iFound);                                  dev16(Data->Cur + 8*Data->iEdgedWidth, Data->iEdgedWidth) +
1210                                    dev16(Data->Cur+8+8*Data->iEdgedWidth, Data->iEdgedWidth);
1211    
1212          if (iSAD < iMinSAD) {                          if (deviation < (sad - InterBias)) return MODE_INTRA;
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
1213          }          }
1214                    return mode;
1215    
1216          if (MotionFlags & PMV_EXTSEARCH8) {          } else {
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
1217    
1218                  if (!(MVequal(pmv[0], backupMV))) {                  int bits, intra, i;
1219                          iSAD =                  VECTOR backup[5], *v;
1220                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                  Data->lambda16 = iQuant;
1221                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,          Data->lambda8 = (pParam->vol_flags & XVID_VOL_MPEGQUANT)?1:0;
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
1222    
1223                          if (iSAD < iMinSAD) {                  v = Data->qpel ? Data->currentQMV : Data->currentMV;
1224                                  *currMV = newMV;                  for (i = 0; i < 5; i++) {
1225                                  iMinSAD = iSAD;                          Data->iMinSAD[i] = 256*4096;
1226                          }                          backup[i] = v[i];
1227                  }                  }
1228    
1229                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                  bits = CountMBBitsInter(Data, pMBs, x, y, pParam, MotionFlags);
1230                          iSAD =                  if (bits == 0) return MODE_INTER; // quick stop
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
1231    
1232                          if (iSAD < iMinSAD) {                  if (inter4v) {
1233                                  *currMV = newMV;                          int bits_inter4v = CountMBBitsInter4v(Data, pMB, pMBs, x, y, pParam, MotionFlags, backup);
1234                                  iMinSAD = iSAD;                          if (bits_inter4v < bits) { Data->iMinSAD[0] = bits = bits_inter4v; mode = MODE_INTER4V; }
1235                          }                          }
                 }  
         }  
   
 /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.  
    By performing an optional local half-pixel search, we can refine this result even further.  
 */  
1236    
   PMVfast8_Terminate_with_Refine:  
         if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step  
                 iMinSAD =  
                         Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                         iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                         iFcode, iQuant, iEdgedWidth);  
1237    
1238                    intra = CountMBBitsIntra(Data);
1239    
1240    PMVfast8_Terminate_without_Refine:                  if (intra < bits) { *Data->iMinSAD = bits = intra; return MODE_INTRA; }
         currPMV->x = currMV->x - center_x;  
         currPMV->y = currMV->y - center_y;  
1241    
1242          return iMinSAD;                  return mode;
1243            }
1244  }  }
1245    
1246  int32_t  static void
1247  EPZSSearch16(const uint8_t * const pRef,  SearchP(const IMAGE * const pRef,
1248                           const uint8_t * const pRefH,                           const uint8_t * const pRefH,
1249                           const uint8_t * const pRefV,                           const uint8_t * const pRefV,
1250                           const uint8_t * const pRefHV,                           const uint8_t * const pRefHV,
1251                           const IMAGE * const pCur,                           const IMAGE * const pCur,
1252                           const int x,                           const int x,
1253                           const int y,                           const int y,
                         const int start_x,  
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
1254                           const uint32_t MotionFlags,                           const uint32_t MotionFlags,
1255                    const uint32_t VopFlags,
1256                           const uint32_t iQuant,                           const uint32_t iQuant,
1257                           const uint32_t iFcode,                  SearchData * const Data,
1258                           const MBParam * const pParam,                           const MBParam * const pParam,
1259                           const MACROBLOCK * const pMBs,                           const MACROBLOCK * const pMBs,
1260                           const MACROBLOCK * const prevMBs,                           const MACROBLOCK * const prevMBs,
1261                           VECTOR * const currMV,                  int inter4v,
1262                           VECTOR * const currPMV)                  MACROBLOCK * const pMB)
1263  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const uint32_t iHcount = pParam->mb_height;  
1264    
1265          const int32_t iWidth = pParam->width;          int i, iDirection = 255, mask, threshA;
1266          const int32_t iHeight = pParam->height;          VECTOR pmv[7];
         const int32_t iEdgedWidth = pParam->edged_width;  
1267    
1268          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1269                                                    pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
1270          int32_t min_dx;  
1271          int32_t max_dx;          get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);
1272          int32_t min_dy;  
1273          int32_t max_dy;          Data->temp[5] = Data->temp[6] = 0; // chroma-sad cache
1274            i = Data->rrv ? 2 : 1;
1275            Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16*i;
1276            Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1277            Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1278    
1279            Data->Ref = pRef->y + (x + Data->iEdgedWidth*y) * 16*i;
1280            Data->RefH = pRefH + (x + Data->iEdgedWidth*y) * 16*i;
1281            Data->RefV = pRefV + (x + Data->iEdgedWidth*y) * 16*i;
1282            Data->RefHV = pRefHV + (x + Data->iEdgedWidth*y) * 16*i;
1283            Data->RefCV = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1284            Data->RefCU = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1285    
1286            Data->lambda16 = lambda_vec16[iQuant];
1287            Data->lambda8 = lambda_vec8[iQuant];
1288            Data->qpel_precision = 0;
1289    
1290            if (pMB->dquant != 0) inter4v = 0;
1291    
1292            memset(Data->currentMV, 0, 5*sizeof(VECTOR));
1293    
1294            if (Data->qpel) Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1295            else Data->predMV = pmv[0];
1296    
1297            i = d_mv_bits(0, 0, Data->predMV, Data->iFcode, 0, 0);
1298            Data->iMinSAD[0] = pMB->sad16 + ((Data->lambda16 * i * pMB->sad16)>>10);
1299            Data->iMinSAD[1] = pMB->sad8[0] + ((Data->lambda8 * i * (pMB->sad8[0]+NEIGH_8X8_BIAS)) >> 10);
1300            Data->iMinSAD[2] = pMB->sad8[1];
1301            Data->iMinSAD[3] = pMB->sad8[2];
1302            Data->iMinSAD[4] = pMB->sad8[3];
1303    
1304            if ((!(VopFlags & XVID_VOP_MODEDECISION_BITS)) || (x | y)) {
1305                    threshA = Data->temp[0]; // that's where we keep this SAD atm
1306                    if (threshA < 512) threshA = 512;
1307                    else if (threshA > 1024) threshA = 1024;
1308            } else
1309                    threshA = 512;
1310    
1311          VECTOR newMV;          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
1312          VECTOR backupMV;                                          prevMBs + x + y * pParam->mb_width, Data->rrv);
1313    
1314          VECTOR pmv[4];          if (!Data->rrv) {
1315          int32_t psad[8];                  if (inter4v | Data->chroma) CheckCandidate = CheckCandidate16;
1316                            else CheckCandidate = CheckCandidate16no4v; //for extra speed
1317            } else CheckCandidate = CheckCandidate32;
1318    
1319    /* main loop. checking all predictions (but first, which is 0,0 and has been checked in MotionEstimation())*/
1320    
1321            for (i = 1; i < 7; i++) {
1322                    if (!(mask = make_mask(pmv, i)) ) continue;
1323                    CheckCandidate(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1324                    if (Data->iMinSAD[0] <= threshA) break;
1325            }
1326    
1327            if ((Data->iMinSAD[0] <= threshA) ||
1328                            (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
1329                            (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16))) {
1330                    if (!(VopFlags & XVID_VOP_MODEDECISION_BITS)) inter4v = 0;      }
1331            else {
1332    
1333          static MACROBLOCK *oldMBs = NULL;                  MainSearchFunc * MainSearchPtr;
1334                    if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1335                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1336                            else MainSearchPtr = DiamondSearch;
1337    
1338  //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;                  MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
         const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;  
         MACROBLOCK *oldMB = NULL;  
1339    
1340           int32_t thresh2;  /* extended search, diamond starting in 0,0 and in prediction.
1341          int32_t bPredEq;          note that this search is/might be done in halfpel positions,
1342          int32_t iMinSAD, iSAD = 9999;          which makes it more different than the diamond above */
1343    
1344          MainSearch16FuncPtr MainSearchPtr;                  if (MotionFlags & XVID_ME_EXTSEARCH16) {
1345                            int32_t bSAD;
1346                            VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
1347                            if (Data->rrv) {
1348                                    startMV.x = RRV_MV_SCALEUP(startMV.x);
1349                                    startMV.y = RRV_MV_SCALEUP(startMV.y);
1350                            }
1351                            if (!(MVequal(startMV, backupMV))) {
1352                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1353    
1354          if (oldMBs == NULL) {                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1355                  oldMBs = (MACROBLOCK *) calloc(iWcount * iHcount, sizeof(MACROBLOCK));                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1356  //      fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));                                  if (bSAD < Data->iMinSAD[0]) {
1357                                            Data->currentMV[0] = backupMV;
1358                                            Data->iMinSAD[0] = bSAD; }
1359          }          }
         oldMB = oldMBs + x + y * iWcount;  
1360    
1361  /* Get maximum range */                          backupMV = Data->currentMV[0];
1362          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,                          startMV.x = startMV.y = 1;
1363                            iFcode);                          if (!(MVequal(startMV, backupMV))) {
1364                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1365    
1366          if (!(MotionFlags & PMV_HALFPEL16)) {                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1367                  min_dx = EVEN(min_dx);                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1368                  max_dx = EVEN(max_dx);                                  if (bSAD < Data->iMinSAD[0]) {
1369                  min_dy = EVEN(min_dy);                                          Data->currentMV[0] = backupMV;
1370                  max_dy = EVEN(max_dy);                                          Data->iMinSAD[0] = bSAD; }
1371                            }
1372                    }
1373          }          }
         /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
         //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);  
   
 /* Step 4: Calculate SAD around the Median prediction.  
         MinSAD=SAD  
         If Motion Vector equal to Previous frame motion vector  
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
 */  
1374    
1375  // Prepare for main loop          if (MotionFlags & XVID_ME_HALFPELREFINE16)
1376                    if ((!(MotionFlags & XVID_ME_HALFPELREFINE16_BITS)) || Data->iMinSAD[0] < 200*(int)iQuant)
1377                            SubpelRefine(Data);
1378    
1379          currMV->x = start_x;          for(i = 0; i < 5; i++) {
1380          currMV->y = start_y;                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // initialize qpel vectors
1381                    Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
1382            }
1383    
1384          if (!(MotionFlags & PMV_HALFPEL16)) {          if (MotionFlags & XVID_ME_QUARTERPELREFINE16) {
                 currMV->x = EVEN(currMV->x);  
                 currMV->y = EVEN(currMV->y);  
         }  
   
         if (currMV->x > max_dx)  
                 currMV->x = max_dx;  
         if (currMV->x < min_dx)  
                 currMV->x = min_dx;  
         if (currMV->y > max_dy)  
                 currMV->y = max_dy;  
         if (currMV->y < min_dy)  
                 currMV->y = min_dy;  
   
 /***************** This is predictor SET A: only median prediction ******************/  
   
         iMinSAD =  
                 sad16(cur,  
                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
   
 // thresh1 is fixed to 256  
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
         }  
   
 /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/  
1385    
1386  // previous frame MV                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1387          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);                                  pParam->width, pParam->height, Data->iFcode, 1, 0);
1388    
1389  // set threshhold based on Min of Prediction and SAD of collocated block                  if ((!(MotionFlags & XVID_ME_QUARTERPELREFINE16_BITS)) || (Data->iMinSAD[0] < 200*(int)iQuant)) {
1390  // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want                          Data->qpel_precision = 1;
1391                            SubpelRefine(Data);
1392                    }
1393            }
1394    
1395          if ((x == 0) && (y == 0)) {          if ((!(VopFlags & XVID_VOP_MODEDECISION_BITS)) && (Data->iMinSAD[0] < (int32_t)iQuant * 30)) inter4v = 0;
                 thresh2 = 512;  
         } else {  
 /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */  
1396    
1397                  thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;          if (inter4v && (!(VopFlags & XVID_VOP_MODEDECISION_BITS) ||
1398          }                          (!(MotionFlags & XVID_ME_QUARTERPELREFINE8_BITS)) || (!(MotionFlags & XVID_ME_HALFPELREFINE8_BITS)) ||
1399                            ((!(MotionFlags & XVID_ME_EXTSEARCH_BITS)) && (!(MotionFlags&XVID_ME_EXTSEARCH8)) ))) {
1400                    // if decision is BITS-based and all refinement steps will be done in BITS domain, there is no reason to call this loop
1401    
1402  // MV=(0,0) is often a good choice                  SearchData Data8;
1403                    memcpy(&Data8, Data, sizeof(SearchData)); //quick copy of common data
1404    
1405          CHECK_MV16_ZERO;                  Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
1406                    Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
1407                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
1408                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
1409    
1410                    if ((Data->chroma) && (!(VopFlags & XVID_VOP_MODEDECISION_BITS))) {
1411                            // chroma is only used for comparsion to INTER. if the comparsion will be done in BITS domain, there is no reason to compute it
1412                            int sumx = 0, sumy = 0;
1413                            const int div = 1 + Data->qpel;
1414                            const VECTOR * const mv = Data->qpel ? pMB->qmvs : pMB->mvs;
1415    
1416  // left neighbour, if allowed                          for (i = 0; i < 4; i++) {
1417          if (x != 0) {                                  sumx += mv[i].x / div;
1418                  if (!(MotionFlags & PMV_HALFPEL16)) {                                  sumy += mv[i].y / div;
                         pmv[1].x = EVEN(pmv[1].x);  
                         pmv[1].y = EVEN(pmv[1].y);  
1419                  }                  }
1420                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
1421                            Data->iMinSAD[1] += ChromaSAD(  (sumx >> 3) + roundtab_76[sumx & 0xf],
1422                                                                                            (sumy >> 3) + roundtab_76[sumy & 0xf], Data);
1423          }          }
 // top neighbour, if allowed  
         if (y != 0) {  
                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                         pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
1424                  }                  }
                 CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
1425    
1426  // top right neighbour, if allowed          inter4v = ModeDecision(iQuant, Data, inter4v, pMB, pMBs, x, y, pParam, MotionFlags, VopFlags);
1427                  if ((uint32_t) x != (iWcount - 1)) {  
1428                          if (!(MotionFlags & PMV_HALFPEL16)) {          if (Data->rrv) {
1429                                  pmv[3].x = EVEN(pmv[3].x);                          Data->currentMV[0].x = RRV_MV_SCALEDOWN(Data->currentMV[0].x);
1430                                  pmv[3].y = EVEN(pmv[3].y);                          Data->currentMV[0].y = RRV_MV_SCALEDOWN(Data->currentMV[0].y);
1431                          }                          }
1432                          CHECK_MV16_CANDIDATE(pmv[3].x, pmv[3].y);  
1433            if (inter4v == MODE_INTER) {
1434                    pMB->mode = MODE_INTER;
1435                    pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
1436                    pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = Data->iMinSAD[0];
1437    
1438                    if(Data->qpel) {
1439                            pMB->qmvs[0] = pMB->qmvs[1]
1440                                    = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1441                            pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1442                            pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;
1443                    } else {
1444                            pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1445                            pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
1446                  }                  }
1447    
1448            } else if (inter4v == MODE_INTER4V) {
1449                    pMB->mode = MODE_INTER4V;
1450                    pMB->sad16 = Data->iMinSAD[0];
1451            } else { // INTRA mode
1452                    SkipMacroblockP(pMB, 0); // not skip, but similar enough
1453                    pMB->mode = MODE_INTRA;
1454          }          }
1455    
1456  /* Terminate if MinSAD <= T_2  }
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
1457    
1458          if ((iMinSAD <= thresh2)  static void
1459                  || (MVequal(*currMV, prevMB->mvs[0]) &&  Search8(const SearchData * const OldData,
1460                          ((int32_t) iMinSAD <= prevMB->sad16))) {                  const int x, const int y,
1461                  if (MotionFlags & PMV_QUICKSTOP16)                  const uint32_t MotionFlags,
1462                          goto EPZS16_Terminate_without_Refine;                  const MBParam * const pParam,
1463                  if (MotionFlags & PMV_EARLYSTOP16)                  MACROBLOCK * const pMB,
1464                          goto EPZS16_Terminate_with_Refine;                  const MACROBLOCK * const pMBs,
1465                    const int block,
1466                    SearchData * const Data)
1467    {
1468            int i = 0;
1469            Data->iMinSAD = OldData->iMinSAD + 1 + block;
1470            Data->currentMV = OldData->currentMV + 1 + block;
1471            Data->currentQMV = OldData->currentQMV + 1 + block;
1472    
1473            if(Data->qpel) {
1474                    Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1475                    if (block != 0) i = d_mv_bits(  Data->currentQMV->x, Data->currentQMV->y,
1476                                                                                    Data->predMV, Data->iFcode, 0, 0);
1477            } else {
1478                    Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1479                    if (block != 0) i = d_mv_bits(  Data->currentMV->x, Data->currentMV->y,
1480                                                                                    Data->predMV, Data->iFcode, 0, Data->rrv);
1481          }          }
1482    
1483  /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/          *(Data->iMinSAD) += (Data->lambda8 * i * (*Data->iMinSAD + NEIGH_8X8_BIAS))>>10;
1484    
1485          backupMV = prevMB->mvs[0];      // collocated MV          if (MotionFlags & (XVID_ME_EXTSEARCH8|XVID_ME_HALFPELREFINE8|XVID_ME_QUARTERPELREFINE8)) {
1486          backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x);     // acceleration X                  if (Data->rrv) i = 2; else i = 1;
         backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y);     // acceleration Y  
1487    
1488          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y);                  Data->Ref = OldData->Ref + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));
1489                    Data->RefH = OldData->RefH + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));
1490                    Data->RefV = OldData->RefV + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));
1491                    Data->RefHV = OldData->RefHV + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));
1492    
1493  // left neighbour                  Data->Cur = OldData->Cur + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));
1494          if (x != 0)                  Data->qpel_precision = 0;
                 CHECK_MV16_CANDIDATE((prevMB - 1)->mvs[0].x, (prevMB - 1)->mvs[0].y);  
1495    
1496  // top neighbour                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1497          if (y != 0)                                          pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
                 CHECK_MV16_CANDIDATE((prevMB - iWcount)->mvs[0].x,  
                                                          (prevMB - iWcount)->mvs[0].y);  
1498    
1499  // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs                  if (!Data->rrv) CheckCandidate = CheckCandidate8;
1500                    else CheckCandidate = CheckCandidate16no4v;
1501    
1502          if ((uint32_t) x != iWcount - 1)                  if (MotionFlags & XVID_ME_EXTSEARCH8 && (!(MotionFlags & XVID_ME_EXTSEARCH_BITS))) {
1503                  CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);                          int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
1504    
1505  // bottom neighbour, dito                          MainSearchFunc *MainSearchPtr;
1506          if ((uint32_t) y != iHcount - 1)                          if (MotionFlags & XVID_ME_USESQUARES8) MainSearchPtr = SquareSearch;
1507                  CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,                                  else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1508                                                           (prevMB + iWcount)->mvs[0].y);                                          else MainSearchPtr = DiamondSearch;
1509    
1510  /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */                          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, 255);
1511          if (iMinSAD <= thresh2) {  
1512                  if (MotionFlags & PMV_QUICKSTOP16)                          if(*(Data->iMinSAD) < temp_sad) {
1513                          goto EPZS16_Terminate_without_Refine;                                          Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1514                  if (MotionFlags & PMV_EARLYSTOP16)                                          Data->currentQMV->y = 2 * Data->currentMV->y;
1515                          goto EPZS16_Terminate_with_Refine;                          }
1516          }          }
1517    
1518  /************ (if Diamond Search)  **************/                  if (MotionFlags & XVID_ME_HALFPELREFINE8) {
1519                            int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
1520    
1521          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                          SubpelRefine(Data); // perform halfpel refine of current best vector
1522    
1523          if (MotionFlags & PMV_USESQUARES16)                          if(*(Data->iMinSAD) < temp_sad) { // we have found a better match
1524                  MainSearchPtr = Square16_MainSearch;                                  Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1525          else                                  Data->currentQMV->y = 2 * Data->currentMV->y;
1526           if (MotionFlags & PMV_ADVANCEDDIAMOND16)                          }
1527                  MainSearchPtr = AdvDiamond16_MainSearch;                  }
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
1528    
1529  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                  if (Data->qpel && MotionFlags & XVID_ME_QUARTERPELREFINE8) {
1530                                    Data->qpel_precision = 1;
1531                                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1532                                            pParam->width, pParam->height, Data->iFcode, 1, 0);
1533                                    SubpelRefine(Data);
1534                    }
1535            }
1536    
1537          iSAD =          if (Data->rrv) {
1538                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,                          Data->currentMV->x = RRV_MV_SCALEDOWN(Data->currentMV->x);
1539                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,                          Data->currentMV->y = RRV_MV_SCALEDOWN(Data->currentMV->y);
1540                                                    min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);          }
1541    
1542          if (iSAD < iMinSAD) {          if(Data->qpel) {
1543                  *currMV = newMV;                  pMB->pmvs[block].x = Data->currentQMV->x - Data->predMV.x;
1544                  iMinSAD = iSAD;                  pMB->pmvs[block].y = Data->currentQMV->y - Data->predMV.y;
1545                    pMB->qmvs[block] = *Data->currentQMV;
1546            } else {
1547                    pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1548                    pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
1549          }          }
1550    
1551            pMB->mvs[block] = *Data->currentMV;
1552            pMB->sad8[block] = 4 * *Data->iMinSAD;
1553    }
1554    
1555          if (MotionFlags & PMV_EXTSEARCH16) {  /* motion estimation for B-frames */
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
1556    
1557                  if (!(MVequal(pmv[0], backupMV))) {  static __inline VECTOR
1558                          iSAD =  ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1559                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  {
1560                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,  /* the stupidiest function ever */
1561                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,          return (mode == MODE_FORWARD ? pMB->mvs[0] : pMB->b_mvs[0]);
                                                                   2, iFcode, iQuant, 0);  
1562                  }                  }
1563    
1564                  if (iSAD < iMinSAD) {  static void __inline
1565                          *currMV = newMV;  PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
1566                          iMinSAD = iSAD;                                                          const uint32_t iWcount,
1567                  }                                                          const MACROBLOCK * const pMB,
1568                                                            const uint32_t mode_curr)
1569    {
1570    
1571                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          // [0] is prediction
1572                          iSAD =          pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);  
1573    
1574                          if (iSAD < iMinSAD) {          pmv[1].x = pmv[1].y = 0; // [1] is zero
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
                 }  
         }  
1575    
1576  /***************        Choose best MV found     **************/          pmv[2] = ChoosePred(pMB, mode_curr);
1577            pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
1578    
1579    EPZS16_Terminate_with_Refine:          if ((y != 0)&&(x != (int)(iWcount+1))) {                        // [3] top-right neighbour
1580          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step                  pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
1581                  iMinSAD =                  pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
1582                          Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,          } else pmv[3].x = pmv[3].y = 0;
                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
1583    
1584    EPZS16_Terminate_without_Refine:          if (y != 0) {
1585                    pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
1586                    pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
1587            } else pmv[4].x = pmv[4].y = 0;
1588    
1589          *oldMB = *prevMB;          if (x != 0) {
1590                    pmv[5] = ChoosePred(pMB-1, mode_curr);
1591                    pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1592            } else pmv[5].x = pmv[5].y = 0;
1593    
1594          currPMV->x = currMV->x - center_x;          if (x != 0 && y != 0) {
1595          currPMV->y = currMV->y - center_y;                  pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
1596          return iMinSAD;                  pmv[6].x = EVEN(pmv[6].x); pmv[6].y = EVEN(pmv[6].y);
1597            } else pmv[6].x = pmv[6].y = 0;
1598  }  }
1599    
1600    
1601  int32_t  /* search backward or forward */
1602  EPZSSearch8(const uint8_t * const pRef,  static void
1603    SearchBF(       const IMAGE * const pRef,
1604                          const uint8_t * const pRefH,                          const uint8_t * const pRefH,
1605                          const uint8_t * const pRefV,                          const uint8_t * const pRefV,
1606                          const uint8_t * const pRefHV,                          const uint8_t * const pRefHV,
1607                          const IMAGE * const pCur,                          const IMAGE * const pCur,
1608                          const int x,                          const int x, const int y,
                         const int y,  
                         const int start_x,  
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
1609                          const uint32_t MotionFlags,                          const uint32_t MotionFlags,
                         const uint32_t iQuant,  
1610                          const uint32_t iFcode,                          const uint32_t iFcode,
1611                          const MBParam * const pParam,                          const MBParam * const pParam,
1612                          const MACROBLOCK * const pMBs,                          MACROBLOCK * const pMB,
1613                          const MACROBLOCK * const prevMBs,                          const VECTOR * const predMV,
1614                          VECTOR * const currMV,                          int32_t * const best_sad,
1615                          VECTOR * const currPMV)                          const int32_t mode_current,
1616                            SearchData * const Data)
1617  {  {
 /* Please not that EPZS might not be a good choice for 8x8-block motion search ! */  
   
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
   
         const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;  
   
         int32_t iDiamondSize = 1;  
1618    
1619          int32_t min_dx;          int i, iDirection = 255, mask;
1620          int32_t max_dx;          VECTOR pmv[7];
1621          int32_t min_dy;          MainSearchFunc *MainSearchPtr;
1622          int32_t max_dy;          *Data->iMinSAD = MV_MAX_ERROR;
1623            Data->iFcode = iFcode;
1624            Data->qpel_precision = 0;
1625            Data->temp[5] = Data->temp[6] = Data->temp[7] = 256*4096; // reset chroma-sad cache
1626    
1627          VECTOR newMV;          Data->Ref = pRef->y + (x + y * Data->iEdgedWidth) * 16;
1628          VECTOR backupMV;          Data->RefH = pRefH + (x + y * Data->iEdgedWidth) * 16;
1629            Data->RefV = pRefV + (x + y * Data->iEdgedWidth) * 16;
1630            Data->RefHV = pRefHV + (x + y * Data->iEdgedWidth) * 16;
1631            Data->RefCU = pRef->u + (x + y * Data->iEdgedWidth/2) * 8;
1632            Data->RefCV = pRef->v + (x + y * Data->iEdgedWidth/2) * 8;
1633    
1634          VECTOR pmv[4];          Data->predMV = *predMV;
         int32_t psad[8];  
1635    
1636          const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1637                                    pParam->width, pParam->height, iFcode - Data->qpel, 0, 0);
1638    
1639  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          pmv[0] = Data->predMV;
1640          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;          if (Data->qpel) { pmv[0].x /= 2; pmv[0].y /= 2; }
1641    
1642          int32_t bPredEq;          PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);
         int32_t iMinSAD, iSAD = 9999;  
1643    
1644          MainSearch8FuncPtr MainSearchPtr;          Data->currentMV->x = Data->currentMV->y = 0;
1645            CheckCandidate = CheckCandidate16no4v;
1646    
1647  /* Get maximum range */  // main loop. checking all predictions
1648          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,          for (i = 0; i < 7; i++) {
1649                            iFcode);                  if (!(mask = make_mask(pmv, i)) ) continue;
1650                    CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
 /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  
   
         if (!(MotionFlags & PMV_HALFPEL8)) {  
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
1651          }          }
         /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
         //bPredEq = get_pmvdata(pMBs, x >> 1, y >> 1, iWcount, iSubBlock, pmv[0].x, pmv[0].y, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, x >> 1, y >> 1, iSubBlock, pmv, psad);  
1652    
1653            if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1654            else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1655                    else MainSearchPtr = DiamondSearch;
1656    
1657  /* Step 4: Calculate SAD around the Median prediction.          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
         MinSAD=SAD  
         If Motion Vector equal to Previous frame motion vector  
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
 */  
   
 // Prepare for main loop  
1658    
1659            SubpelRefine(Data);
1660    
1661          if (!(MotionFlags & PMV_HALFPEL8)) {          if (Data->qpel && *Data->iMinSAD < *best_sad + 300) {
1662                  currMV->x = EVEN(currMV->x);                  Data->currentQMV->x = 2*Data->currentMV->x;
1663                  currMV->y = EVEN(currMV->y);                  Data->currentQMV->y = 2*Data->currentMV->y;
1664                    Data->qpel_precision = 1;
1665                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1666                                            pParam->width, pParam->height, iFcode, 1, 0);
1667                    SubpelRefine(Data);
1668          }          }
1669    
1670          if (currMV->x > max_dx)  // three bits are needed to code backward mode. four for forward
                 currMV->x = max_dx;  
         if (currMV->x < min_dx)  
                 currMV->x = min_dx;  
         if (currMV->y > max_dy)  
                 currMV->y = max_dy;  
         if (currMV->y < min_dy)  
                 currMV->y = min_dy;  
1671    
1672  /***************** This is predictor SET A: only median prediction ******************/          if (mode_current == MODE_FORWARD) *Data->iMinSAD += 4 * Data->lambda16;
1673            else *Data->iMinSAD += 3 * Data->lambda16;
1674    
1675            if (*Data->iMinSAD < *best_sad) {
1676                    *best_sad = *Data->iMinSAD;
1677                    pMB->mode = mode_current;
1678                    if (Data->qpel) {
1679                            pMB->pmvs[0].x = Data->currentQMV->x - predMV->x;
1680                            pMB->pmvs[0].y = Data->currentQMV->y - predMV->y;
1681                            if (mode_current == MODE_FORWARD)
1682                                    pMB->qmvs[0] = *Data->currentQMV;
1683                            else
1684                                    pMB->b_qmvs[0] = *Data->currentQMV;
1685                    } else {
1686                            pMB->pmvs[0].x = Data->currentMV->x - predMV->x;
1687                            pMB->pmvs[0].y = Data->currentMV->y - predMV->y;
1688                    }
1689                    if (mode_current == MODE_FORWARD) pMB->mvs[0] = *Data->currentMV;
1690                    else pMB->b_mvs[0] = *Data->currentMV;
1691            }
1692    
1693          iMinSAD =          if (mode_current == MODE_FORWARD) *(Data->currentMV+2) = *Data->currentMV;
1694                  sad8(cur,          else *(Data->currentMV+1) = *Data->currentMV; //we store currmv for interpolate search
1695                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  }
1696                                                  iEdgedWidth), iEdgedWidth);  
1697          iMinSAD +=  static void
1698                  calc_delta_8(currMV->x - center_x, currMV->y - center_y,  SkipDecisionB(const IMAGE * const pCur,
1699                                           (uint8_t) iFcode, iQuant);                                  const IMAGE * const f_Ref,
1700                                    const IMAGE * const b_Ref,
1701                                    MACROBLOCK * const pMB,
1702                                    const uint32_t x, const uint32_t y,
1703                                    const SearchData * const Data)
1704    {
1705            int dx = 0, dy = 0, b_dx = 0, b_dy = 0;
1706            int32_t sum;
1707            const int div = 1 + Data->qpel;
1708            int k;
1709            const uint32_t stride = Data->iEdgedWidth/2;
1710    //this is not full chroma compensation, only it's fullpel approximation. should work though
1711    
1712            for (k = 0; k < 4; k++) {
1713                    dy += Data->directmvF[k].y / div;
1714                    dx += Data->directmvF[k].x / div;
1715                    b_dy += Data->directmvB[k].y / div;
1716                    b_dx += Data->directmvB[k].x / div;
1717            }
1718    
1719            dy = (dy >> 3) + roundtab_76[dy & 0xf];
1720            dx = (dx >> 3) + roundtab_76[dx & 0xf];
1721            b_dy = (b_dy >> 3) + roundtab_76[b_dy & 0xf];
1722            b_dx = (b_dx >> 3) + roundtab_76[b_dx & 0xf];
1723    
1724            sum = sad8bi(pCur->u + 8 * x + 8 * y * stride,
1725                                            f_Ref->u + (y*8 + dy/2) * stride + x*8 + dx/2,
1726                                            b_Ref->u + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1727                                            stride);
1728    
1729            if (sum >= 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) return; //no skip
1730    
1731            sum += sad8bi(pCur->v + 8*x + 8 * y * stride,
1732                                            f_Ref->v + (y*8 + dy/2) * stride + x*8 + dx/2,
1733                                            b_Ref->v + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1734                                            stride);
1735    
1736  // thresh1 is fixed to 256          if (sum < 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) {
1737          if (iMinSAD < 256 / 4) {                  pMB->mode = MODE_DIRECT_NONE_MV; //skipped
1738                  if (MotionFlags & PMV_QUICKSTOP8)                  for (k = 0; k < 4; k++) {
1739                          goto EPZS8_Terminate_without_Refine;                          pMB->qmvs[k] = pMB->mvs[k];
1740                  if (MotionFlags & PMV_EARLYSTOP8)                          pMB->b_qmvs[k] = pMB->b_mvs[k];
1741                          goto EPZS8_Terminate_with_Refine;                  }
1742            }
1743          }          }
1744    
1745  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/  static __inline uint32_t
1746    SearchDirect(const IMAGE * const f_Ref,
1747                                    const uint8_t * const f_RefH,
1748                                    const uint8_t * const f_RefV,
1749                                    const uint8_t * const f_RefHV,
1750                                    const IMAGE * const b_Ref,
1751                                    const uint8_t * const b_RefH,
1752                                    const uint8_t * const b_RefV,
1753                                    const uint8_t * const b_RefHV,
1754                                    const IMAGE * const pCur,
1755                                    const int x, const int y,
1756                                    const uint32_t MotionFlags,
1757                                    const int32_t TRB, const int32_t TRD,
1758                                    const MBParam * const pParam,
1759                                    MACROBLOCK * const pMB,
1760                                    const MACROBLOCK * const b_mb,
1761                                    int32_t * const best_sad,
1762                                    SearchData * const Data)
1763    
1764    {
1765            int32_t skip_sad;
1766            int k = (x + Data->iEdgedWidth*y) * 16;
1767            MainSearchFunc *MainSearchPtr;
1768    
1769            *Data->iMinSAD = 256*4096;
1770            Data->Ref = f_Ref->y + k;
1771            Data->RefH = f_RefH + k;
1772            Data->RefV = f_RefV + k;
1773            Data->RefHV = f_RefHV + k;
1774            Data->bRef = b_Ref->y + k;
1775            Data->bRefH = b_RefH + k;
1776            Data->bRefV = b_RefV + k;
1777            Data->bRefHV = b_RefHV + k;
1778            Data->RefCU = f_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1779            Data->RefCV = f_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1780            Data->b_RefCU = b_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1781            Data->b_RefCV = b_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1782    
1783            k = Data->qpel ? 4 : 2;
1784            Data->max_dx = k * (pParam->width - x * 16);
1785            Data->max_dy = k * (pParam->height - y * 16);
1786            Data->min_dx = -k * (16 + x * 16);
1787            Data->min_dy = -k * (16 + y * 16);
1788    
1789            Data->referencemv = Data->qpel ? b_mb->qmvs : b_mb->mvs;
1790            Data->qpel_precision = 0;
1791    
1792  // MV=(0,0) is often a good choice          for (k = 0; k < 4; k++) {
1793          CHECK_MV8_ZERO;                  pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);
1794                    pMB->b_mvs[k].x = Data->directmvB[k].x = ((TRB - TRD) * Data->referencemv[k].x) / TRD;
1795                    pMB->mvs[k].y = Data->directmvF[k].y = ((TRB * Data->referencemv[k].y) / TRD);
1796                    pMB->b_mvs[k].y = Data->directmvB[k].y = ((TRB - TRD) * Data->referencemv[k].y) / TRD;
1797    
1798  // previous frame MV                  if ( (pMB->b_mvs[k].x > Data->max_dx) | (pMB->b_mvs[k].x < Data->min_dx)
1799          CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x, prevMB->mvs[iSubBlock].y);                          | (pMB->b_mvs[k].y > Data->max_dy) | (pMB->b_mvs[k].y < Data->min_dy) ) {
1800    
1801  // left neighbour, if allowed                          *best_sad = 256*4096; // in that case, we won't use direct mode
1802          if (psad[1] != MV_MAX_ERROR) {                          pMB->mode = MODE_DIRECT; // just to make sure it doesn't say "MODE_DIRECT_NONE_MV"
1803                  if (!(MotionFlags & PMV_HALFPEL8)) {                          pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;
1804                          pmv[1].x = EVEN(pmv[1].x);                          return 256*4096;
                         pmv[1].y = EVEN(pmv[1].y);  
1805                  }                  }
1806                  CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);                  if (b_mb->mode != MODE_INTER4V) {
1807                            pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mvs[0];
1808                            pMB->b_mvs[1] = pMB->b_mvs[2] = pMB->b_mvs[3] = pMB->b_mvs[0];
1809                            Data->directmvF[1] = Data->directmvF[2] = Data->directmvF[3] = Data->directmvF[0];
1810                            Data->directmvB[1] = Data->directmvB[2] = Data->directmvB[3] = Data->directmvB[0];
1811                            break;
1812          }          }
 // top neighbour, if allowed  
         if (psad[2] != MV_MAX_ERROR) {  
                 if (!(MotionFlags & PMV_HALFPEL8)) {  
                         pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
1813                  }                  }
                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
1814    
1815  // top right neighbour, if allowed          CheckCandidate = b_mb->mode == MODE_INTER4V ? CheckCandidateDirect : CheckCandidateDirectno4v;
1816                  if (psad[3] != MV_MAX_ERROR) {  
1817                          if (!(MotionFlags & PMV_HALFPEL8)) {          CheckCandidate(0, 0, 255, &k, Data);
1818                                  pmv[3].x = EVEN(pmv[3].x);  
1819                                  pmv[3].y = EVEN(pmv[3].y);  // initial (fast) skip decision
1820                          }          if (*Data->iMinSAD < pMB->quant * INITIAL_SKIP_THRESH * (2 + Data->chroma?1:0)) {
1821                          CHECK_MV8_CANDIDATE(pmv[3].x, pmv[3].y);                  //possible skip
1822                    if (Data->chroma) {
1823                            pMB->mode = MODE_DIRECT_NONE_MV;
1824                            return *Data->iMinSAD; // skip.
1825                    } else {
1826                            SkipDecisionB(pCur, f_Ref, b_Ref, pMB, x, y, Data);
1827                            if (pMB->mode == MODE_DIRECT_NONE_MV) return *Data->iMinSAD; // skip.
1828                  }                  }
1829          }          }
1830    
1831  /*  // this bias is zero anyway, at the moment!          *Data->iMinSAD += Data->lambda16;
1832            skip_sad = *Data->iMinSAD;
1833    
1834          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)  //      DIRECT MODE DELTA VECTOR SEARCH.
1835                  iMinSAD -= MV8_00_BIAS;  //      This has to be made more effective, but at the moment I'm happy it's running at all
1836    
1837  */          if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1838                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1839                            else MainSearchPtr = DiamondSearch;
1840    
1841  /* Terminate if MinSAD <= T_2          MainSearchPtr(0, 0, Data, 255);
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
1842    
1843          if (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */          SubpelRefine(Data);
                 if (MotionFlags & PMV_QUICKSTOP8)  
                         goto EPZS8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
         }  
1844    
1845  /************ (Diamond Search)  **************/          *best_sad = *Data->iMinSAD;
1846    
1847          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          if (Data->qpel || b_mb->mode == MODE_INTER4V) pMB->mode = MODE_DIRECT;
1848            else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation
1849    
1850          if (!(MotionFlags & PMV_HALFPELDIAMOND8))          pMB->pmvs[3] = *Data->currentMV;
1851                  iDiamondSize *= 2;  
1852            for (k = 0; k < 4; k++) {
1853                    pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
1854                    pMB->b_mvs[k].x = (     (Data->currentMV->x == 0)
1855                                                            ? Data->directmvB[k].x
1856                                                            :pMB->mvs[k].x - Data->referencemv[k].x);
1857                    pMB->mvs[k].y = (Data->directmvF[k].y + Data->currentMV->y);
1858                    pMB->b_mvs[k].y = ((Data->currentMV->y == 0)
1859                                                            ? Data->directmvB[k].y
1860                                                            : pMB->mvs[k].y - Data->referencemv[k].y);
1861                    if (Data->qpel) {
1862                            pMB->qmvs[k].x = pMB->mvs[k].x; pMB->mvs[k].x /= 2;
1863                            pMB->b_qmvs[k].x = pMB->b_mvs[k].x; pMB->b_mvs[k].x /= 2;
1864                            pMB->qmvs[k].y = pMB->mvs[k].y; pMB->mvs[k].y /= 2;
1865                            pMB->b_qmvs[k].y = pMB->b_mvs[k].y; pMB->b_mvs[k].y /= 2;
1866                    }
1867    
1868                    if (b_mb->mode != MODE_INTER4V) {
1869                            pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1870                            pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1871                            pMB->qmvs[3] = pMB->qmvs[2] = pMB->qmvs[1] = pMB->qmvs[0];
1872                            pMB->b_qmvs[3] = pMB->b_qmvs[2] = pMB->b_qmvs[1] = pMB->b_qmvs[0];
1873                            break;
1874                    }
1875            }
1876            return skip_sad;
1877    }
1878    
1879    static void
1880    SearchInterpolate(const IMAGE * const f_Ref,
1881                                    const uint8_t * const f_RefH,
1882                                    const uint8_t * const f_RefV,
1883                                    const uint8_t * const f_RefHV,
1884                                    const IMAGE * const b_Ref,
1885                                    const uint8_t * const b_RefH,
1886                                    const uint8_t * const b_RefV,
1887                                    const uint8_t * const b_RefHV,
1888                                    const IMAGE * const pCur,
1889                                    const int x, const int y,
1890                                    const uint32_t fcode,
1891                                    const uint32_t bcode,
1892                                    const uint32_t MotionFlags,
1893                                    const MBParam * const pParam,
1894                                    const VECTOR * const f_predMV,
1895                                    const VECTOR * const b_predMV,
1896                                    MACROBLOCK * const pMB,
1897                                    int32_t * const best_sad,
1898                                    SearchData * const fData)
1899    
1900  /* default: use best prediction as starting point for one call of EPZS_MainSearch */  {
1901    
1902  // there is no EPZS^2 for inter4v at the moment          int iDirection, i, j;
1903            SearchData bData;
1904    
1905            fData->qpel_precision = 0;
1906            memcpy(&bData, fData, sizeof(SearchData)); //quick copy of common data
1907            *fData->iMinSAD = 4096*256;
1908            bData.currentMV++; bData.currentQMV++;
1909            fData->iFcode = bData.bFcode = fcode; fData->bFcode = bData.iFcode = bcode;
1910    
1911            i = (x + y * fData->iEdgedWidth) * 16;
1912            bData.bRef = fData->Ref = f_Ref->y + i;
1913            bData.bRefH = fData->RefH = f_RefH + i;
1914            bData.bRefV = fData->RefV = f_RefV + i;
1915            bData.bRefHV = fData->RefHV = f_RefHV + i;
1916            bData.Ref = fData->bRef = b_Ref->y + i;
1917            bData.RefH = fData->bRefH = b_RefH + i;
1918            bData.RefV = fData->bRefV = b_RefV + i;
1919            bData.RefHV = fData->bRefHV = b_RefHV + i;
1920            bData.b_RefCU = fData->RefCU = f_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
1921            bData.b_RefCV = fData->RefCV = f_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
1922            bData.RefCU = fData->b_RefCU = b_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
1923            bData.RefCV = fData->b_RefCV = b_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
1924    
1925    
1926            bData.bpredMV = fData->predMV = *f_predMV;
1927            fData->bpredMV = bData.predMV = *b_predMV;
1928            fData->currentMV[0] = fData->currentMV[2];
1929    
1930            get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode - fData->qpel, 0, 0);
1931            get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode - fData->qpel, 0, 0);
1932    
1933            if (fData->currentMV[0].x > fData->max_dx) fData->currentMV[0].x = fData->max_dx;
1934            if (fData->currentMV[0].x < fData->min_dx) fData->currentMV[0].x = fData->min_dx;
1935            if (fData->currentMV[0].y > fData->max_dy) fData->currentMV[0].y = fData->max_dy;
1936            if (fData->currentMV[0].y < fData->min_dy) fData->currentMV[0].y = fData->min_dy;
1937    
1938            if (fData->currentMV[1].x > bData.max_dx) fData->currentMV[1].x = bData.max_dx;
1939            if (fData->currentMV[1].x < bData.min_dx) fData->currentMV[1].x = bData.min_dx;
1940            if (fData->currentMV[1].y > bData.max_dy) fData->currentMV[1].y = bData.max_dy;
1941            if (fData->currentMV[1].y < bData.min_dy) fData->currentMV[1].y = bData.min_dy;
1942    
1943    if (MotionFlags & PMV_USESQUARES8)          CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, 255, &iDirection, fData);
       MainSearchPtr = Square8_MainSearch;  
   else  
1944    
1945          if (MotionFlags & PMV_ADVANCEDDIAMOND8)  //diamond
1946                  MainSearchPtr = AdvDiamond8_MainSearch;          do {
1947          else                  iDirection = 255;
1948                  MainSearchPtr = Diamond8_MainSearch;                  // forward MV moves
1949                    i = fData->currentMV[0].x; j = fData->currentMV[0].y;
1950    
1951                    CheckCandidateInt(i + 1, j, 0, &iDirection, fData);
1952                    CheckCandidateInt(i, j + 1, 0, &iDirection, fData);
1953                    CheckCandidateInt(i - 1, j, 0, &iDirection, fData);
1954                    CheckCandidateInt(i, j - 1, 0, &iDirection, fData);
1955    
1956                    // backward MV moves
1957                    i = fData->currentMV[1].x; j = fData->currentMV[1].y;
1958                    fData->currentMV[2] = fData->currentMV[0];
1959                    CheckCandidateInt(i + 1, j, 0, &iDirection, &bData);
1960                    CheckCandidateInt(i, j + 1, 0, &iDirection, &bData);
1961                    CheckCandidateInt(i - 1, j, 0, &iDirection, &bData);
1962                    CheckCandidateInt(i, j - 1, 0, &iDirection, &bData);
1963    
1964            } while (!(iDirection));
1965    
1966    //qpel refinement
1967            if (fData->qpel) {
1968                    if (*fData->iMinSAD > *best_sad + 500) return;
1969                    CheckCandidate = CheckCandidateInt;
1970                    fData->qpel_precision = bData.qpel_precision = 1;
1971                    get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode, 1, 0);
1972                    get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode, 1, 0);
1973                    fData->currentQMV[2].x = fData->currentQMV[0].x = 2 * fData->currentMV[0].x;
1974                    fData->currentQMV[2].y = fData->currentQMV[0].y = 2 * fData->currentMV[0].y;
1975                    fData->currentQMV[1].x = 2 * fData->currentMV[1].x;
1976                    fData->currentQMV[1].y = 2 * fData->currentMV[1].y;
1977                    SubpelRefine(fData);
1978                    if (*fData->iMinSAD > *best_sad + 300) return;
1979                    fData->currentQMV[2] = fData->currentQMV[0];
1980                    SubpelRefine(&bData);
1981            }
1982    
1983            *fData->iMinSAD += (2+3) * fData->lambda16; // two bits are needed to code interpolate mode.
1984    
1985            if (*fData->iMinSAD < *best_sad) {
1986                    *best_sad = *fData->iMinSAD;
1987                    pMB->mvs[0] = fData->currentMV[0];
1988                    pMB->b_mvs[0] = fData->currentMV[1];
1989                    pMB->mode = MODE_INTERPOLATE;
1990                    if (fData->qpel) {
1991                            pMB->qmvs[0] = fData->currentQMV[0];
1992                            pMB->b_qmvs[0] = fData->currentQMV[1];
1993                            pMB->pmvs[1].x = pMB->qmvs[0].x - f_predMV->x;
1994                            pMB->pmvs[1].y = pMB->qmvs[0].y - f_predMV->y;
1995                            pMB->pmvs[0].x = pMB->b_qmvs[0].x - b_predMV->x;
1996                            pMB->pmvs[0].y = pMB->b_qmvs[0].y - b_predMV->y;
1997                    } else {
1998                            pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;
1999                            pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;
2000                            pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;
2001                            pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;
2002                    }
2003            }
2004    }
2005    
2006          iSAD =  void
2007                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  MotionEstimationBVOP(MBParam * const pParam,
2008                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,                                           FRAMEINFO * const frame,
2009                                                    min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,                                           const int32_t time_bp,
2010                                                    iQuant, 0);                                           const int32_t time_pp,
2011                                             // forward (past) reference
2012                                             const MACROBLOCK * const f_mbs,
2013                                             const IMAGE * const f_ref,
2014                                             const IMAGE * const f_refH,
2015                                             const IMAGE * const f_refV,
2016                                             const IMAGE * const f_refHV,
2017                                             // backward (future) reference
2018                                             const FRAMEINFO * const b_reference,
2019                                             const IMAGE * const b_ref,
2020                                             const IMAGE * const b_refH,
2021                                             const IMAGE * const b_refV,
2022                                             const IMAGE * const b_refHV)
2023    {
2024            uint32_t i, j;
2025            int32_t best_sad;
2026            uint32_t skip_sad;
2027            int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;
2028            const MACROBLOCK * const b_mbs = b_reference->mbs;
2029    
2030            VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
2031    
2032          if (iSAD < iMinSAD) {          const int32_t TRB = time_pp - time_bp;
2033                  *currMV = newMV;          const int32_t TRD = time_pp;
                 iMinSAD = iSAD;  
         }  
2034    
2035          if (MotionFlags & PMV_EXTSEARCH8) {  // some pre-inintialized data for the rest of the search
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
2036    
2037                  if (!(MVequal(pmv[0], backupMV))) {          SearchData Data;
2038                          iSAD =          int32_t iMinSAD;
2039                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,          VECTOR currentMV[3];
2040                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,          VECTOR currentQMV[3];
2041                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,          int32_t temp[8];
2042                                                                    iDiamondSize, iFcode, iQuant, 0);          memset(&Data, 0, sizeof(SearchData));
2043            Data.iEdgedWidth = pParam->edged_width;
2044            Data.currentMV = currentMV; Data.currentQMV = currentQMV;
2045            Data.iMinSAD = &iMinSAD;
2046            Data.lambda16 = lambda_vec16[frame->quant];
2047            Data.qpel = pParam->vol_flags & XVID_VOL_QUARTERPEL;
2048            Data.rounding = 0;
2049            Data.chroma = frame->motion_flags & XVID_ME_CHROMA8;
2050            Data.temp = temp;
2051    
2052                          if (iSAD < iMinSAD) {          Data.RefQ = f_refV->u; // a good place, also used in MC (for similar purpose)
2053                                  *currMV = newMV;          // note: i==horizontal, j==vertical
2054                                  iMinSAD = iSAD;          for (j = 0; j < pParam->mb_height; j++) {
                         }  
                 }  
2055    
2056                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                  f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, 0);  
2057    
2058                          if (iSAD < iMinSAD) {                  for (i = 0; i < pParam->mb_width; i++) {
2059                                  *currMV = newMV;                          MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
2060                                  iMinSAD = iSAD;                          const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
2061                          }  
2062                  }  /* special case, if collocated block is SKIPed in P-VOP: encoding is forward (0,0), cpb=0 without further ado */
2063                            if (b_reference->coding_type != S_VOP)
2064                                    if (b_mb->mode == MODE_NOT_CODED) {
2065                                            pMB->mode = MODE_NOT_CODED;
2066                                            continue;
2067          }          }
2068    
2069  /***************        Choose best MV found     **************/                          Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
2070                            Data.CurU = frame->image.u + (j * Data.iEdgedWidth/2 + i) * 8;
2071    EPZS8_Terminate_with_Refine:                          Data.CurV = frame->image.v + (j * Data.iEdgedWidth/2 + i) * 8;
2072          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step                          pMB->quant = frame->quant;
2073                  iMinSAD =  
2074                          Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  /* direct search comes first, because it (1) checks for SKIP-mode
2075                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,          and (2) sets very good predictions for forward and backward search */
2076                                                          iFcode, iQuant, iEdgedWidth);                          skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2077                                                                            b_ref, b_refH->y, b_refV->y, b_refHV->y,
2078                                                                            &frame->image,
2079                                                                            i, j,
2080                                                                            frame->motion_flags,
2081                                                                            TRB, TRD,
2082                                                                            pParam,
2083                                                                            pMB, b_mb,
2084                                                                            &best_sad,
2085                                                                            &Data);
2086    
2087    EPZS8_Terminate_without_Refine:                          if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
2088    
2089          currPMV->x = currMV->x - center_x;                          // forward search
2090          currPMV->y = currMV->y - center_y;                          SearchBF(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2091          return iMinSAD;                                                  &frame->image, i, j,
2092  }                                                  frame->motion_flags,
2093                                                    frame->fcode, pParam,
2094                                                    pMB, &f_predMV, &best_sad,
2095                                                    MODE_FORWARD, &Data);
2096    
2097                            // backward search
2098                            SearchBF(b_ref, b_refH->y, b_refV->y, b_refHV->y,
2099                                                    &frame->image, i, j,
2100                                                    frame->motion_flags,
2101                                                    frame->bcode, pParam,
2102                                                    pMB, &b_predMV, &best_sad,
2103                                                    MODE_BACKWARD, &Data);
2104    
2105                            // interpolate search comes last, because it uses data from forward and backward as prediction
2106                            SearchInterpolate(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2107                                                    b_ref, b_refH->y, b_refV->y, b_refHV->y,
2108                                                    &frame->image,
2109                                                    i, j,
2110                                                    frame->fcode, frame->bcode,
2111                                                    frame->motion_flags,
2112                                                    pParam,
2113                                                    &f_predMV, &b_predMV,
2114                                                    pMB, &best_sad,
2115                                                    &Data);
2116    
2117    // final skip decision
2118                            if ( (skip_sad < frame->quant * MAX_SAD00_FOR_SKIP * 2)
2119                                            && ((100*best_sad)/(skip_sad+1) > FINAL_SKIP_THRESH) )
2120                                    SkipDecisionB(&frame->image, f_ref, b_ref, pMB, i, j, &Data);
2121    
2122                            switch (pMB->mode) {
2123                                    case MODE_FORWARD:
2124                                            f_count++;
2125                                            f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2126                                            break;
2127                                    case MODE_BACKWARD:
2128                                            b_count++;
2129                                            b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2130                                            break;
2131                                    case MODE_INTERPOLATE:
2132                                            i_count++;
2133                                            f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2134                                            b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2135                                            break;
2136                                    case MODE_DIRECT:
2137                                    case MODE_DIRECT_NO4V:
2138                                            d_count++;
2139                                    default:
2140                                            break;
2141                            }
2142                    }
2143            }
2144    }
2145    
2146  int32_t  static __inline void
2147  PMVfastIntSearch16(const uint8_t * const pRef,  MEanalyzeMB (   const uint8_t * const pRef,
2148                                  const uint8_t * const pRefH,                                  const uint8_t * const pCur,
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const IMAGE * const pCur,  
2149                                  const int x,                                  const int x,
2150                                  const int y,                                  const int y,
                                 const int start_x,              /* start should be most likely vector */  
                                 const int start_y,  
                                 const int center_x,             /* center is from where length of MVs is measured */  
                                 const int center_y,  
                                 const uint32_t MotionFlags,  
                                 const uint32_t iQuant,  
                                 const uint32_t iFcode,  
2151                                  const MBParam * const pParam,                                  const MBParam * const pParam,
2152                                  const MACROBLOCK * const pMBs,                                  MACROBLOCK * const pMBs,
2153                                  const MACROBLOCK * const prevMBs,                                  SearchData * const Data)
                                 VECTOR * const currMV,  
                                 VECTOR * const currPMV)  
2154  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
2155    
2156          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          int i, mask;
2157          const VECTOR zeroMV = { 0, 0 };          int quarterpel = (pParam->vol_flags & XVID_VOL_QUARTERPEL)? 1: 0;
2158            VECTOR pmv[3];
2159            MACROBLOCK * const pMB = &pMBs[x + y * pParam->mb_width];
2160    
2161            for (i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;
2162    
2163          int32_t iDiamondSize;          //median is only used as prediction. it doesn't have to be real
2164            if (x == 1 && y == 1) Data->predMV.x = Data->predMV.y = 0;
2165            else
2166                    if (x == 1) //left macroblock does not have any vector now
2167                            Data->predMV = (pMB - pParam->mb_width)->mvs[0]; // top instead of median
2168                    else if (y == 1) // top macroblock doesn't have it's vector
2169                            Data->predMV = (pMB - 1)->mvs[0]; // left instead of median
2170                            else Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); //else median
2171    
2172          int32_t min_dx;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2173          int32_t max_dx;          pParam->width, pParam->height, Data->iFcode - quarterpel, 0, 0);
         int32_t min_dy;  
         int32_t max_dy;  
2174    
2175          int32_t iFound;          Data->Cur = pCur + (x + y * pParam->edged_width) * 16;
2176            Data->Ref = pRef + (x + y * pParam->edged_width) * 16;
2177    
2178          VECTOR newMV;          pmv[1].x = EVEN(pMB->mvs[0].x);
2179          VECTOR backupMV;          pmv[1].y = EVEN(pMB->mvs[0].y);
2180            pmv[2].x = EVEN(Data->predMV.x);
2181            pmv[2].y = EVEN(Data->predMV.y);
2182            pmv[0].x = pmv[0].y = 0;
2183    
2184          VECTOR pmv[4];          CheckCandidate32I(0, 0, 255, &i, Data);
2185          int32_t psad[4];          Data->iMinSAD[1] -= 50;
2186            Data->iMinSAD[2] -= 50;
2187            Data->iMinSAD[3] -= 50;
2188            Data->iMinSAD[4] -= 50;
2189    
2190          MainSearch16FuncPtr MainSearchPtr;          if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP) {
2191    
2192          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;                  if (!(mask = make_mask(pmv, 1)))
2193          MACROBLOCK *const pMB = pMBs + x + y * iWcount;                          CheckCandidate32I(pmv[1].x, pmv[1].y, mask, &i, Data);
2194                    if (!(mask = make_mask(pmv, 2)))
2195                            CheckCandidate32I(pmv[2].x, pmv[2].y, mask, &i, Data);
2196    
2197          int32_t threshA, threshB;                  if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP) // diamond only if needed
2198          int32_t bPredEq;                          DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, i);
2199          int32_t iMinSAD, iSAD;          }
2200    
2201            for (i = 0; i < 4; i++) {
2202                    MACROBLOCK * MB = &pMBs[x + (i&1) + (y+(i>>1)) * pParam->mb_width];
2203                    MB->mvs[0] = MB->mvs[1] = MB->mvs[2] = MB->mvs[3] = Data->currentMV[i];
2204                    MB->mode = MODE_INTER;
2205                    MB->sad16 = Data->iMinSAD[i+1];
2206            }
2207    }
2208    
2209  /* Get maximum range */  #define INTRA_THRESH    2400
2210          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  #define INTER_THRESH    1100
                           iFcode);  
2211    
2212  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  int
2213    MEanalysis(     const IMAGE * const pRef,
2214                            const FRAMEINFO * const Current,
2215                            const MBParam * const pParam,
2216                            const int maxIntra, //maximum number if non-I frames
2217                            const int intraCount, //number of non-I frames after last I frame; 0 if we force P/B frame
2218                            const int bCount,  // number of B frames in a row
2219                            const int b_thresh)
2220    {
2221            uint32_t x, y, intra = 0;
2222            int sSAD = 0;
2223            MACROBLOCK * const pMBs = Current->mbs;
2224            const IMAGE * const pCurrent = &Current->image;
2225            int IntraThresh = INTRA_THRESH, InterThresh = INTER_THRESH + 10*b_thresh;
2226            int s = 0, blocks = 0;
2227    
2228            int32_t iMinSAD[5], temp[5];
2229            VECTOR currentMV[5];
2230            SearchData Data;
2231            Data.iEdgedWidth = pParam->edged_width;
2232            Data.currentMV = currentMV;
2233            Data.iMinSAD = iMinSAD;
2234            Data.iFcode = Current->fcode;
2235            Data.temp = temp;
2236            CheckCandidate = CheckCandidate32I;
2237    
2238          if ((x == 0) && (y == 0)) {          if (intraCount != 0 && intraCount < 10) // we're right after an I frame
2239                  threshA = 512;                  IntraThresh += 8 * (intraCount - 10) * (intraCount - 10);
2240                  threshB = 1024;          else
2241                    if ( 5*(maxIntra - intraCount) < maxIntra) // we're close to maximum. 2 sec when max is 10 sec
2242                            IntraThresh -= (IntraThresh * (maxIntra - 5*(maxIntra - intraCount)))/maxIntra;
2243    
2244                  bPredEq = 0;          InterThresh -= (350 - 8*b_thresh) * bCount;
2245                  psad[0] = psad[1] = psad[2] = psad[3] = 0;          if (InterThresh < 300 + 5*b_thresh) InterThresh = 300 + 5*b_thresh;
                 *currMV = pmv[0] = pmv[1] = pmv[2] = pmv[3] = zeroMV;  
2246    
2247          } else {          if (sadInit) (*sadInit) ();
                 threshA = psad[0];  
                 threshB = threshA + 256;  
                 if (threshA < 512)  
                         threshA = 512;  
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
   
                 bPredEq = get_ipmvdata(pMBs, iWcount, 0, x, y, 0, pmv, psad);  
                 *currMV = pmv[0];                       /* current best := prediction */  
         }  
   
         iFound = 0;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
2248    
2249          if (currMV->x > max_dx) {          for (y = 1; y < pParam->mb_height-1; y += 2) {
2250                  currMV->x = EVEN(max_dx);                  for (x = 1; x < pParam->mb_width-1; x += 2) {
2251                            int i;
2252                            blocks += 4;
2253    
2254                            if (bCount == 0) pMBs[x + y * pParam->mb_width].mvs[0] = zeroMV;
2255                            else { //extrapolation of the vector found for last frame
2256                                    pMBs[x + y * pParam->mb_width].mvs[0].x =
2257                                            (pMBs[x + y * pParam->mb_width].mvs[0].x * (bCount+1) ) / bCount;
2258                                    pMBs[x + y * pParam->mb_width].mvs[0].y =
2259                                            (pMBs[x + y * pParam->mb_width].mvs[0].y * (bCount+1) ) / bCount;
2260                            }
2261    
2262                            MEanalyzeMB(pRef->y, pCurrent->y, x, y, pParam, pMBs, &Data);
2263    
2264                            for (i = 0; i < 4; i++) {
2265                                    int dev;
2266                                    MACROBLOCK *pMB = &pMBs[x+(i&1) + (y+(i>>1)) * pParam->mb_width];
2267                                    if (pMB->sad16 > IntraThresh) {
2268                                            dev = dev16(pCurrent->y + (x + (i&1) + (y + (i>>1)) * pParam->edged_width) * 16,
2269                                                                            pParam->edged_width);
2270                                            if (dev + IntraThresh < pMB->sad16) {
2271                                                    pMB->mode = MODE_INTRA;
2272                                                    if (++intra > ((pParam->mb_height-2)*(pParam->mb_width-2))/2) return I_VOP;
2273          }          }
         if (currMV->x < min_dx) {  
                 currMV->x = EVEN(min_dx);  
2274          }          }
2275          if (currMV->y > max_dy) {                                  if (pMB->mvs[0].x == 0 && pMB->mvs[0].y == 0) s++;
2276                  currMV->y = EVEN(max_dy);  
2277                                    sSAD += pMB->sad16;
2278                            }
2279          }          }
         if (currMV->y < min_dy) {  
                 currMV->y = EVEN(min_dy);  
2280          }          }
2281    
2282          iMinSAD =          sSAD /= blocks;
2283                  sad16(cur,          s = (10*s) / blocks;
                           get_iref_mv(pRef, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
2284    
2285          if ((iMinSAD < 256) ||          if (s > 5) sSAD += (s - 4) * (180 - 2*b_thresh); //static block - looks bad when in bframe...
                 ((MVequal(*currMV, prevMB->i_mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->i_sad16))) {  
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
                 {  
                         if (!MVzero(*currMV)) {  
                                 iMinSAD += MV16_00_BIAS;  
                                 CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures  
                                 iMinSAD -= MV16_00_BIAS;  
                         }  
                 }  
2286    
2287                  if (MotionFlags & PMV_EARLYSTOP16)          if (sSAD > InterThresh ) return P_VOP;
2288                          goto PMVfastInt16_Terminate_with_Refine;          emms();
2289            return B_VOP;
2290          }          }
2291    
2292    
2293  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  static WARPPOINTS
2294     vector of the median.  GlobalMotionEst(const MACROBLOCK * const pMBs,
2295     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2                                  const MBParam * const pParam,
2296  */                                  const FRAMEINFO * const current,
2297                                    const FRAMEINFO * const reference,
2298          if ((bPredEq) && (MVequal(pmv[0], prevMB->i_mvs[0])))                                  const IMAGE * const pRefH,
2299                  iFound = 2;                                  const IMAGE * const pRefV,
2300                                    const IMAGE * const pRefHV      )
2301    {
2302    
2303  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          const int deltax=8;             // upper bound for difference between a MV and it's neighbour MVs
2304     Otherwise select large Diamond Search.          const int deltay=8;
2305  */          const int grad=512;             // lower bound for deviation in MB
2306    
2307          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))          WARPPOINTS gmc;
                 iDiamondSize = 2;               // halfpel units!  
         else  
                 iDiamondSize = 4;               // halfpel units!  
2308    
2309  /*          uint32_t mx, my;
    Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  
    Also calculate (0,0) but do not subtract offset.  
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset.  
 */  
2310    
2311  // (0,0) is often a good choice          int MBh = pParam->mb_height;
2312            int MBw = pParam->mb_width;
2313    
2314          if (!MVzero(pmv[0]))          int *MBmask= calloc(MBh*MBw,sizeof(int));
2315                  CHECK_MV16_ZERO;          double DtimesF[4] = { 0.,0., 0., 0. };
2316            double sol[4] = { 0., 0., 0., 0. };
2317            double a,b,c,n,denom;
2318            double meanx,meany;
2319            int num,oldnum;
2320    
2321  // previous frame MV is always possible          if (!MBmask) { fprintf(stderr,"Mem error\n");
2322                                   gmc.duv[0].x= gmc.duv[0].y =
2323                                                    gmc.duv[1].x= gmc.duv[1].y =
2324                                                    gmc.duv[2].x= gmc.duv[2].y = 0;
2325                                            return gmc; }
2326    
2327          if (!MVzero(prevMB->i_mvs[0]))  // filter mask of all blocks
                 if (!MVequal(prevMB->i_mvs[0], pmv[0]))  
                         CHECK_MV16_CANDIDATE(prevMB->i_mvs[0].x, prevMB->i_mvs[0].y);  
   
 // left neighbour, if allowed  
   
         if (!MVzero(pmv[1]))  
                 if (!MVequal(pmv[1], prevMB->i_mvs[0]))  
                         if (!MVequal(pmv[1], pmv[0]))  
                                 CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
   
 // top neighbour, if allowed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], prevMB->i_mvs[0]))  
                         if (!MVequal(pmv[2], pmv[0]))  
                                 if (!MVequal(pmv[2], pmv[1]))  
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed  
                                         if (!MVzero(pmv[3]))  
                                                 if (!MVequal(pmv[3], prevMB->i_mvs[0]))  
                                                         if (!MVequal(pmv[3], pmv[0]))  
                                                                 if (!MVequal(pmv[3], pmv[1]))  
                                                                         if (!MVequal(pmv[3], pmv[2]))  
                                                                                 CHECK_MV16_CANDIDATE(pmv[3].x,  
                                                                                                                          pmv[3].y);  
   
         if ((MVzero(*currMV)) &&  
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV16_00_BIAS;  
2328    
2329            for (my = 1; my < (uint32_t)MBh-1; my++)
2330            for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2331            {
2332                    const int mbnum = mx + my * MBw;
2333                    const MACROBLOCK *pMB = &pMBs[mbnum];
2334                    const VECTOR mv = pMB->mvs[0];
2335    
2336  /* Step 6: If MinSAD <= thresa goto Step 10.                  if (pMB->mode == MODE_INTRA || pMB->mode == MODE_NOT_CODED)
2337     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.                          continue;
 */  
2338    
2339          if ((iMinSAD <= threshA) ||                  if ( ( (ABS(mv.x -   (pMB-1)->mvs[0].x) < deltax) && (ABS(mv.y -   (pMB-1)->mvs[0].y) < deltay) )
2340                  (MVequal(*currMV, prevMB->i_mvs[0]) &&                  &&   ( (ABS(mv.x -   (pMB+1)->mvs[0].x) < deltax) && (ABS(mv.y -   (pMB+1)->mvs[0].y) < deltay) )
2341                   ((int32_t) iMinSAD < prevMB->i_sad16))) {                  &&   ( (ABS(mv.x - (pMB-MBw)->mvs[0].x) < deltax) && (ABS(mv.y - (pMB-MBw)->mvs[0].y) < deltay) )
2342                    &&   ( (ABS(mv.x - (pMB+MBw)->mvs[0].x) < deltax) && (ABS(mv.y - (pMB+MBw)->mvs[0].y) < deltay) ) )
2343                  if (MotionFlags & PMV_EARLYSTOP16)                          MBmask[mbnum]=1;
                         goto PMVfastInt16_Terminate_with_Refine;  
2344          }          }
2345    
2346            for (my = 1; my < (uint32_t)MBh-1; my++)
2347            for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2348            {
2349                    const uint8_t *const pCur = current->image.y + 16*my*pParam->edged_width + 16*mx;
2350    
2351  /************ (Diamond Search)  **************/                  const int mbnum = mx + my * MBw;
2352  /*                  if (!MBmask[mbnum])
2353     Step 7: Perform Diamond search, with either the small or large diamond.                          continue;
    If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
    Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
    If center then goto step 10.  
    Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
    Refine by using small diamond and goto step 10.  
 */  
   
         if (MotionFlags & PMV_USESQUARES16)  
                 MainSearchPtr = Square16_MainSearch;  
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
2354    
2355          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                  if (sad16 ( pCur, pCur+1 , pParam->edged_width, 65536) <= (uint32_t)grad )
2356                            MBmask[mbnum] = 0;
2357                    if (sad16 ( pCur, pCur+pParam->edged_width, pParam->edged_width, 65536) <= (uint32_t)grad )
2358                            MBmask[mbnum] = 0;
2359    
2360            }
2361    
2362  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          emms();
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  
                                                   currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
2363    
2364          if (iSAD < iMinSAD) {          do {            /* until convergence */
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
2365    
2366          if (MotionFlags & PMV_EXTSEARCH16) {          a = b = c = n = 0;
2367  /* extended: search (up to) two more times: orignal prediction and (0,0) */          DtimesF[0] = DtimesF[1] = DtimesF[2] = DtimesF[3] = 0.;
2368            for (my = 0; my < (uint32_t)MBh; my++)
2369                    for (mx = 0; mx < (uint32_t)MBw; mx++)
2370                    {
2371                            const int mbnum = mx + my * MBw;
2372                            const MACROBLOCK *pMB = &pMBs[mbnum];
2373                            const VECTOR mv = pMB->mvs[0];
2374    
2375                  if (!(MVequal(pmv[0], backupMV))) {                          if (!MBmask[mbnum])
2376                          iSAD =                                  continue;
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
2377    
2378                          if (iSAD < iMinSAD) {                          n++;
2379                                  *currMV = newMV;                          a += 16*mx+8;
2380                                  iMinSAD = iSAD;                          b += 16*my+8;
2381                          }                          c += (16*mx+8)*(16*mx+8)+(16*my+8)*(16*my+8);
2382                  }  
2383                            DtimesF[0] += (double)mv.x;
2384                            DtimesF[1] += (double)mv.x*(16*mx+8) + (double)mv.y*(16*my+8);
2385                            DtimesF[2] += (double)mv.x*(16*my+8) - (double)mv.y*(16*mx+8);
2386                            DtimesF[3] += (double)mv.y;
2387                    }
2388    
2389            denom = a*a+b*b-c*n;
2390    
2391    /* Solve the system:     sol = (D'*E*D)^{-1} D'*E*F   */
2392    /* D'*E*F has been calculated in the same loop as matrix */
2393    
2394            sol[0] = -c*DtimesF[0] + a*DtimesF[1] + b*DtimesF[2];
2395            sol[1] =  a*DtimesF[0] - n*DtimesF[1]                + b*DtimesF[3];
2396            sol[2] =  b*DtimesF[0]                - n*DtimesF[2] - a*DtimesF[3];
2397            sol[3] =                 b*DtimesF[1] - a*DtimesF[2] - c*DtimesF[3];
2398    
2399            sol[0] /= denom;
2400            sol[1] /= denom;
2401            sol[2] /= denom;
2402            sol[3] /= denom;
2403    
2404            meanx = meany = 0.;
2405            oldnum = 0;
2406            for (my = 0; my < (uint32_t)MBh; my++)
2407                    for (mx = 0; mx < (uint32_t)MBw; mx++)
2408                    {
2409                            const int mbnum = mx + my * MBw;
2410                            const MACROBLOCK *pMB = &pMBs[mbnum];
2411                            const VECTOR mv = pMB->mvs[0];
2412    
2413                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                          if (!MBmask[mbnum])
2414                          iSAD =                                  continue;
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
2415    
2416                          if (iSAD < iMinSAD) {                          oldnum++;
2417                                  *currMV = newMV;                          meanx += ABS(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - mv.x );
2418                                  iMinSAD = iSAD;                          meany += ABS(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - mv.y );
                         }  
2419                  }                  }
         }  
   
 /*  
    Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  
 */  
2420    
2421  PMVfastInt16_Terminate_with_Refine:          if (4*meanx > oldnum)   /* better fit than 0.25 is useless */
2422                    meanx /= oldnum;
2423            else
2424                    meanx = 0.25;
2425    
2426          pMB->i_mvs[0] = pMB->i_mvs[1] = pMB->i_mvs[2] = pMB->i_mvs[3] = pMB->i_mv16 = *currMV;          if (4*meany > oldnum)
2427          pMB->i_sad8[0] = pMB->i_sad8[1] = pMB->i_sad8[2] = pMB->i_sad8[3] = pMB->i_sad16 = iMinSAD;                  meany /= oldnum;
2428            else
2429                    meany = 0.25;
2430    
2431          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step  /*      fprintf(stderr,"sol = (%8.5f, %8.5f, %8.5f, %8.5f)\n",sol[0],sol[1],sol[2],sol[3]);
2432                  iMinSAD =          fprintf(stderr,"meanx = %8.5f  meany = %8.5f   %d\n",meanx,meany, oldnum);
2433                          Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  */
2434                                                           iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,          num = 0;
2435                                                           iFcode, iQuant, iEdgedWidth);          for (my = 0; my < (uint32_t)MBh; my++)
2436                    for (mx = 0; mx < (uint32_t)MBw; mx++)
2437                    {
2438                            const int mbnum = mx + my * MBw;
2439                            const MACROBLOCK *pMB = &pMBs[mbnum];
2440                            const VECTOR mv = pMB->mvs[0];
2441    
2442          pmv[0] = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          // get _REAL_ prediction (halfpel possible)                          if (!MBmask[mbnum])
2443                                    continue;
2444    
2445  PMVfastInt16_Terminate_without_Refine:                          if  ( ( ABS(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - mv.x ) > meanx )
2446          currPMV->x = currMV->x - center_x;                             || ( ABS(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - mv.y ) > meany ) )
2447          currPMV->y = currMV->y - center_y;                                  MBmask[mbnum]=0;
2448          return iMinSAD;                          else
2449                                    num++;
2450  }  }
2451    
2452            } while ( (oldnum != num) && (num>=4) );
2453    
2454            if (num < 4)
2455            {
2456                    gmc.duv[0].x= gmc.duv[0].y= gmc.duv[1].x= gmc.duv[1].y= gmc.duv[2].x= gmc.duv[2].y=0;
2457            } else {
2458    
2459  /* ***********************************************************                  gmc.duv[0].x=(int)(sol[0]+0.5);
2460          bvop motion estimation                  gmc.duv[0].y=(int)(sol[3]+0.5);
 ***************************************************************/  
2461    
2462  void                  gmc.duv[1].x=(int)(sol[1]*pParam->width+0.5);
2463  MotionEstimationBVOP(MBParam * const pParam,                  gmc.duv[1].y=(int)(-sol[2]*pParam->width+0.5);
                                          FRAMEINFO * const frame,  
                                          const int32_t time_bp,  
                                          const int32_t time_pp,  
                                          // forward (past) reference  
                                          const MACROBLOCK * const f_mbs,  
                                          const IMAGE * const f_ref,  
                                          const IMAGE * const f_refH,  
                                          const IMAGE * const f_refV,  
                                          const IMAGE * const f_refHV,  
                                          // backward (future) reference  
                                          const MACROBLOCK * const b_mbs,  
                                          const IMAGE * const b_ref,  
                                          const IMAGE * const b_refH,  
                                          const IMAGE * const b_refV,  
                                          const IMAGE * const b_refHV)  
 {  
         const int mb_width = pParam->mb_width;  
         const int mb_height = pParam->mb_height;  
         const int edged_width = pParam->edged_width;  
2464    
2465          const int32_t iWidth = pParam->width;                  gmc.duv[2].x=0;
2466          const int32_t iHeight = pParam->height;                  gmc.duv[2].y=0;
2467            }
2468    //      fprintf(stderr,"wp1 = ( %4d, %4d)  wp2 = ( %4d, %4d) \n", gmc.duv[0].x, gmc.duv[0].y, gmc.duv[1].x, gmc.duv[1].y);
2469    
2470          int i, j, k;          free(MBmask);
2471    
2472          static const VECTOR zeroMV={0,0};          return gmc;
2473    }
2474    
2475          int f_sad16;    /* forward (as usual) search */  // functions which perform BITS-based search/bitcount
         int b_sad16;    /* backward (only in b-frames) search */  
         int i_sad16;    /* interpolated (both direction, b-frames only) */  
         int d_sad16;    /* direct mode (assume almost linear motion) */  
2476    
2477          int best_sad;  static int
2478    CountMBBitsInter(SearchData * const Data,
2479                                    const MACROBLOCK * const pMBs, const int x, const int y,
2480                                    const MBParam * const pParam,
2481                                    const uint32_t MotionFlags)
2482    {
2483            int i, iDirection;
2484            int32_t bsad[5];
2485    
2486          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/          CheckCandidate = CheckCandidateBits16;
         VECTOR f_interpolMV, b_interpolMV;  
         VECTOR pmv_dontcare;  
2487    
2488          int min_dx, max_dx, min_dy, max_dy;          if (Data->qpel) {
2489          int f_min_dx, f_max_dx, f_min_dy, f_max_dy;                  for(i = 0; i < 5; i++) {
2490          int b_min_dx, b_max_dx, b_min_dy, b_max_dy;                          Data->currentMV[i].x = Data->currentQMV[i].x/2;
2491                            Data->currentMV[i].y = Data->currentQMV[i].y/2;
2492          int f_count=0;                  }
2493          int b_count=0;                  Data->qpel_precision = 1;
2494          int i_count=0;                  CheckCandidateBits16(Data->currentQMV[0].x, Data->currentQMV[0].y, 255, &iDirection, Data);
         int d_count=0;  
2495    
2496          const int64_t TRB = (int32_t)time_pp - (int32_t)time_bp;                  //checking if this vector is perfect. if it is, we stop.
2497      const int64_t TRD = (int32_t)time_pp;                  if (Data->temp[0] == 0 && Data->temp[1] == 0 && Data->temp[2] == 0 && Data->temp[3] == 0)
2498                            return 0; //quick stop
2499    
2500          // fprintf(stderr,"TRB = %lld  TRD = %lld  time_bp =%d time_pp =%d\n\n",TRB,TRD,time_bp,time_pp);                  if (MotionFlags & (XVID_ME_HALFPELREFINE16_BITS | XVID_ME_EXTSEARCH_BITS)) { //we have to prepare for halfpixel-precision search
2501          // note: i==horizontal, j==vertical                          for(i = 0; i < 5; i++) bsad[i] = Data->iMinSAD[i];
2502          for (j = 0; j < mb_height; j++) {                          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2503                                                    pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
2504                            Data->qpel_precision = 0;
2505                            if (Data->currentQMV->x & 1 || Data->currentQMV->y & 1)
2506                                    CheckCandidateBits16(Data->currentMV[0].x, Data->currentMV[0].y, 255, &iDirection, Data);
2507                    }
2508    
2509                  f_predMV = zeroMV;      /* prediction is reset at left boundary */          } else { // not qpel
                 b_predMV = zeroMV;  
2510    
2511                  for (i = 0; i < mb_width; i++) {                  CheckCandidateBits16(Data->currentMV[0].x, Data->currentMV[0].y, 255, &iDirection, Data);
2512                          MACROBLOCK *mb = &frame->mbs[i + j * mb_width];                  //checking if this vector is perfect. if it is, we stop.
2513                          const MACROBLOCK *f_mb = &f_mbs[i + j * mb_width];                  if (Data->temp[0] == 0 && Data->temp[1] == 0 && Data->temp[2] == 0 && Data->temp[3] == 0) {
2514                          const MACROBLOCK *b_mb = &b_mbs[i + j * mb_width];                          return 0; //inter
2515                    }
                         mb->deltamv=zeroMV;  
   
 /* special case, if collocated block is SKIPed: encoding is forward (0,0), cpb=0 without further ado */  
   
 #ifndef _DISABLE_SKIP  
                         if (b_mb->mode == MODE_INTER && b_mb->cbp == 0 &&  
                                 b_mb->mvs[0].x == 0 && b_mb->mvs[0].y == 0) {  
                                 mb->mode = MODE_NOT_CODED;  
                                 mb->mvs[0].x = 0;  
                                 mb->mvs[0].y = 0;  
                                 mb->b_mvs[0].x = 0;  
                                 mb->b_mvs[0].y = 0;  
                                 continue;  
2516                          }                          }
 #endif  
2517    
2518                          if (b_mb->mode == MODE_INTER4V)          if (MotionFlags&XVID_ME_EXTSEARCH_BITS) SquareSearch(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
                         {  
                                 d_sad16 = 0;  
                         /* same method of scaling as in decoder.c, so we copy from there */  
                     for (k = 0; k < 4; k++) {  
2519    
2520                                          mb->directmv[k] = b_mb->mvs[k];          if (MotionFlags&XVID_ME_HALFPELREFINE16_BITS) SubpelRefine(Data);
2521    
2522                                          mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);          if (Data->qpel) {
2523                      mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)                  if (MotionFlags&(XVID_ME_EXTSEARCH_BITS | XVID_ME_HALFPELREFINE16_BITS)) { // there was halfpel-precision search
2524                                                                                  ? ((TRB - TRD) * mb->directmv[k].x) / TRD                          for(i = 0; i < 5; i++) if (bsad[i] > Data->iMinSAD[i]) {
2525                                              : mb->mvs[k].x - mb->directmv[k].x);                                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // we have found a better match
2526                                    Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
                     mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);  
                         mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)  
                                                                                 ? ((TRB - TRD) * mb->directmv[k].y) / TRD  
                                             : mb->mvs[k].y - mb->directmv[k].y);  
   
                                         d_sad16 +=  
                                                 sad8bi(frame->image.y + 2*(i+(k&1))*8 + 2*(j+(k>>1))*8*edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 2*(i+(k&1)), 2*(j+(k>>1)), 8, &mb->mvs[k], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 2*(i+(k&1)), 2*(j+(k>>1)), 8, &mb->b_mvs[k], edged_width),  
                                                   edged_width);  
2527                                  }                                  }
                         }  
                         else  
                         {  
                                 mb->directmv[3] = mb->directmv[2] = mb->directmv[1] =  
                                         mb->directmv[0] = b_mb->mvs[0];  
2528    
2529                                  mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);                          // preparing for qpel-precision search
2530                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)                          Data->qpel_precision = 1;
2531                                                                          ? ((TRB - TRD) * mb->directmv[0].x) / TRD                          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2532                                      : mb->mvs[0].x - mb->directmv[0].x);                                          pParam->width, pParam->height, Data->iFcode, 1, 0);
2533                    }
2534                      mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);                  if (MotionFlags&XVID_ME_QUARTERPELREFINE16_BITS) SubpelRefine(Data);
2535                  mb->b_mvs[0].y = (int32_t) ((mb->directmv[0].y == 0)          }
                                                                         ? ((TRB - TRD) * mb->directmv[0].y) / TRD  
                                     : mb->mvs[0].y - mb->directmv[0].y);  
   
                                 d_sad16 = sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 i, j, 16, &mb->mvs[0], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 i, j, 16, &mb->b_mvs[0], edged_width),  
                                                   edged_width);  
2536    
2537            if (MotionFlags&XVID_ME_CHECKPREDICTION_BITS) { //let's check vector equal to prediction
2538                    VECTOR * v = Data->qpel ? Data->currentQMV : Data->currentMV;
2539                    if (!(Data->predMV.x == v->x && Data->predMV.y == v->y))
2540                            CheckCandidateBits16(Data->predMV.x, Data->predMV.y, 255, &iDirection, Data);
2541            }
2542            return Data->iMinSAD[0];
2543              }              }
                     d_sad16 += calc_delta_16(mb->deltamv.x, mb->deltamv.y, 1, frame->quant);  
2544    
                         // forward search  
                         f_sad16 = SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 &frame->image, i, j,  
                                                 mb->mvs[0].x, mb->mvs[0].y,                     /* start point f_directMV */  
                                                 f_predMV.x, f_predMV.y,                         /* center is f-prediction */  
                                                 frame->motion_flags,  
                                                 frame->quant, frame->fcode, pParam,  
                                                 f_mbs, f_mbs,  
                                                 &mb->mvs[0], &pmv_dontcare);  
2545    
2546    static int
2547    CountMBBitsInter4v(const SearchData * const Data,
2548                                            MACROBLOCK * const pMB, const MACROBLOCK * const pMBs,
2549                                            const int x, const int y,
2550                                            const MBParam * const pParam, const uint32_t MotionFlags,
2551                                            const VECTOR * const backup)
2552    {
2553    
2554                          // backward search          int cbp = 0, bits = 0, t = 0, i, iDirection;
2555                          b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,          SearchData Data2, *Data8 = &Data2;
2556                                                  &frame->image, i, j,          int sumx = 0, sumy = 0;
2557                                                  mb->b_mvs[0].x, mb->b_mvs[0].y,         /* start point b_directMV */          int16_t *in = Data->dctSpace, *coeff = Data->dctSpace + 64;
2558                                                  b_predMV.x, b_predMV.y,                         /* center is b-prediction */  
2559                                                  frame->motion_flags,          memcpy(Data8, Data, sizeof(SearchData));
2560                                                  frame->quant, frame->bcode, pParam,          CheckCandidate = CheckCandidateBits8;
2561                                                  b_mbs, b_mbs,  
2562                                                  &mb->b_mvs[0], &pmv_dontcare);          for (i = 0; i < 4; i++) {
2563                    Data8->iMinSAD = Data->iMinSAD + i + 1;
2564                          i_sad16 =                  Data8->currentMV = Data->currentMV + i + 1;
2565                                  sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,                  Data8->currentQMV = Data->currentQMV + i + 1;
2566                                                    get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,                  Data8->Cur = Data->Cur + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2567                                                                  i, j, 16, &mb->mvs[0], edged_width),                  Data8->Ref = Data->Ref + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2568                                                    get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,                  Data8->RefH = Data->RefH + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2569                                                                  i, j, 16, &mb->b_mvs[0], edged_width),                  Data8->RefV = Data->RefV + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2570                                                    edged_width);                  Data8->RefHV = Data->RefHV + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2571                      i_sad16 += calc_delta_16(mb->mvs[0].x-f_predMV.x, mb->mvs[0].y-f_predMV.y,  
2572                                                                  frame->fcode, frame->quant);                  if(Data->qpel) {
2573                      i_sad16 += calc_delta_16(mb->b_mvs[0].x-b_predMV.x, mb->b_mvs[0].y-b_predMV.y,                          Data8->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, i);
2574                                                                  frame->bcode, frame->quant);                          if (i != 0)     t = d_mv_bits(  Data8->currentQMV->x, Data8->currentQMV->y,
2575                                                                                    Data8->predMV, Data8->iFcode, 0, 0);
                         get_range(&f_min_dx, &f_max_dx, &f_min_dy, &f_max_dy, i, j, 16, iWidth, iHeight,  
                           frame->fcode);  
                         get_range(&b_min_dx, &b_max_dx, &b_min_dy, &b_max_dy, i, j, 16, iWidth, iHeight,  
                           frame->bcode);  
   
 /* Interpolated MC motion vector search, this is tedious and more complicated because there are  
    two values for everything, always one for backward and one for forward ME. Still, we don't gain  
    much from this search, maybe it should simply be skipped and simply current i_sad16 value used  
    as "optimal". */  
   
                         i_sad16 = Diamond16_InterpolMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i * 16 + j * 16 * edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 mb->mvs[0].x, mb->mvs[0].y,  
                                                 mb->b_mvs[0].x, mb->b_mvs[0].y,  
                                                 i_sad16,  
                                                 &f_interpolMV, &b_interpolMV,  
                                                 f_predMV.x, f_predMV.y, b_predMV.x, b_predMV.y,  
                                                 f_min_dx, f_max_dx, f_min_dy, f_max_dy,  
                                                 b_min_dx, b_max_dx, b_min_dy, b_max_dy,  
                                                 edged_width,  1,  
                                                 frame->fcode, frame->bcode,frame->quant,0);  
   
   
 /*  DIRECT MODE DELTA VECTOR SEARCH.  
     This has to be made more effective, but at the moment I'm happy it's running at all */  
   
 /* range is taken without fcode restriction, just a hack instead of writing down the dimensions, of course */  
   
                         get_range(&min_dx, &max_dx, &min_dy, &max_dy, i, j, 16, iWidth, iHeight, 19);  
   
                         d_sad16 = Diamond16_DirectMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i*16 + j*16*edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 TRB,TRD,  
                                                 0,0,  
                                                 d_sad16,  
                                                 &mb->deltamv,  
                                                 mb->directmv, // this has to be pre-initialized with b_mb->mvs[}  
                                         min_dx, max_dx, min_dy, max_dy,  
                                                 edged_width, 1, frame->quant, 0);  
   
   
 //                      i_sad16 = 65535;                /* remove the comment to disable any of the MODEs */  
 //                      f_sad16 = 65535;  
 //                      b_sad16 = 65535;  
 //                      d_sad16 = 65535;  
   
                         if (f_sad16 < b_sad16) {  
                                 best_sad = f_sad16;  
                                 mb->mode = MODE_FORWARD;  
2576                          } else {                          } else {
2577                                  best_sad = b_sad16;                          Data8->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, i);
2578                                  mb->mode = MODE_BACKWARD;                          if (i != 0)     t = d_mv_bits(  Data8->currentMV->x, Data8->currentMV->y,
2579                                                                                    Data8->predMV, Data8->iFcode, 0, 0);
2580                          }                          }
2581    
2582                          if (i_sad16 < best_sad) {                  get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 8,
2583                                  best_sad = i_sad16;                                          pParam->width, pParam->height, Data8->iFcode, Data8->qpel, 0);
2584                                  mb->mode = MODE_INTERPOLATE;  
2585                    *Data8->iMinSAD += t;
2586    
2587                    Data8->qpel_precision = Data8->qpel;
2588                    // checking the vector which has been found by SAD-based 8x8 search (if it's different than the one found so far)
2589                    if (Data8->qpel) {
2590                            if (!(Data8->currentQMV->x == backup[i+1].x && Data8->currentQMV->y == backup[i+1].y))
2591                                    CheckCandidateBits8(backup[i+1].x, backup[i+1].y, 255, &iDirection, Data8);
2592                    } else {
2593                            if (!(Data8->currentMV->x == backup[i+1].x && Data8->currentMV->y == backup[i+1].y))
2594                                    CheckCandidateBits8(backup[i+1].x, backup[i+1].y, 255, &iDirection, Data8);
2595                          }                          }
2596    
2597                          if (d_sad16 < best_sad) {                  if (Data8->qpel) {
2598                            if (MotionFlags&XVID_ME_HALFPELREFINE8_BITS || (MotionFlags&XVID_ME_EXTSEARCH8 && MotionFlags&XVID_ME_EXTSEARCH_BITS)) { // halfpixel motion search follows
2599                                    int32_t s = *Data8->iMinSAD;
2600                                    Data8->currentMV->x = Data8->currentQMV->x/2;
2601                                    Data8->currentMV->y = Data8->currentQMV->y/2;
2602                                    Data8->qpel_precision = 0;
2603                                    get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 8,
2604                                                            pParam->width, pParam->height, Data8->iFcode - 1, 0, 0);
2605    
2606                                  if (b_mb->mode == MODE_INTER4V)                                  if (Data8->currentQMV->x & 1 || Data8->currentQMV->y & 1)
2607                                  {                                          CheckCandidateBits8(Data8->currentMV->x, Data8->currentMV->y, 255, &iDirection, Data8);
2608    
2609                                  /* how to calc vectors is defined in standard. mvs[] and b_mvs[] are only for motion compensation */                                  if (MotionFlags & XVID_ME_EXTSEARCH8 && MotionFlags & XVID_ME_EXTSEARCH_BITS)
2610                                  /* for the bitstream, the value mb->deltamv is read directly */                                          SquareSearch(Data8->currentMV->x, Data8->currentMV->x, Data8, 255);
2611    
2612                              for (k = 0; k < 4; k++) {                                  if (MotionFlags & XVID_ME_HALFPELREFINE8_BITS) SubpelRefine(Data8);
2613    
2614                                                  mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);                                  if(s > *Data8->iMinSAD) { //we have found a better match
2615                              mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)                                          Data8->currentQMV->x = 2*Data8->currentMV->x;
2616                                                                                          ? ((TRB - TRD) * mb->directmv[k].x) / TRD                                          Data8->currentQMV->y = 2*Data8->currentMV->y;
                                                     : mb->mvs[k].x - mb->directmv[k].x);  
   
                             mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);  
                         mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)  
                                                                                         ? ((TRB - TRD) * mb->directmv[k].y) / TRD  
                                             : mb->mvs[k].y - mb->directmv[k].y);  
2617                                          }                                          }
                                 }  
                                 else  
                                 {  
                                         mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);  
2618    
2619                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)                                  Data8->qpel_precision = 1;
2620                                                                                  ? ((TRB - TRD) * mb->directmv[0].x) / TRD                                  get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 8,
2621                                          : mb->mvs[0].x - mb->directmv[0].x);                                                          pParam->width, pParam->height, Data8->iFcode, 1, 0);
2622    
2623                              mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);                          }
2624                            if (MotionFlags & XVID_ME_QUARTERPELREFINE8_BITS) SubpelRefine(Data8);
2625    
2626                          mb->b_mvs[0].y = (int32_t) ((mb->deltamv.y == 0)                  } else // not qpel
2627                                                                                  ? ((TRB - TRD) * mb->directmv[0].y) / TRD                          if (MotionFlags & XVID_ME_HALFPELREFINE8_BITS) SubpelRefine(Data8); //halfpel mode, halfpel refinement
                                             : mb->mvs[0].y - mb->directmv[0].y);  
2628    
2629                                          mb->mvs[3] = mb->mvs[2] = mb->mvs[1] = mb->mvs[0];                  //checking vector equal to predicion
2630                                          mb->b_mvs[3] = mb->b_mvs[2] = mb->b_mvs[1] = mb->b_mvs[0];                  if (i != 0 && MotionFlags & XVID_ME_CHECKPREDICTION_BITS) {
2631                            const VECTOR * v = Data->qpel ? Data8->currentQMV : Data8->currentMV;
2632                            if (!(Data8->predMV.x == v->x && Data8->predMV.y == v->y))
2633                                    CheckCandidateBits8(Data8->predMV.x, Data8->predMV.y, 255, &iDirection, Data8);
2634                  }                  }
2635    
2636                                  best_sad = d_sad16;                  bits += *Data8->iMinSAD;
2637                                  mb->mode = MODE_DIRECT;                  if (bits >= Data->iMinSAD[0]) break; // no chances for INTER4V
                         }  
2638    
2639                          switch (mb->mode)                  // MB structures for INTER4V mode; we have to set them here, we don't have predictor anywhere else
2640                          {                  if(Data->qpel) {
2641                                  case MODE_FORWARD:                          pMB->pmvs[i].x = Data8->currentQMV->x - Data8->predMV.x;
2642                                          f_count++;                          pMB->pmvs[i].y = Data8->currentQMV->y - Data8->predMV.y;
2643                                          f_predMV = mb->mvs[0];                          pMB->qmvs[i] = *Data8->currentQMV;
2644                                          break;                          sumx += Data8->currentQMV->x/2;
2645                                  case MODE_BACKWARD:                          sumy += Data8->currentQMV->y/2;
2646                                          b_count++;                  } else {
2647                                          b_predMV = mb->b_mvs[0];                          pMB->pmvs[i].x = Data8->currentMV->x - Data8->predMV.x;
2648                            pMB->pmvs[i].y = Data8->currentMV->y - Data8->predMV.y;
2649                            sumx += Data8->currentMV->x;
2650                            sumy += Data8->currentMV->y;
2651                    }
2652                    pMB->mvs[i] = *Data8->currentMV;
2653                    pMB->sad8[i] = 4 * *Data8->iMinSAD;
2654                    if (Data8->temp[0]) cbp |= 1 << (5 - i);
2655            }
2656    
2657            if (bits < *Data->iMinSAD) { // there is still a chance for inter4v mode. let's check chroma
2658                    const uint8_t * ptr;
2659                    sumx = (sumx >> 3) + roundtab_76[sumx & 0xf];
2660                    sumy = (sumy >> 3) + roundtab_76[sumy & 0xf];
2661    
2662                    //chroma U
2663                    ptr = interpolate8x8_switch2(Data->RefQ + 64, Data->RefCU, 0, 0, sumx, sumy, Data->iEdgedWidth/2, Data->rounding);
2664                    transfer_8to16subro(in, Data->CurU, ptr, Data->iEdgedWidth/2);
2665                    fdct(in);
2666                    if (Data->lambda8 == 0) i = quant_inter(coeff, in, Data->lambda16);
2667                    else i = quant4_inter(coeff, in, Data->lambda16);
2668                    if (i > 0) {
2669                            bits += CodeCoeffInter_CalcBits(coeff, scan_tables[0]);
2670                            cbp |= 1 << (5 - 4);
2671                    }
2672    
2673                    if (bits < *Data->iMinSAD) { // still possible
2674                            //chroma V
2675                            ptr = interpolate8x8_switch2(Data->RefQ + 64, Data->RefCV, 0, 0, sumx, sumy, Data->iEdgedWidth/2, Data->rounding);
2676                            transfer_8to16subro(in, Data->CurV, ptr, Data->iEdgedWidth/2);
2677                            fdct(in);
2678                            if (Data->lambda8 == 0) i = quant_inter(coeff, in, Data->lambda16);
2679                            else i = quant4_inter(coeff, in, Data->lambda16);
2680                            if (i > 0) {
2681                                    bits += CodeCoeffInter_CalcBits(coeff, scan_tables[0]);
2682                                    cbp |= 1 << (5 - 5);
2683                            }
2684                            bits += xvid_cbpy_tab[15-(cbp>>2)].len;
2685                            bits += mcbpc_inter_tab[(MODE_INTER4V & 7) | ((cbp & 3) << 3)].len;
2686                    }
2687            }
2688    
2689            return bits;
2690    }
2691    
2692    
2693    static int
2694    CountMBBitsIntra(const SearchData * const Data)
2695    {
2696            int bits = 1; //this one is ac/dc prediction flag. always 1.
2697            int cbp = 0, i, t, dc = 0, b_dc = 1024;
2698            const uint32_t iQuant = Data->lambda16;
2699            int16_t *in = Data->dctSpace, * coeff = Data->dctSpace + 64;
2700    
2701            for(i = 0; i < 4; i++) {
2702                    uint32_t iDcScaler = get_dc_scaler(iQuant, 1);
2703    
2704                    int s = 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2705                    transfer_8to16copy(in, Data->Cur + s, Data->iEdgedWidth);
2706                    fdct(in);
2707                    b_dc = dc;
2708                    dc = in[0];
2709                    in[0] -= b_dc;
2710                    if (Data->lambda8 == 0) quant_intra_c(coeff, in, iQuant, iDcScaler);
2711                    else quant4_intra_c(coeff, in, iQuant, iDcScaler);
2712    
2713                    b_dc = dc;
2714                    dc = coeff[0];
2715                    if (i != 0) coeff[0] -= b_dc;
2716    
2717                    bits += t = CodeCoeffIntra_CalcBits(coeff, scan_tables[0]) + dcy_tab[coeff[0] + 255].len;;
2718                    Data->temp[i] = t;
2719                    if (t != 0)  cbp |= 1 << (5 - i);
2720                    if (bits >= Data->iMinSAD[0]) break;
2721            }
2722    
2723            if (bits < Data->iMinSAD[0]) { // INTRA still looks good, let's add chroma
2724                    uint32_t iDcScaler = get_dc_scaler(iQuant, 0);
2725                    //chroma U
2726                    transfer_8to16copy(in, Data->CurU, Data->iEdgedWidth/2);
2727                    fdct(in);
2728                    in[0] -= 1024;
2729                    if (Data->lambda8 == 0) quant_intra(coeff, in, iQuant, iDcScaler);
2730                    else quant4_intra(coeff, in, iQuant, iDcScaler);
2731    
2732                    bits += t = CodeCoeffIntra_CalcBits(coeff, scan_tables[0]) + dcc_tab[coeff[0] + 255].len;
2733                    if (t != 0) cbp |= 1 << (5 - 4);
2734    
2735                    if (bits < Data->iMinSAD[0]) {
2736                            iDcScaler = get_dc_scaler(iQuant, 1);
2737                            //chroma V
2738                            transfer_8to16copy(in, Data->CurV, Data->iEdgedWidth/2);
2739                            fdct(in);
2740                            in[0] -= 1024;
2741                            if (Data->lambda8 == 0) quant_intra(coeff, in, iQuant, iDcScaler);
2742                            else quant4_intra(coeff, in, iQuant, iDcScaler);
2743    
2744                                          break;                          bits += t = CodeCoeffIntra_CalcBits(coeff, scan_tables[0]) + dcc_tab[coeff[0] + 255].len;
2745                                  case MODE_INTERPOLATE:                          if (t != 0) cbp |= 1 << (5 - 5);
                                         i_count++;  
                                         mb->mvs[0] = f_interpolMV;  
                                         mb->b_mvs[0] = b_interpolMV;  
                                         f_predMV = mb->mvs[0];  
                                         b_predMV = mb->b_mvs[0];  
                                         break;  
                                 case MODE_DIRECT:  
                                         d_count++;  
                                         break;  
                                 default:  
                                         break;  
                         }  
2746    
2747                            bits += xvid_cbpy_tab[cbp>>2].len;
2748                            bits += mcbpc_inter_tab[(MODE_INTRA & 7) | ((cbp & 3) << 3)].len;
2749                  }                  }
2750          }          }
2751            return bits;
 #ifdef _DEBUG_BFRAME_STAT  
         fprintf(stderr,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d\n",  
                                 f_count,b_count,i_count,d_count);  
 #endif  
   
2752  }  }

Legend:
Removed from v.346  
changed lines
  Added in v.963

No admin address has been configured
ViewVC Help
Powered by ViewVC 1.0.4