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

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

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

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

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

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