[svn] / trunk / xvidcore / src / motion / motion_est.c Repository:
ViewVC logotype

Diff of /trunk/xvidcore/src/motion/motion_est.c

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

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

Legend:
Removed from v.347  
changed lines
  Added in v.973

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