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

Legend:
Removed from v.370  
changed lines
  Added in v.982

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