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

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

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

revision 370, Mon Aug 12 10:07:16 2002 UTC revision 904, Tue Mar 4 11:00:53 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;
   
         iSAD = sad16( cur,  
                 get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth),  
                 iEdgedWidth, MV_MAX_ERROR);  
         if (iSAD <= iQuant * 96)  
                 iSAD -= MV16_00_BIAS;  
248    
249          currMV->x = 0;          ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
250          currMV->y = 0;          ref1 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
251          currPMV->x = -pred.x;          switch( ((x&1)<<1) + (y&1) ) {
252          currPMV->y = -pred.y;          case 0: // pure halfpel position
253                    return (uint8_t *) ref1;
254          return iSAD;                  break;
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          } else {          return Reference;
                 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;  
340    
341                  do {          if (!data->qpel_precision) {
342                          iDirection = 0;                  Reference = GetReference(x, y, data);
343                          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)                  current = data->currentMV;
344                                  CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);                  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 & 2)          sad = sad16v(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
352                                  CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);          t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
353    
354                          if (bDirection & 4)          sad += (data->lambda16 * t * sad)>>10;
355                                  CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;
356    
357                          if (bDirection & 8)          if (data->chroma) sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
358                                  CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);                                                                                  (yc >> 1) + roundtab_79[yc & 0x3], data);
359    
360                          /* now we're doing diagonal checks near our candidate */          if (sad < data->iMinSAD[0]) {
361                    data->iMinSAD[0] = sad;
362                          if (iDirection)         //checking if anything found                  current[0].x = x; current[0].y = y;
363                          {                  *dir = Direction;
                                 bDirection = iDirection;  
                                 iDirection = 0;  
                                 start_x = currMV->x;  
                                 start_y = currMV->y;  
                                 if (bDirection & 3)     //our candidate is left or right  
                                 {  
                                         CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);  
                                 } else                  // what remains here is up or down  
                                 {  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
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;  
375                                  }                                  }
                                 if (!iDirection)  
                                         break;          //ok, the end. really  
                                 else {  
                                         bDirection = iDirection;  
                                         start_x = currMV->x;  
                                         start_y = currMV->y;  
                                 }  
                         }  
                 }  
                 while (1);                              //forever  
         }  
         return iMinSAD;  
 }  
   
 #define CHECK_MV16_F_INTERPOL(X,Y) { \  
   if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \  
     && ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, b_currMV->x, b_currMV->y, iEdgedWidth),   \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16((X) - f_center_x, (Y) - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16(b_currMV->x - b_center_x, b_currMV->y - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; f_currMV->x=(X); f_currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_F_INTERPOL_FOUND(X,Y) { \  
   if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \  
     && ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, b_currMV->x, b_currMV->y, iEdgedWidth),   \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16((X) - f_center_x, (Y) - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16(b_currMV->x - b_center_x, b_currMV->y - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; f_currMV->x=(X); f_currMV->y=(Y); iFound=0;} } \  
 }  
   
 #define CHECK_MV16_B_INTERPOL(X,Y) { \  
   if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \  
     && ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth),   \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16((X) - b_center_x, (Y) - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; b_currMV->x=(X); b_currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_B_INTERPOL_FOUND(X,Y) { \  
   if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \  
     && ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth),   \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16((X) - b_center_x, (Y) - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; b_currMV->x=(X); b_currMV->y=(Y); iFound=0;} } \  
 }  
   
 int32_t  
 Diamond16_InterpolMainSearch(  
                                         const uint8_t * const f_pRef,  
                                          const uint8_t * const f_pRefH,  
                                          const uint8_t * const f_pRefV,  
                                          const uint8_t * const f_pRefHV,  
   
                                          const uint8_t * const cur,  
   
                                         const uint8_t * const b_pRef,  
                                          const uint8_t * const b_pRefH,  
                                          const uint8_t * const b_pRefV,  
                                          const uint8_t * const b_pRefHV,  
   
                                          const int x,  
                                          const int y,  
   
                                    const int f_start_x,  
                                    const int f_start_y,  
                                    const int b_start_x,  
                                    const int b_start_y,  
   
                                    int iMinSAD,  
                                    VECTOR * const f_currMV,  
                                    VECTOR * const b_currMV,  
   
                                    const int f_center_x,  
                                    const int f_center_y,  
                                    const int b_center_x,  
                                    const int b_center_y,  
   
                                     const int32_t f_min_dx,  
                                         const int32_t f_max_dx,  
                                         const int32_t f_min_dy,  
                                         const int32_t f_max_dy,  
   
                                     const int32_t b_min_dx,  
                                         const int32_t b_max_dx,  
                                         const int32_t b_min_dy,  
                                         const int32_t b_max_dy,  
   
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
   
                                         const int32_t f_iFcode,  
                                         const int32_t b_iFcode,  
   
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iSAD;  
   
         VECTOR f_backupMV;  
         VECTOR b_backupMV;  
   
         f_currMV->x = f_start_x;  
         f_currMV->y = f_start_y;  
         b_currMV->x = b_start_x;  
         b_currMV->y = b_start_y;  
   
         do  
         {  
                 iFound = 1;  
   
                 f_backupMV = *f_currMV;  
   
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x - iDiamondSize, f_backupMV.y);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x + iDiamondSize, f_backupMV.y);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y - iDiamondSize);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y + iDiamondSize);  
   
                 b_backupMV = *b_currMV;  
   
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x - iDiamondSize, b_backupMV.y);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x + iDiamondSize, b_backupMV.y);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y - iDiamondSize);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y + iDiamondSize);  
   
         } while (!iFound);  
   
         return iMinSAD;  
 }  
   
 /* Sorry, these MACROS really got too large... I'll turn them into function soon! */  
   
 #define CHECK_MV16_DIRECT_FOUND(X,Y) \  
         if ( (X)>=(-32) && (X)<=(31) && ((Y)>=-32) && ((Y)<=31) ) \  
         { int k;\  
         VECTOR mvs,b_mvs;       \  
         iSAD = 0;\  
         for (k = 0; k < 4; k++) {       \  
                                         mvs.x = (int32_t) ((TRB * directmv[k].x) / TRD + (X));          \  
                     b_mvs.x = (int32_t) (((X) == 0)                                                     \  
                                                                                 ? ((TRB - TRD) * directmv[k].x) / TRD   \  
                                             : mvs.x - directmv[k].x);                           \  
                                                                                                                                                                 \  
                     mvs.y = (int32_t) ((TRB * directmv[k].y) / TRD + (Y));              \  
                         b_mvs.y = (int32_t) (((Y) == 0)                                                         \  
                                                                                 ? ((TRB - TRD) * directmv[k].y) / TRD   \  
                                             : mvs.y - directmv[k].y);                           \  
                                                                                                                                                                 \  
   if ( (mvs.x <= max_dx) && (mvs.x >= min_dx) \  
     && (mvs.y <= max_dy) && (mvs.y >= min_dy)  \  
         && (b_mvs.x <= max_dx) && (b_mvs.x >= min_dx)  \  
     && (b_mvs.y <= max_dy) && (b_mvs.y >= min_dy) ) { \  
             iSAD += sad8bi( cur + 8*(k&1) + 8*(k>>1)*iEdgedWidth,                                                                                                       \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \  
                                         mvs.x, mvs.y, iEdgedWidth),                                                             \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \  
                                         b_mvs.x, b_mvs.y, iEdgedWidth),                                                         \  
                         iEdgedWidth); \  
                 }       \  
         else    \  
                 iSAD = 65535;   \  
         } \  
         iSAD += calc_delta_16((X),(Y), 1, iQuant);\  
         if (iSAD < iMinSAD) \  
             {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iFound=0; } \  
 }  
   
   
   
 int32_t  
 Diamond16_DirectMainSearch(  
                                         const uint8_t * const f_pRef,  
                                         const uint8_t * const f_pRefH,  
                                         const uint8_t * const f_pRefV,  
                                         const uint8_t * const f_pRefHV,  
   
                                         const uint8_t * const cur,  
   
                                         const uint8_t * const b_pRef,  
                                         const uint8_t * const b_pRefH,  
                                         const uint8_t * const b_pRefV,  
                                         const uint8_t * const b_pRefHV,  
   
                                         const int x,  
                                         const int y,  
   
                                         const int TRB,  
                                         const int TRD,  
   
                                     const int start_x,  
                                     const int start_y,  
   
                                     int iMinSAD,  
                                     VECTOR * const currMV,  
                                         const VECTOR * const directmv,  
   
                                     const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
376    
377                                          const int32_t iEdgedWidth,  static void
378                                          const int32_t iDiamondSize,  CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
   
                                         const int32_t iQuant,  
                                         int iFound)  
379  {  {
380  /* Do a diamond search around given starting point, return SAD of best */          int32_t sad; uint32_t t;
381            const uint8_t * Reference;
         int32_t iSAD;  
   
         VECTOR backupMV;  
   
         currMV->x = start_x;  
         currMV->y = start_y;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
382    
383          do          if ( (x > data->max_dx) || (x < data->min_dx)
384          {                  || (y > data->max_dy) || (y < data->min_dy) ) return;
                 iFound = 1;  
385    
386                  backupMV = *currMV;          if (!data->qpel_precision) Reference = GetReference(x, y, data);
387            else Reference = Interpolate8x8qpel(x, y, 0, 0, data);
388    
389                  CHECK_MV16_DIRECT_FOUND(backupMV.x - iDiamondSize, backupMV.y);          sad = sad8(data->Cur, Reference, data->iEdgedWidth);
390                  CHECK_MV16_DIRECT_FOUND(backupMV.x + iDiamondSize, backupMV.y);          t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
                 CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y - iDiamondSize);  
                 CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y + iDiamondSize);  
391    
392          } while (!iFound);          sad += (data->lambda8 * t * (sad+NEIGH_8X8_BIAS))>>10;
393    
394          return iMinSAD;          if (sad < *(data->iMinSAD)) {
395                    *(data->iMinSAD) = sad;
396                    data->currentMV->x = x; data->currentMV->y = y;
397                    *dir = Direction;
398            }
399  }  }
400    
401    
402  int32_t  static void
403  AdvDiamond8_MainSearch(const uint8_t * const pRef,  CheckCandidate32(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                                            const uint8_t * const pRefH,  
                                            const uint8_t * const pRefV,  
                                            const uint8_t * const pRefHV,  
                                            const uint8_t * const cur,  
                                            const int x,  
                                            const int y,  
                                            int start_x,  
                                            int start_y,  
                                            int iMinSAD,  
                                            VECTOR * const currMV,  
                                            const int center_x,  
                                            const int center_y,  
                                            const int32_t min_dx,  
                                            const int32_t max_dx,  
                                            const int32_t min_dy,  
                                            const int32_t max_dy,  
                                            const int32_t iEdgedWidth,  
                                            const int32_t iDiamondSize,  
                                            const int32_t iFcode,  
                                            const int32_t iQuant,  
                                            int iDirection)  
404  {  {
405            uint32_t t;
406            const uint8_t * Reference;
407    
408          int32_t iSAD;          if ( (!(x&1) && x !=0) || (!(y&1) && y !=0) || //non-zero integer value
409                    (x > data->max_dx) || (x < data->min_dx)
410                    || (y > data->max_dy) || (y < data->min_dy) ) return;
411    
412  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */          Reference = GetReference(x, y, data);
413            t = d_mv_bits(x, y, data->predMV, data->iFcode, 0, 1);
         if (iDirection) {  
                 CHECK_MV8_CANDIDATE(start_x - iDiamondSize, start_y);  
                 CHECK_MV8_CANDIDATE(start_x + iDiamondSize, start_y);  
                 CHECK_MV8_CANDIDATE(start_x, start_y - iDiamondSize);  
                 CHECK_MV8_CANDIDATE(start_x, start_y + iDiamondSize);  
         } else {  
                 int bDirection = 1 + 2 + 4 + 8;  
   
                 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_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
414    
415                          if (bDirection & 2)          data->temp[0] = sad32v_c(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
                                 CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
416    
417                          if (bDirection & 4)          data->temp[0] += (data->lambda16 * t * data->temp[0]) >> 10;
418                                  CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;
419    
420                          if (bDirection & 8)          if (data->temp[0] < data->iMinSAD[0]) {
421                                  CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);                  data->iMinSAD[0] = data->temp[0];
422                    data->currentMV[0].x = x; data->currentMV[0].y = y;
423                    *dir = Direction; }
424    
425                          /* now we're doing diagonal checks near our candidate */          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 (iDirection)         //checking if anything found          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                                  bDirection = iDirection;          if (data->temp[3] < data->iMinSAD[3]) {
430                                  iDirection = 0;                  data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
431                                  start_x = currMV->x;          if (data->temp[4] < data->iMinSAD[4]) {
432                                  start_y = currMV->y;                  data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = 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);  
433                                  }                                  }
434    
435                                  if (iDirection) {  static void
436                                          bDirection += iDirection;  CheckCandidate16no4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                                         start_x = currMV->x;  
                                         start_y = currMV->y;  
                                 }  
                         } else                          //about to quit, eh? not so fast....  
437                          {                          {
438                                  switch (bDirection) {          int32_t sad, xc, yc;
439                                  case 2:          const uint8_t * Reference;
440                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,          uint32_t t;
441                                                                                          start_y - iDiamondSize, 2 + 4);          VECTOR * current;
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 2 + 4:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 4:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         break;  
                                 case 8:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 1 + 4:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         break;  
                                 case 2 + 8:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1 + 8:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         break;  
                                 default:                //1+2+4+8 == we didn't find anything at all  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 }  
                                 if (!(iDirection))  
                                         break;          //ok, the end. really  
                                 else {  
                                         bDirection = iDirection;  
                                         start_x = currMV->x;  
                                         start_y = currMV->y;  
                                 }  
                         }  
                 }  
                 while (1);                              //forever  
         }  
         return iMinSAD;  
 }  
442    
443            if ( (x > data->max_dx) | ( x < data->min_dx)
444                    | (y > data->max_dy) | (y < data->min_dy) ) return;
445    
446  int32_t          if (data->rrv && (!(x&1) && x !=0) | (!(y&1) && y !=0) ) return; //non-zero even value
 Full8_MainSearch(const uint8_t * const pRef,  
                                  const uint8_t * const pRefH,  
                                  const uint8_t * const pRefV,  
                                  const uint8_t * const pRefHV,  
                                  const uint8_t * const cur,  
                                  const int x,  
                                  const int y,  
                            const int start_x,  
                            const int start_y,  
                            int iMinSAD,  
                            VECTOR * const currMV,  
                            const int center_x,  
                            const int center_y,  
                                  const int32_t min_dx,  
                                  const int32_t max_dx,  
                                  const int32_t min_dy,  
                                  const int32_t max_dy,  
                                  const int32_t iEdgedWidth,  
                                  const int32_t iDiamondSize,  
                                  const int32_t iFcode,  
                                  const int32_t iQuant,  
                                  int iFound)  
 {  
         int32_t iSAD;  
         int32_t dx, dy;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV8_CANDIDATE(dx, dy);  
447    
448          return iMinSAD;          if (data->qpel_precision) { // x and y are in 1/4 precision
449                    Reference = Interpolate16x16qpel(x, y, 0, data);
450                    current = data->currentQMV;
451                    xc = x/2; yc = y/2;
452            } else {
453                    Reference = GetReference(x, y, data);
454                    current = data->currentMV;
455                    xc = x; yc = y;
456  }  }
457            t = d_mv_bits(x, y, data->predMV, data->iFcode,
458                                            data->qpel^data->qpel_precision, data->rrv);
459    
460  Halfpel8_RefineFuncPtr Halfpel8_Refine;          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  Halfpel16_Refine(const uint8_t * const pRef,                                                                                  (yc >> 1) + roundtab_79[yc & 0x3], data);
                                  const uint8_t * const pRefH,  
                                  const uint8_t * const pRefV,  
                                  const uint8_t * const pRefHV,  
                                  const uint8_t * const cur,  
                                  const int x,  
                                  const int y,  
                                  VECTOR * const currMV,  
                                  int32_t iMinSAD,  
                            const int center_x,  
                            const int center_y,  
                                  const int32_t min_dx,  
                                  const int32_t max_dx,  
                                  const int32_t min_dy,  
                                  const int32_t max_dy,  
                                  const int32_t iFcode,  
                                  const int32_t iQuant,  
                                  const int32_t iEdgedWidth)  
 {  
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
465    
466          int32_t iSAD;          if (sad < *(data->iMinSAD)) {
467          VECTOR backupMV = *currMV;                  *(data->iMinSAD) = sad;
468                    current->x = x; current->y = y;
469          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y - 1);                  *dir = Direction;
470          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y - 1);          }
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y - 1);  
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y + 1);  
         CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y + 1);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y + 1);  
   
         return iMinSAD;  
471  }  }
472    
473  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)  static void
474    CheckCandidate32I(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
   
   
 int32_t  
 PMVfastSearch16(const uint8_t * const pRef,  
                                 const uint8_t * const pRefH,  
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const IMAGE * const pCur,  
                                 const int x,  
                                 const int y,  
                                 const int start_x,      /* start is searched first, so it should contain the most */  
                                 const int start_y,  /* likely motion vector for this block */  
                                 const int center_x,     /* center is from where length of MVs is measured */  
                                 const int center_y,  
                                 const uint32_t MotionFlags,  
                                 const uint32_t iQuant,  
                                 const uint32_t iFcode,  
                                 const MBParam * const pParam,  
                                 const MACROBLOCK * const pMBs,  
                                 const MACROBLOCK * const prevMBs,  
                                 VECTOR * const currMV,  
                                 VECTOR * const currPMV)  
475  {  {
476          const uint32_t iWcount = pParam->mb_width;  // maximum speed - for P/B/I decision
477          const int32_t iWidth = pParam->width;          int32_t sad;
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
478    
479          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          if ( (x > data->max_dx) || (x < data->min_dx)
480                    || (y > data->max_dy) || (y < data->min_dy) ) return;
481    
482          int32_t iDiamondSize;          sad = sad32v_c(data->Cur, data->Ref + x/2 + (y/2)*(data->iEdgedWidth),
483                                                            data->iEdgedWidth, data->temp+1);
484    
485          int32_t min_dx;          if (sad < *(data->iMinSAD)) {
486          int32_t max_dx;                  *(data->iMinSAD) = sad;
487          int32_t min_dy;                  data->currentMV[0].x = x; data->currentMV[0].y = y;
488          int32_t max_dy;                  *dir = Direction;
489            }
490          int32_t iFound;          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          VECTOR newMV;          if (data->temp[2] < data->iMinSAD[2]) {
493          VECTOR backupMV;                        /* just for PMVFAST */                  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          VECTOR pmv[4];                  data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
496          int32_t psad[4];          if (data->temp[4] < data->iMinSAD[4]) {
497                    data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
         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 */  
498    
         if (!(MotionFlags & PMV_HALFPEL16)) {  
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
499          }          }
500    
501          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  static void
502          //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)
503          bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);  {
504            int32_t sad, xb, yb, xcf, ycf, xcb, ycb;
505            uint32_t t;
506            const uint8_t *ReferenceF, *ReferenceB;
507            VECTOR *current;
508    
509          if ((x == 0) && (y == 0)) {          if ( (xf > data->max_dx) || (xf < data->min_dx)
510                  threshA = 512;                  || (yf > data->max_dy) || (yf < data->min_dy) ) return;
511                  threshB = 1024;  
512            if (!data->qpel_precision) {
513                    ReferenceF = GetReference(xf, yf, data);
514                    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          if (currMV->x < min_dx) {                  *dir = Direction;
                 currMV->x = min_dx;  
         }  
         if (currMV->y > max_dy) {  
                 currMV->y = max_dy;  
543          }          }
         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 += xvid_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->global_flags);
999    
1000            uint32_t x, y;
1001            uint32_t iIntra = 0;
1002            int32_t quant = current->quant, sad00;
1003            int skip_thresh = INITIAL_SKIP_THRESH *
1004                    (current->global_flags & XVID_REDUCED ? 4:1) *
1005                    (current->global_flags & XVID_MODEDECISION_BITS ? 2:1);
1006    
1007            // some pre-initialized thingies for SearchP
1008            int32_t temp[8];
1009            VECTOR currentMV[5];
1010            VECTOR currentQMV[5];
1011            int32_t iMinSAD[5];
1012            SearchData Data;
1013            memset(&Data, 0, sizeof(SearchData));
1014            Data.iEdgedWidth = iEdgedWidth;
1015            Data.currentMV = currentMV;
1016            Data.currentQMV = currentQMV;
1017            Data.iMinSAD = iMinSAD;
1018            Data.temp = temp;
1019            Data.iFcode = current->fcode;
1020            Data.rounding = pParam->m_rounding_type;
1021            Data.qpel = pParam->m_quarterpel;
1022            Data.chroma = MotionFlags & PMV_CHROMA16;
1023            Data.rrv = current->global_flags & XVID_REDUCED;
1024    
1025            if ((current->global_flags & XVID_REDUCED)) {
1026                    mb_width = (pParam->width + 31) / 32;
1027                    mb_height = (pParam->height + 31) / 32;
1028                    Data.qpel = 0;
1029            }
1030    
1031            Data.RefQ = pRefV->u; // a good place, also used in MC (for similar purpose)
1032            if (sadInit) (*sadInit) ();
1033    
1034            for (y = 0; y < mb_height; y++) {
1035                    for (x = 0; x < mb_width; x++)  {
1036                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1037    
1038                            if (!Data.rrv) pMB->sad16 =
1039                                    sad16v(pCurrent->y + (x + y * iEdgedWidth) * 16,
1040                                                            pRef->y + (x + y * iEdgedWidth) * 16,
1041                                                            pParam->edged_width, pMB->sad8 );
1042    
1043                            else pMB->sad16 =
1044                                    sad32v_c(pCurrent->y + (x + y * iEdgedWidth) * 32,
1045                                                            pRef->y + (x + y * iEdgedWidth) * 32,
1046                                                            pParam->edged_width, pMB->sad8 );
1047    
1048                            if (Data.chroma) {
1049                                    Data.temp[7] = sad8(pCurrent->u + x*8 + y*(iEdgedWidth/2)*8,
1050                                                                            pRef->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2)
1051                                                                    + sad8(pCurrent->v + (x + y*(iEdgedWidth/2))*8,
1052                                                                            pRef->v + (x + y*(iEdgedWidth/2))*8, iEdgedWidth/2);
1053                                    pMB->sad16 += Data.temp[7];
1054                            }
1055    
1056          if ((x == 0) && (y == 0)) {                          sad00 = pMB->sad16;
                 threshA = 512 / 4;  
                 threshB = 1024 / 4;  
1057    
1058                            if (!(current->global_flags & XVID_LUMIMASKING)) {
1059                                    pMB->dquant = NO_CHANGE;
1060          } else {          } else {
1061                  threshA = psad[0] / 4;  /* good estimate? */                                  if (pMB->dquant != NO_CHANGE) {
1062                  threshB = threshA + 256 / 4;                                          quant += DQtab[pMB->dquant];
1063                  if (threshA < 512 / 4)                                          if (quant > 31) quant = 31;
1064                          threshA = 512 / 4;                                          else if (quant < 1) quant = 1;
1065                  if (threshA > 1024 / 4)                                  }
1066                          threshA = 1024 / 4;                          }
1067                  if (threshB > 1792 / 4)                          pMB->quant = current->quant;
1068                          threshB = 1792 / 4;  
1069          }  //initial skip decision
1070    /* no early skip for GMC (global vector = skip vector is unknown!)  */
1071          iFound = 0;                          if (!(current->global_flags & XVID_GMC))        { /* no fast SKIP for S(GMC)-VOPs */
1072                                    if (pMB->dquant == NO_CHANGE && sad00 < pMB->quant * skip_thresh)
1073  /* Step 4: Calculate SAD around the Median prediction.                                          if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, iEdgedWidth/2, pMB->quant, Data.rrv)) {
1074     MinSAD=SAD                                                  SkipMacroblockP(pMB, sad00);
1075     If Motion Vector equal to Previous frame motion vector                                                  continue;
1076     and MinSAD<PrevFrmSAD goto Step 10.                                          }
1077     If SAD<=256 goto Step 10.                          }
 */  
1078    
1079                            SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1080                                                    y, MotionFlags, current->global_flags, pMB->quant,
1081                                                    &Data, pParam, pMBs, reference->mbs,
1082                                                    current->global_flags & XVID_INTER4V, pMB);
1083    
1084  // Prepare for main loop  /* final skip decision, a.k.a. "the vector you found, really that good?" */
1085                            if (!(current->global_flags & XVID_GMC || current->global_flags & XVID_MODEDECISION_BITS)) {
1086                                    if ( pMB->dquant == NO_CHANGE && sad00 < pMB->quant * MAX_SAD00_FOR_SKIP) {
1087                                            if ( (100*pMB->sad16)/(sad00+1) > FINAL_SKIP_THRESH * (Data.rrv ? 4:1) )
1088                                                    if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, iEdgedWidth/2, pMB->quant, Data.rrv))
1089                                                            SkipMacroblockP(pMB, sad00);
1090                                    }
1091                            }
1092                            if (pMB->mode == MODE_INTRA)
1093                                    if (++iIntra > iLimit) return 1;
1094                    }
1095            }
1096    
1097    if (MotionFlags & PMV_USESQUARES8)          if (current->global_flags & XVID_GMC )  /* GMC only for S(GMC)-VOPs */
1098        MainSearchPtr = Square8_MainSearch;          {
1099    else                  current->warp = GlobalMotionEst( pMBs, pParam, current, reference, pRefH, pRefV, pRefHV);
1100            }
1101            return 0;
1102    }
1103    
         if (MotionFlags & PMV_ADVANCEDDIAMOND8)  
                 MainSearchPtr = AdvDiamond8_MainSearch;  
         else  
                 MainSearchPtr = Diamond8_MainSearch;  
1104    
1105    static __inline int
1106    make_mask(const VECTOR * const pmv, const int i)
1107    {
1108            int mask = 255, j;
1109            for (j = 0; j < i; j++) {
1110                    if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already
1111                    if (pmv[i].x == pmv[j].x) {
1112                            if (pmv[i].y == pmv[j].y + iDiamondSize) mask &= ~4;
1113                            else if (pmv[i].y == pmv[j].y - iDiamondSize) mask &= ~8;
1114                    } else
1115                            if (pmv[i].y == pmv[j].y) {
1116                                    if (pmv[i].x == pmv[j].x + iDiamondSize) mask &= ~1;
1117                                    else if (pmv[i].x == pmv[j].x - iDiamondSize) mask &= ~2;
1118                            }
1119            }
1120            return mask;
1121    }
1122    
1123          *currMV = startMV;  static __inline void
1124    PreparePredictionsP(VECTOR * const pmv, int x, int y, int iWcount,
1125                            int iHcount, const MACROBLOCK * const prevMB, int rrv)
1126    {
1127    
1128          iMinSAD =  //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself
1129                  sad8(cur,          if (rrv) { iWcount /= 2; iHcount /= 2; }
                          get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  
                                                 iEdgedWidth), iEdgedWidth);  
         iMinSAD +=  
                 calc_delta_8(currMV->x - center_x, currMV->y - center_y,  
                                          (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256 / 4) || ((MVequal(*currMV, prevMB->mvs[iSubBlock]))  
                                                                 && ((int32_t) iMinSAD <  
                                                                         prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  
    vector of the median.  
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
1130    
1131          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[iSubBlock])))          if ( (y != 0) && (x < (iWcount-1)) ) {          // [5] top-right neighbour
1132                  iFound = 2;                  pmv[5].x = EVEN(pmv[3].x);
1133                    pmv[5].y = EVEN(pmv[3].y);
1134            } else pmv[5].x = pmv[5].y = 0;
1135    
1136  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }// pmv[3] is left neighbour
1137     Otherwise select large Diamond Search.          else pmv[3].x = pmv[3].y = 0;
 */  
1138    
1139          if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))          if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }// [4] top neighbour
1140                  iDiamondSize = 1;               // 1 halfpel!          else pmv[4].x = pmv[4].y = 0;
         else  
                 iDiamondSize = 2;               // 2 halfpel = 1 full pixel!  
1141    
1142          if (!(MotionFlags & PMV_HALFPELDIAMOND8))          // [1] median prediction
1143                  iDiamondSize *= 2;          pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
1144    
1145            pmv[0].x = pmv[0].y = 0; // [0] is zero; not used in the loop (checked before) but needed here for make_mask
1146    
1147  /*          pmv[2].x = EVEN(prevMB->mvs[0].x); // [2] is last frame
1148     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.          pmv[2].y = EVEN(prevMB->mvs[0].y);
    Also calculate (0,0) but do not subtract offset.  
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset.  
 */  
1149    
1150  // the median prediction might be even better than mv16          if ((x < iWcount-1) && (y < iHcount-1)) {
1151                    pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); //[6] right-down neighbour in last frame
1152                    pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
1153            } else pmv[6].x = pmv[6].y = 0;
1154    
1155          if (!MVequal(pmv[0], startMV))          if (rrv) {
1156                  CHECK_MV8_CANDIDATE(center_x, center_y);                  int i;
1157                    for (i = 0; i < 7; i++) {
1158                            pmv[i].x = RRV_MV_SCALEUP(pmv[i].x);
1159                            pmv[i].y = RRV_MV_SCALEUP(pmv[i].y);
1160                    }
1161            }
1162    }
1163    
1164  // (0,0) if needed  static int
1165          if (!MVzero(pmv[0]))  ModeDecision(const uint32_t iQuant, SearchData * const Data,
1166                  if (!MVzero(startMV))                  int inter4v,
1167                          CHECK_MV8_ZERO;                  MACROBLOCK * const pMB,
1168                    const MACROBLOCK * const pMBs,
1169  // previous frame MV if needed                  const int x, const int y,
1170          if (!MVzero(prevMB->mvs[iSubBlock]))                  const MBParam * const pParam,
1171                  if (!MVequal(prevMB->mvs[iSubBlock], startMV))                  const uint32_t MotionFlags,
1172                          if (!MVequal(prevMB->mvs[iSubBlock], pmv[0]))                  const uint32_t GlobalFlags)
1173                                  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;  
1174    
1175            int mode = MODE_INTER;
1176    
1177  /* Step 6: If MinSAD <= thresa goto Step 10.          if (!(GlobalFlags & XVID_MODEDECISION_BITS)) { //normal, fast, SAD-based mode decision
1178     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  //              int intra = 0;
1179  */                  int sad;
1180                    int InterBias = MV16_INTER_BIAS;
1181                    if (inter4v == 0 || Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
1182                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant) {
1183                                    mode = 0; //inter
1184                                    sad = Data->iMinSAD[0];
1185                    } else {
1186                            mode = MODE_INTER4V;
1187                            sad = Data->iMinSAD[1] + Data->iMinSAD[2] +
1188                                                    Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant;
1189                            Data->iMinSAD[0] = sad;
1190                    }
1191    
1192          if ((iMinSAD <= threshA) ||                  /* intra decision */
1193                  (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&  
1194                   ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {                  if (iQuant > 8) InterBias += 100 * (iQuant - 8); // to make high quants work
1195                  if (MotionFlags & PMV_QUICKSTOP16)                  if (y != 0)
1196                          goto PMVfast8_Terminate_without_Refine;                          if ((pMB - pParam->mb_width)->mode == MODE_INTRA ) InterBias -= 80;
1197                  if (MotionFlags & PMV_EARLYSTOP16)                  if (x != 0)
1198                          goto PMVfast8_Terminate_with_Refine;                          if ((pMB - 1)->mode == MODE_INTRA ) InterBias -= 80;
         }  
   
 /************ (Diamond Search)  **************/  
 /*  
    Step 7: Perform Diamond search, with either the small or large diamond.  
    If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
    Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
    If center then goto step 10.  
    Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
    Refine by using small diamond and goto step 10.  
 */  
1199    
1200          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                  if (Data->chroma) InterBias += 50; // to compensate bigger SAD
1201                    if (Data->rrv) InterBias *= 4;
1202    
1203  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                  if (InterBias < pMB->sad16) {
1204          iSAD =                          int32_t deviation;
1205                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,                          if (!Data->rrv) deviation = dev16(Data->Cur, Data->iEdgedWidth);
1206                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,                          else deviation = dev16(Data->Cur, Data->iEdgedWidth) +
1207                                                    min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,                                  dev16(Data->Cur+8, Data->iEdgedWidth) +
1208                                                    iQuant, iFound);                                  dev16(Data->Cur + 8*Data->iEdgedWidth, Data->iEdgedWidth) +
1209                                    dev16(Data->Cur+8+8*Data->iEdgedWidth, Data->iEdgedWidth);
1210    
1211          if (iSAD < iMinSAD) {                          if (deviation < (sad - InterBias))  return MODE_INTRA;// intra
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
1212          }          }
1213                    return mode;
1214    
1215          if (MotionFlags & PMV_EXTSEARCH8) {          } else {
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
1216    
1217                  if (!(MVequal(pmv[0], backupMV))) {                  int bits, intra, i;
1218                          iSAD =                  VECTOR backup[5], *v;
1219                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                  Data->lambda16 = iQuant;
1220                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,                  Data->lambda8 = pParam->m_quant_type;
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
1221    
1222                          if (iSAD < iMinSAD) {                  v = Data->qpel ? Data->currentQMV : Data->currentMV;
1223                                  *currMV = newMV;                  for (i = 0; i < 5; i++) {
1224                                  iMinSAD = iSAD;                          Data->iMinSAD[i] = 256*4096;
1225                          }                          backup[i] = v[i];
1226                  }                  }
1227    
1228                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                  bits = CountMBBitsInter(Data, pMBs, x, y, pParam, MotionFlags);
1229                          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);  
1230    
1231                          if (iSAD < iMinSAD) {                  if (inter4v) {
1232                                  *currMV = newMV;                          int inter4v = CountMBBitsInter4v(Data, pMB, pMBs, x, y, pParam, MotionFlags, backup);
1233                                  iMinSAD = iSAD;                          if (inter4v < bits) { Data->iMinSAD[0] = bits = inter4v; mode = MODE_INTER4V; }
                         }  
1234                  }                  }
         }  
   
 /* 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.  
 */  
1235    
   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);  
1236    
1237                    intra = CountMBBitsIntra(Data);
1238    
1239    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;  
1240    
1241          return iMinSAD;                  return mode;
1242            }
1243  }  }
1244    
1245  int32_t  static void
1246  EPZSSearch16(const uint8_t * const pRef,  SearchP(const IMAGE * const pRef,
1247                           const uint8_t * const pRefH,                           const uint8_t * const pRefH,
1248                           const uint8_t * const pRefV,                           const uint8_t * const pRefV,
1249                           const uint8_t * const pRefHV,                           const uint8_t * const pRefHV,
1250                           const IMAGE * const pCur,                           const IMAGE * const pCur,
1251                           const int x,                           const int x,
1252                           const int y,                           const int y,
                         const int start_x,  
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
1253                           const uint32_t MotionFlags,                           const uint32_t MotionFlags,
1254                    const uint32_t GlobalFlags,
1255                           const uint32_t iQuant,                           const uint32_t iQuant,
1256                           const uint32_t iFcode,                  SearchData * const Data,
1257                           const MBParam * const pParam,                           const MBParam * const pParam,
1258                           const MACROBLOCK * const pMBs,                           const MACROBLOCK * const pMBs,
1259                           const MACROBLOCK * const prevMBs,                           const MACROBLOCK * const prevMBs,
1260                           VECTOR * const currMV,                  int inter4v,
1261                           VECTOR * const currPMV)                  MACROBLOCK * const pMB)
1262  {  {
         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;  
   
         const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;  
   
         int32_t min_dx;  
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
1263    
1264          VECTOR newMV;          int i, iDirection = 255, mask, threshA;
1265          VECTOR backupMV;          VECTOR pmv[7];
1266    
1267          VECTOR pmv[4];          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1268          int32_t psad[8];                                                  pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
1269    
1270            get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);
1271    
1272            Data->temp[5] = Data->temp[6] = 0; // chroma-sad cache
1273            i = Data->rrv ? 2 : 1;
1274            Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16*i;
1275            Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1276            Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1277    
1278            Data->Ref = pRef->y + (x + Data->iEdgedWidth*y) * 16*i;
1279            Data->RefH = pRefH + (x + Data->iEdgedWidth*y) * 16*i;
1280            Data->RefV = pRefV + (x + Data->iEdgedWidth*y) * 16*i;
1281            Data->RefHV = pRefHV + (x + Data->iEdgedWidth*y) * 16*i;
1282            Data->RefCV = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1283            Data->RefCU = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1284    
1285            Data->lambda16 = lambda_vec16[iQuant];
1286            Data->lambda8 = lambda_vec8[iQuant];
1287            Data->qpel_precision = 0;
1288    
1289            if (pMB->dquant != NO_CHANGE) inter4v = 0;
1290    
1291            for(i = 0; i < 5; i++)
1292                    Data->currentMV[i].x = Data->currentMV[i].y = 0;
1293    
1294            if (Data->qpel) Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1295            else Data->predMV = pmv[0];
1296    
1297            i = d_mv_bits(0, 0, Data->predMV, Data->iFcode, 0, 0);
1298            Data->iMinSAD[0] = pMB->sad16 + ((Data->lambda16 * i * pMB->sad16)>>10);
1299            Data->iMinSAD[1] = pMB->sad8[0] + ((Data->lambda8 * i * (pMB->sad8[0]+NEIGH_8X8_BIAS)) >> 10);
1300            Data->iMinSAD[2] = pMB->sad8[1];
1301            Data->iMinSAD[3] = pMB->sad8[2];
1302            Data->iMinSAD[4] = pMB->sad8[3];
1303    
1304            if ((!(GlobalFlags & XVID_MODEDECISION_BITS)) || (x | y)) {
1305                    threshA = Data->temp[0]; // that's where we keep this SAD atm
1306                    if (threshA < 512) threshA = 512;
1307                    else if (threshA > 1024) threshA = 1024;
1308            } else
1309                    threshA = 512;
1310    
1311          static MACROBLOCK *oldMBs = NULL;          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
1312                                            prevMBs + x + y * pParam->mb_width, Data->rrv);
1313    
1314  //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;          if (!Data->rrv) {
1315          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;                  if (inter4v | Data->chroma) CheckCandidate = CheckCandidate16;
1316          MACROBLOCK *oldMB = NULL;                          else CheckCandidate = CheckCandidate16no4v; //for extra speed
1317            } else CheckCandidate = CheckCandidate32;
1318    
1319    /* main loop. checking all predictions (but first, which is 0,0 and has been checked in MotionEstimation())*/
1320    
1321            for (i = 1; i < 7; i++) {
1322                    if (!(mask = make_mask(pmv, i)) ) continue;
1323                    CheckCandidate(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1324                    if (Data->iMinSAD[0] <= threshA) break;
1325            }
1326    
1327            if ((Data->iMinSAD[0] <= threshA) ||
1328                            (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
1329                            (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16))) {
1330                    if (!(GlobalFlags & XVID_MODEDECISION_BITS)) inter4v = 0;       }
1331            else {
1332    
1333           int32_t thresh2;                  MainSearchFunc * MainSearchPtr;
1334          int32_t bPredEq;                  if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1335          int32_t iMinSAD, iSAD = 9999;                  else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1336                            else MainSearchPtr = DiamondSearch;
1337    
1338                    MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
1339    
1340    /* extended search, diamond starting in 0,0 and in prediction.
1341            note that this search is/might be done in halfpel positions,
1342            which makes it more different than the diamond above */
1343    
1344          MainSearch16FuncPtr MainSearchPtr;                  if (MotionFlags & PMV_EXTSEARCH16) {
1345                            int32_t bSAD;
1346                            VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
1347                            if (Data->rrv) {
1348                                    startMV.x = RRV_MV_SCALEUP(startMV.x);
1349                                    startMV.y = RRV_MV_SCALEUP(startMV.y);
1350                            }
1351                            if (!(MVequal(startMV, backupMV))) {
1352                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1353    
1354          if (oldMBs == NULL) {                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1355                  oldMBs = (MACROBLOCK *) calloc(iWcount * iHcount, sizeof(MACROBLOCK));                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1356  //      fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));                                  if (bSAD < Data->iMinSAD[0]) {
1357                                            Data->currentMV[0] = backupMV;
1358                                            Data->iMinSAD[0] = bSAD; }
1359          }          }
         oldMB = oldMBs + x + y * iWcount;  
1360    
1361  /* Get maximum range */                          backupMV = Data->currentMV[0];
1362          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,                          startMV.x = startMV.y = 1;
1363                            iFcode);                          if (!(MVequal(startMV, backupMV))) {
1364                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1365    
1366          if (!(MotionFlags & PMV_HALFPEL16)) {                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1367                  min_dx = EVEN(min_dx);                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1368                  max_dx = EVEN(max_dx);                                  if (bSAD < Data->iMinSAD[0]) {
1369                  min_dy = EVEN(min_dy);                                          Data->currentMV[0] = backupMV;
1370                  max_dy = EVEN(max_dy);                                          Data->iMinSAD[0] = bSAD; }
1371                            }
1372                    }
1373          }          }
         /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
         //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);  
   
 /* Step 4: Calculate SAD around the Median prediction.  
         MinSAD=SAD  
         If Motion Vector equal to Previous frame motion vector  
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
 */  
1374    
1375  // Prepare for main loop          if (MotionFlags & PMV_HALFPELREFINE16)
1376                    if ((!(MotionFlags & HALFPELREFINE16_BITS)) || Data->iMinSAD[0] < 200*(int)iQuant)
1377                            SubpelRefine(Data);
1378    
1379          currMV->x = start_x;          for(i = 0; i < 5; i++) {
1380          currMV->y = start_y;                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // initialize qpel vectors
1381                    Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
1382            }
1383    
1384          if (!(MotionFlags & PMV_HALFPEL16)) {          if (MotionFlags & PMV_QUARTERPELREFINE16) {
                 currMV->x = EVEN(currMV->x);  
                 currMV->y = EVEN(currMV->y);  
         }  
   
         if (currMV->x > max_dx)  
                 currMV->x = max_dx;  
         if (currMV->x < min_dx)  
                 currMV->x = min_dx;  
         if (currMV->y > max_dy)  
                 currMV->y = max_dy;  
         if (currMV->y < min_dy)  
                 currMV->y = min_dy;  
   
 /***************** This is predictor SET A: only median prediction ******************/  
   
         iMinSAD =  
                 sad16(cur,  
                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
   
 // thresh1 is fixed to 256  
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
         }  
   
 /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/  
1385    
1386  // previous frame MV                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1387          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);                                  pParam->width, pParam->height, Data->iFcode, 1, 0);
1388    
1389  // set threshhold based on Min of Prediction and SAD of collocated block                  if ((!(MotionFlags & QUARTERPELREFINE16_BITS)) || (Data->iMinSAD[0] < 200*(int)iQuant)) {
1390  // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want                          Data->qpel_precision = 1;
1391                            SubpelRefine(Data);
1392                    }
1393            }
1394    
1395          if ((x == 0) && (y == 0)) {          if ((!(GlobalFlags & XVID_MODEDECISION_BITS)) && (Data->iMinSAD[0] < (int32_t)iQuant * 30)) inter4v = 0;
                 thresh2 = 512;  
         } else {  
 /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */  
1396    
1397                  thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;          if (inter4v && (!(GlobalFlags & XVID_MODEDECISION_BITS) ||
1398          }                          (!(MotionFlags & QUARTERPELREFINE8_BITS)) || (!(MotionFlags & HALFPELREFINE8_BITS)) ||
1399                            ((!(MotionFlags & EXTSEARCH_BITS)) && (!(MotionFlags&PMV_EXTSEARCH8)) ))) {
1400                    // if decision is BITS-based and all refinement steps will be done in BITS domain, there is no reason to call this loop
1401    
1402  // MV=(0,0) is often a good choice                  SearchData Data8;
1403                    memcpy(&Data8, Data, sizeof(SearchData)); //quick copy of common data
1404    
1405          CHECK_MV16_ZERO;                  Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
1406                    Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
1407                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
1408                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
1409    
1410                    if ((Data->chroma) && (!(GlobalFlags & XVID_MODEDECISION_BITS))) {
1411                            // chroma is only used for comparsion to INTER. if the comparsion will be done in BITS domain, there is no reason to compute it
1412                            int sumx = 0, sumy = 0;
1413                            const int div = 1 + Data->qpel;
1414                            const VECTOR * const mv = Data->qpel ? pMB->qmvs : pMB->mvs;
1415    
1416  // left neighbour, if allowed                          for (i = 0; i < 4; i++) {
1417          if (x != 0) {                                  sumx += mv[i].x / div;
1418                  if (!(MotionFlags & PMV_HALFPEL16)) {                                  sumy += mv[i].y / div;
                         pmv[1].x = EVEN(pmv[1].x);  
                         pmv[1].y = EVEN(pmv[1].y);  
1419                  }                  }
1420                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
1421                            Data->iMinSAD[1] += ChromaSAD(  (sumx >> 3) + roundtab_76[sumx & 0xf],
1422                                                                                            (sumy >> 3) + roundtab_76[sumy & 0xf], Data);
1423          }          }
 // top neighbour, if allowed  
         if (y != 0) {  
                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                         pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
1424                  }                  }
                 CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
1425    
1426  // top right neighbour, if allowed          inter4v = ModeDecision(iQuant, Data, inter4v, pMB, pMBs, x, y, pParam, MotionFlags, GlobalFlags);
1427                  if ((uint32_t) x != (iWcount - 1)) {  
1428                          if (!(MotionFlags & PMV_HALFPEL16)) {          if (Data->rrv) {
1429                                  pmv[3].x = EVEN(pmv[3].x);                          Data->currentMV[0].x = RRV_MV_SCALEDOWN(Data->currentMV[0].x);
1430                                  pmv[3].y = EVEN(pmv[3].y);                          Data->currentMV[0].y = RRV_MV_SCALEDOWN(Data->currentMV[0].y);
1431                          }                          }
1432                          CHECK_MV16_CANDIDATE(pmv[3].x, pmv[3].y);  
1433            if (inter4v == MODE_INTER) {
1434                    pMB->mode = MODE_INTER;
1435                    pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
1436                    pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = Data->iMinSAD[0];
1437    
1438                    if(Data->qpel) {
1439                            pMB->qmvs[0] = pMB->qmvs[1]
1440                                    = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1441                            pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1442                            pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;
1443                    } else {
1444                            pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1445                            pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
1446                  }                  }
1447    
1448            } else if (inter4v == MODE_INTER4V) {
1449                    pMB->mode = MODE_INTER4V;
1450                    pMB->sad16 = Data->iMinSAD[0];
1451            } else { // INTRA mode
1452                    SkipMacroblockP(pMB, 0); // not skip, but similar enough
1453                    pMB->mode = MODE_INTRA;
1454          }          }
1455    
1456  /* Terminate if MinSAD <= T_2  }
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
1457    
1458          if ((iMinSAD <= thresh2)  static void
1459                  || (MVequal(*currMV, prevMB->mvs[0]) &&  Search8(const SearchData * const OldData,
1460                          ((int32_t) iMinSAD <= prevMB->sad16))) {                  const int x, const int y,
1461                  if (MotionFlags & PMV_QUICKSTOP16)                  const uint32_t MotionFlags,
1462                          goto EPZS16_Terminate_without_Refine;                  const MBParam * const pParam,
1463                  if (MotionFlags & PMV_EARLYSTOP16)                  MACROBLOCK * const pMB,
1464                          goto EPZS16_Terminate_with_Refine;                  const MACROBLOCK * const pMBs,
1465                    const int block,
1466                    SearchData * const Data)
1467    {
1468            int i = 0;
1469            Data->iMinSAD = OldData->iMinSAD + 1 + block;
1470            Data->currentMV = OldData->currentMV + 1 + block;
1471            Data->currentQMV = OldData->currentQMV + 1 + block;
1472    
1473            if(Data->qpel) {
1474                    Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1475                    if (block != 0) i = d_mv_bits(  Data->currentQMV->x, Data->currentQMV->y,
1476                                                                                    Data->predMV, Data->iFcode, 0, 0);
1477            } else {
1478                    Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1479                    if (block != 0) i = d_mv_bits(  Data->currentMV->x, Data->currentMV->y,
1480                                                                                    Data->predMV, Data->iFcode, 0, Data->rrv);
1481          }          }
1482    
1483  /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/          *(Data->iMinSAD) += (Data->lambda8 * i * (*Data->iMinSAD + NEIGH_8X8_BIAS))>>10;
1484    
1485          backupMV = prevMB->mvs[0];      // collocated MV          if (MotionFlags & (PMV_EXTSEARCH8|PMV_HALFPELREFINE8|PMV_QUARTERPELREFINE8)) {
1486          backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x);     // acceleration X                  if (Data->rrv) i = 2; else i = 1;
         backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y);     // acceleration Y  
1487    
1488          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y);                  Data->Ref = OldData->Ref + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));
1489                    Data->RefH = OldData->RefH + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));
1490                    Data->RefV = OldData->RefV + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));
1491                    Data->RefHV = OldData->RefHV + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));
1492    
1493  // left neighbour                  Data->Cur = OldData->Cur + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));
1494          if (x != 0)                  Data->qpel_precision = 0;
                 CHECK_MV16_CANDIDATE((prevMB - 1)->mvs[0].x, (prevMB - 1)->mvs[0].y);  
1495    
1496  // top neighbour                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1497          if (y != 0)                                          pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
                 CHECK_MV16_CANDIDATE((prevMB - iWcount)->mvs[0].x,  
                                                          (prevMB - iWcount)->mvs[0].y);  
1498    
1499  // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs                  if (!Data->rrv) CheckCandidate = CheckCandidate8;
1500                    else CheckCandidate = CheckCandidate16no4v;
1501    
1502          if ((uint32_t) x != iWcount - 1)                  if (MotionFlags & PMV_EXTSEARCH8 && (!(MotionFlags & EXTSEARCH_BITS))) {
1503                  CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);                          int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
1504    
1505  // bottom neighbour, dito                          MainSearchFunc *MainSearchPtr;
1506          if ((uint32_t) y != iHcount - 1)                          if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
1507                  CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,                                  else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1508                                                           (prevMB + iWcount)->mvs[0].y);                                          else MainSearchPtr = DiamondSearch;
1509    
1510  /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */                          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, 255);
1511          if (iMinSAD <= thresh2) {  
1512                  if (MotionFlags & PMV_QUICKSTOP16)                          if(*(Data->iMinSAD) < temp_sad) {
1513                          goto EPZS16_Terminate_without_Refine;                                          Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1514                  if (MotionFlags & PMV_EARLYSTOP16)                                          Data->currentQMV->y = 2 * Data->currentMV->y;
1515                          goto EPZS16_Terminate_with_Refine;                          }
1516          }          }
1517    
1518  /************ (if Diamond Search)  **************/                  if (MotionFlags & PMV_HALFPELREFINE8) {
1519                            int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
1520    
1521          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                          SubpelRefine(Data); // perform halfpel refine of current best vector
1522    
1523          if (MotionFlags & PMV_USESQUARES16)                          if(*(Data->iMinSAD) < temp_sad) { // we have found a better match
1524                  MainSearchPtr = Square16_MainSearch;                                  Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1525          else                                  Data->currentQMV->y = 2 * Data->currentMV->y;
1526           if (MotionFlags & PMV_ADVANCEDDIAMOND16)                          }
1527                  MainSearchPtr = AdvDiamond16_MainSearch;                  }
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
1528    
1529  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                  if (Data->qpel && MotionFlags & PMV_QUARTERPELREFINE8) {
1530                                    Data->qpel_precision = 1;
1531                                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1532                                            pParam->width, pParam->height, Data->iFcode, 1, 0);
1533                                    SubpelRefine(Data);
1534                    }
1535            }
1536    
1537            if (Data->rrv) {
1538                            Data->currentMV->x = RRV_MV_SCALEDOWN(Data->currentMV->x);
1539                            Data->currentMV->y = RRV_MV_SCALEDOWN(Data->currentMV->y);
1540            }
1541    
1542          iSAD =          if(Data->qpel) {
1543                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,                  pMB->pmvs[block].x = Data->currentQMV->x - Data->predMV.x;
1544                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,                  pMB->pmvs[block].y = Data->currentQMV->y - Data->predMV.y;
1545                                                    min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);                  pMB->qmvs[block] = *Data->currentQMV;
1546            } else {
1547          if (iSAD < iMinSAD) {                  pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1548                  *currMV = newMV;                  pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
                 iMinSAD = iSAD;  
1549          }          }
1550    
1551            pMB->mvs[block] = *Data->currentMV;
1552            pMB->sad8[block] = 4 * *Data->iMinSAD;
1553    }
1554    
1555          if (MotionFlags & PMV_EXTSEARCH16) {  /* motion estimation for B-frames */
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
1556    
1557                  if (!(MVequal(pmv[0], backupMV))) {  static __inline VECTOR
1558                          iSAD =  ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1559                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  {
1560                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,  /* the stupidiest function ever */
1561                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,          return (mode == MODE_FORWARD ? pMB->mvs[0] : pMB->b_mvs[0]);
                                                                   2, iFcode, iQuant, 0);  
1562                  }                  }
1563    
1564                  if (iSAD < iMinSAD) {  static void __inline
1565                          *currMV = newMV;  PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
1566                          iMinSAD = iSAD;                                                          const uint32_t iWcount,
1567                  }                                                          const MACROBLOCK * const pMB,
1568                                                            const uint32_t mode_curr)
1569    {
1570    
1571                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          // [0] is prediction
1572                          iSAD =          pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);  
1573    
1574                          if (iSAD < iMinSAD) {          pmv[1].x = pmv[1].y = 0; // [1] is zero
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
                 }  
         }  
1575    
1576  /***************        Choose best MV found     **************/          pmv[2] = ChoosePred(pMB, mode_curr);
1577            pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
1578    
1579    EPZS16_Terminate_with_Refine:          if ((y != 0)&&(x != (int)(iWcount+1))) {                        // [3] top-right neighbour
1580          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step                  pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
1581                  iMinSAD =                  pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
1582                          Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,          } else pmv[3].x = pmv[3].y = 0;
                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
1583    
1584    EPZS16_Terminate_without_Refine:          if (y != 0) {
1585                    pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
1586                    pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
1587            } else pmv[4].x = pmv[4].y = 0;
1588    
1589          *oldMB = *prevMB;          if (x != 0) {
1590                    pmv[5] = ChoosePred(pMB-1, mode_curr);
1591                    pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1592            } else pmv[5].x = pmv[5].y = 0;
1593    
1594          currPMV->x = currMV->x - center_x;          if (x != 0 && y != 0) {
1595          currPMV->y = currMV->y - center_y;                  pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
1596          return iMinSAD;                  pmv[6].x = EVEN(pmv[6].x); pmv[6].y = EVEN(pmv[6].y);
1597            } else pmv[6].x = pmv[6].y = 0;
1598  }  }
1599    
1600    
1601  int32_t  /* search backward or forward */
1602  EPZSSearch8(const uint8_t * const pRef,  static void
1603    SearchBF(       const IMAGE * const pRef,
1604                          const uint8_t * const pRefH,                          const uint8_t * const pRefH,
1605                          const uint8_t * const pRefV,                          const uint8_t * const pRefV,
1606                          const uint8_t * const pRefHV,                          const uint8_t * const pRefHV,
1607                          const IMAGE * const pCur,                          const IMAGE * const pCur,
1608                          const int x,                          const int x, const int y,
                         const int y,  
                         const int start_x,  
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
1609                          const uint32_t MotionFlags,                          const uint32_t MotionFlags,
                         const uint32_t iQuant,  
1610                          const uint32_t iFcode,                          const uint32_t iFcode,
1611                          const MBParam * const pParam,                          const MBParam * const pParam,
1612                          const MACROBLOCK * const pMBs,                          MACROBLOCK * const pMB,
1613                          const MACROBLOCK * const prevMBs,                          const VECTOR * const predMV,
1614                          VECTOR * const currMV,                          int32_t * const best_sad,
1615                          VECTOR * const currPMV)                          const int32_t mode_current,
1616                            SearchData * const Data)
1617  {  {
 /* Please not that EPZS might not be a good choice for 8x8-block motion search ! */  
   
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
   
         const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;  
   
         int32_t iDiamondSize = 1;  
1618    
1619          int32_t min_dx;          int i, iDirection = 255, mask;
1620          int32_t max_dx;          VECTOR pmv[7];
1621          int32_t min_dy;          MainSearchFunc *MainSearchPtr;
1622          int32_t max_dy;          *Data->iMinSAD = MV_MAX_ERROR;
1623            Data->iFcode = iFcode;
1624            Data->qpel_precision = 0;
1625            Data->temp[5] = Data->temp[6] = Data->temp[7] = 256*4096; // reset chroma-sad cache
1626    
1627          VECTOR newMV;          Data->Ref = pRef->y + (x + y * Data->iEdgedWidth) * 16;
1628          VECTOR backupMV;          Data->RefH = pRefH + (x + y * Data->iEdgedWidth) * 16;
1629            Data->RefV = pRefV + (x + y * Data->iEdgedWidth) * 16;
1630            Data->RefHV = pRefHV + (x + y * Data->iEdgedWidth) * 16;
1631            Data->RefCU = pRef->u + (x + y * Data->iEdgedWidth/2) * 8;
1632            Data->RefCV = pRef->v + (x + y * Data->iEdgedWidth/2) * 8;
1633    
1634          VECTOR pmv[4];          Data->predMV = *predMV;
         int32_t psad[8];  
1635    
1636          const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1637                                    pParam->width, pParam->height, iFcode - Data->qpel, 0, 0);
1638    
1639  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          pmv[0] = Data->predMV;
1640          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;          if (Data->qpel) { pmv[0].x /= 2; pmv[0].y /= 2; }
1641    
1642          int32_t bPredEq;          PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);
         int32_t iMinSAD, iSAD = 9999;  
1643    
1644          MainSearch8FuncPtr MainSearchPtr;          Data->currentMV->x = Data->currentMV->y = 0;
1645            CheckCandidate = CheckCandidate16no4v;
1646    
1647  /* Get maximum range */  // main loop. checking all predictions
1648          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,          for (i = 0; i < 7; i++) {
1649                            iFcode);                  if (!(mask = make_mask(pmv, i)) ) continue;
1650                    CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
 /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  
   
         if (!(MotionFlags & PMV_HALFPEL8)) {  
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
1651          }          }
         /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
         //bPredEq = get_pmvdata(pMBs, x >> 1, y >> 1, iWcount, iSubBlock, pmv[0].x, pmv[0].y, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, x >> 1, y >> 1, iSubBlock, pmv, psad);  
1652    
1653            if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1654            else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1655                    else MainSearchPtr = DiamondSearch;
1656    
1657  /* Step 4: Calculate SAD around the Median prediction.          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
         MinSAD=SAD  
         If Motion Vector equal to Previous frame motion vector  
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
 */  
   
 // Prepare for main loop  
1658    
1659            SubpelRefine(Data);
1660    
1661          if (!(MotionFlags & PMV_HALFPEL8)) {          if (Data->qpel && *Data->iMinSAD < *best_sad + 300) {
1662                  currMV->x = EVEN(currMV->x);                  Data->currentQMV->x = 2*Data->currentMV->x;
1663                  currMV->y = EVEN(currMV->y);                  Data->currentQMV->y = 2*Data->currentMV->y;
1664                    Data->qpel_precision = 1;
1665                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1666                                            pParam->width, pParam->height, iFcode, 1, 0);
1667                    SubpelRefine(Data);
1668          }          }
1669    
1670          if (currMV->x > max_dx)  // three bits are needed to code backward mode. four for forward
                 currMV->x = max_dx;  
         if (currMV->x < min_dx)  
                 currMV->x = min_dx;  
         if (currMV->y > max_dy)  
                 currMV->y = max_dy;  
         if (currMV->y < min_dy)  
                 currMV->y = min_dy;  
1671    
1672  /***************** This is predictor SET A: only median prediction ******************/          if (mode_current == MODE_FORWARD) *Data->iMinSAD += 4 * Data->lambda16;
1673            else *Data->iMinSAD += 3 * Data->lambda16;
1674    
1675            if (*Data->iMinSAD < *best_sad) {
1676                    *best_sad = *Data->iMinSAD;
1677                    pMB->mode = mode_current;
1678                    if (Data->qpel) {
1679                            pMB->pmvs[0].x = Data->currentQMV->x - predMV->x;
1680                            pMB->pmvs[0].y = Data->currentQMV->y - predMV->y;
1681                            if (mode_current == MODE_FORWARD)
1682                                    pMB->qmvs[0] = *Data->currentQMV;
1683                            else
1684                                    pMB->b_qmvs[0] = *Data->currentQMV;
1685                    } else {
1686                            pMB->pmvs[0].x = Data->currentMV->x - predMV->x;
1687                            pMB->pmvs[0].y = Data->currentMV->y - predMV->y;
1688                    }
1689                    if (mode_current == MODE_FORWARD) pMB->mvs[0] = *Data->currentMV;
1690                    else pMB->b_mvs[0] = *Data->currentMV;
1691            }
1692    
1693          iMinSAD =          if (mode_current == MODE_FORWARD) *(Data->currentMV+2) = *Data->currentMV;
1694                  sad8(cur,          else *(Data->currentMV+1) = *Data->currentMV; //we store currmv for interpolate search
1695                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  }
1696                                                  iEdgedWidth), iEdgedWidth);  
1697          iMinSAD +=  static void
1698                  calc_delta_8(currMV->x - center_x, currMV->y - center_y,  SkipDecisionB(const IMAGE * const pCur,
1699                                           (uint8_t) iFcode, iQuant);                                  const IMAGE * const f_Ref,
1700                                    const IMAGE * const b_Ref,
1701                                    MACROBLOCK * const pMB,
1702                                    const uint32_t x, const uint32_t y,
1703                                    const SearchData * const Data)
1704    {
1705            int dx = 0, dy = 0, b_dx = 0, b_dy = 0;
1706            int32_t sum;
1707            const int div = 1 + Data->qpel;
1708            int k;
1709            const uint32_t stride = Data->iEdgedWidth/2;
1710    //this is not full chroma compensation, only it's fullpel approximation. should work though
1711    
1712            for (k = 0; k < 4; k++) {
1713                    dy += Data->directmvF[k].y / div;
1714                    dx += Data->directmvF[0].x / div;
1715                    b_dy += Data->directmvB[0].y / div;
1716                    b_dx += Data->directmvB[0].x / div;
1717            }
1718    
1719            dy = (dy >> 3) + roundtab_76[dy & 0xf];
1720            dx = (dx >> 3) + roundtab_76[dx & 0xf];
1721            b_dy = (b_dy >> 3) + roundtab_76[b_dy & 0xf];
1722            b_dx = (b_dx >> 3) + roundtab_76[b_dx & 0xf];
1723    
1724            sum = sad8bi(pCur->u + 8 * x + 8 * y * stride,
1725                                            f_Ref->u + (y*8 + dy/2) * stride + x*8 + dx/2,
1726                                            b_Ref->u + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1727                                            stride);
1728    
1729            if (sum >= 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) return; //no skip
1730    
1731            sum += sad8bi(pCur->v + 8*x + 8 * y * stride,
1732                                            f_Ref->v + (y*8 + dy/2) * stride + x*8 + dx/2,
1733                                            b_Ref->v + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1734                                            stride);
1735    
1736  // thresh1 is fixed to 256          if (sum < 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) 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;  
1737          }          }
1738    
1739  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/  static __inline uint32_t
1740    SearchDirect(const IMAGE * const f_Ref,
1741                                    const uint8_t * const f_RefH,
1742                                    const uint8_t * const f_RefV,
1743                                    const uint8_t * const f_RefHV,
1744                                    const IMAGE * const b_Ref,
1745                                    const uint8_t * const b_RefH,
1746                                    const uint8_t * const b_RefV,
1747                                    const uint8_t * const b_RefHV,
1748                                    const IMAGE * const pCur,
1749                                    const int x, const int y,
1750                                    const uint32_t MotionFlags,
1751                                    const int32_t TRB, const int32_t TRD,
1752                                    const MBParam * const pParam,
1753                                    MACROBLOCK * const pMB,
1754                                    const MACROBLOCK * const b_mb,
1755                                    int32_t * const best_sad,
1756                                    SearchData * const Data)
1757    
1758    {
1759            int32_t skip_sad;
1760            int k = (x + Data->iEdgedWidth*y) * 16;
1761            MainSearchFunc *MainSearchPtr;
1762    
1763            *Data->iMinSAD = 256*4096;
1764            Data->Ref = f_Ref->y + k;
1765            Data->RefH = f_RefH + k;
1766            Data->RefV = f_RefV + k;
1767            Data->RefHV = f_RefHV + k;
1768            Data->bRef = b_Ref->y + k;
1769            Data->bRefH = b_RefH + k;
1770            Data->bRefV = b_RefV + k;
1771            Data->bRefHV = b_RefHV + k;
1772            Data->RefCU = f_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1773            Data->RefCV = f_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1774            Data->b_RefCU = b_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1775            Data->b_RefCV = b_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1776    
1777            k = Data->qpel ? 4 : 2;
1778            Data->max_dx = k * (pParam->width - x * 16);
1779            Data->max_dy = k * (pParam->height - y * 16);
1780            Data->min_dx = -k * (16 + x * 16);
1781            Data->min_dy = -k * (16 + y * 16);
1782    
1783            Data->referencemv = Data->qpel ? b_mb->qmvs : b_mb->mvs;
1784            Data->qpel_precision = 0;
1785    
1786  // MV=(0,0) is often a good choice          for (k = 0; k < 4; k++) {
1787          CHECK_MV8_ZERO;                  pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);
1788                    pMB->b_mvs[k].x = Data->directmvB[k].x = ((TRB - TRD) * Data->referencemv[k].x) / TRD;
1789                    pMB->mvs[k].y = Data->directmvF[k].y = ((TRB * Data->referencemv[k].y) / TRD);
1790                    pMB->b_mvs[k].y = Data->directmvB[k].y = ((TRB - TRD) * Data->referencemv[k].y) / TRD;
1791    
1792  // previous frame MV                  if ( (pMB->b_mvs[k].x > Data->max_dx) | (pMB->b_mvs[k].x < Data->min_dx)
1793          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) ) {
1794    
1795  // left neighbour, if allowed                          *best_sad = 256*4096; // in that case, we won't use direct mode
1796          if (psad[1] != MV_MAX_ERROR) {                          pMB->mode = MODE_DIRECT; // just to make sure it doesn't say "MODE_DIRECT_NONE_MV"
1797                  if (!(MotionFlags & PMV_HALFPEL8)) {                          pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;
1798                          pmv[1].x = EVEN(pmv[1].x);                          return 256*4096;
                         pmv[1].y = EVEN(pmv[1].y);  
1799                  }                  }
1800                  CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);                  if (b_mb->mode != MODE_INTER4V) {
1801                            pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mvs[0];
1802                            pMB->b_mvs[1] = pMB->b_mvs[2] = pMB->b_mvs[3] = pMB->b_mvs[0];
1803                            Data->directmvF[1] = Data->directmvF[2] = Data->directmvF[3] = Data->directmvF[0];
1804                            Data->directmvB[1] = Data->directmvB[2] = Data->directmvB[3] = Data->directmvB[0];
1805                            break;
1806          }          }
 // 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);  
1807                  }                  }
                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
1808    
1809  // top right neighbour, if allowed          CheckCandidate = b_mb->mode == MODE_INTER4V ? CheckCandidateDirect : CheckCandidateDirectno4v;
1810                  if (psad[3] != MV_MAX_ERROR) {  
1811                          if (!(MotionFlags & PMV_HALFPEL8)) {          CheckCandidate(0, 0, 255, &k, Data);
1812                                  pmv[3].x = EVEN(pmv[3].x);  
1813                                  pmv[3].y = EVEN(pmv[3].y);  // initial (fast) skip decision
1814                          }          if (*Data->iMinSAD < pMB->quant * INITIAL_SKIP_THRESH * (2 + Data->chroma?1:0)) {
1815                          CHECK_MV8_CANDIDATE(pmv[3].x, pmv[3].y);                  //possible skip
1816                    if (Data->chroma) {
1817                            pMB->mode = MODE_DIRECT_NONE_MV;
1818                            return *Data->iMinSAD; // skip.
1819                    } else {
1820                            SkipDecisionB(pCur, f_Ref, b_Ref, pMB, x, y, Data);
1821                            if (pMB->mode == MODE_DIRECT_NONE_MV) return *Data->iMinSAD; // skip.
1822                  }                  }
1823          }          }
1824    
1825  /*  // this bias is zero anyway, at the moment!          *Data->iMinSAD += Data->lambda16;
1826            skip_sad = *Data->iMinSAD;
1827    
1828          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)  //      DIRECT MODE DELTA VECTOR SEARCH.
1829                  iMinSAD -= MV8_00_BIAS;  //      This has to be made more effective, but at the moment I'm happy it's running at all
1830    
1831  */          if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1832                    else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1833                            else MainSearchPtr = DiamondSearch;
1834    
1835  /* Terminate if MinSAD <= T_2          MainSearchPtr(0, 0, Data, 255);
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
1836    
1837          if (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */          SubpelRefine(Data);
1838                  if (MotionFlags & PMV_QUICKSTOP8)  
1839                          goto EPZS8_Terminate_without_Refine;          *best_sad = *Data->iMinSAD;
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
         }  
1840    
1841  /************ (Diamond Search)  **************/          if (Data->qpel || b_mb->mode == MODE_INTER4V) pMB->mode = MODE_DIRECT;
1842            else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation
1843    
1844          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          pMB->pmvs[3] = *Data->currentMV;
1845    
1846          if (!(MotionFlags & PMV_HALFPELDIAMOND8))          for (k = 0; k < 4; k++) {
1847                  iDiamondSize *= 2;                  pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
1848                    pMB->b_mvs[k].x = (     (Data->currentMV->x == 0)
1849                                                            ? Data->directmvB[k].x
1850                                                            :pMB->mvs[k].x - Data->referencemv[k].x);
1851                    pMB->mvs[k].y = (Data->directmvF[k].y + Data->currentMV->y);
1852                    pMB->b_mvs[k].y = ((Data->currentMV->y == 0)
1853                                                            ? Data->directmvB[k].y
1854                                                            : pMB->mvs[k].y - Data->referencemv[k].y);
1855                    if (Data->qpel) {
1856                            pMB->qmvs[k].x = pMB->mvs[k].x; pMB->mvs[k].x /= 2;
1857                            pMB->b_qmvs[k].x = pMB->b_mvs[k].x; pMB->b_mvs[k].x /= 2;
1858                            pMB->qmvs[k].y = pMB->mvs[k].y; pMB->mvs[k].y /= 2;
1859                            pMB->b_qmvs[k].y = pMB->b_mvs[k].y; pMB->b_mvs[k].y /= 2;
1860                    }
1861    
1862                    if (b_mb->mode != MODE_INTER4V) {
1863                            pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1864                            pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1865                            pMB->qmvs[3] = pMB->qmvs[2] = pMB->qmvs[1] = pMB->qmvs[0];
1866                            pMB->b_qmvs[3] = pMB->b_qmvs[2] = pMB->b_qmvs[1] = pMB->b_qmvs[0];
1867                            break;
1868                    }
1869            }
1870            return skip_sad;
1871    }
1872    
1873    static void
1874    SearchInterpolate(const IMAGE * const f_Ref,
1875                                    const uint8_t * const f_RefH,
1876                                    const uint8_t * const f_RefV,
1877                                    const uint8_t * const f_RefHV,
1878                                    const IMAGE * const b_Ref,
1879                                    const uint8_t * const b_RefH,
1880                                    const uint8_t * const b_RefV,
1881                                    const uint8_t * const b_RefHV,
1882                                    const IMAGE * const pCur,
1883                                    const int x, const int y,
1884                                    const uint32_t fcode,
1885                                    const uint32_t bcode,
1886                                    const uint32_t MotionFlags,
1887                                    const MBParam * const pParam,
1888                                    const VECTOR * const f_predMV,
1889                                    const VECTOR * const b_predMV,
1890                                    MACROBLOCK * const pMB,
1891                                    int32_t * const best_sad,
1892                                    SearchData * const fData)
1893    
1894  /* default: use best prediction as starting point for one call of EPZS_MainSearch */  {
1895    
1896  // there is no EPZS^2 for inter4v at the moment          int iDirection, i, j;
1897            SearchData bData;
1898    
1899            fData->qpel_precision = 0;
1900            memcpy(&bData, fData, sizeof(SearchData)); //quick copy of common data
1901            *fData->iMinSAD = 4096*256;
1902            bData.currentMV++; bData.currentQMV++;
1903            fData->iFcode = bData.bFcode = fcode; fData->bFcode = bData.iFcode = bcode;
1904    
1905            i = (x + y * fData->iEdgedWidth) * 16;
1906            bData.bRef = fData->Ref = f_Ref->y + i;
1907            bData.bRefH = fData->RefH = f_RefH + i;
1908            bData.bRefV = fData->RefV = f_RefV + i;
1909            bData.bRefHV = fData->RefHV = f_RefHV + i;
1910            bData.Ref = fData->bRef = b_Ref->y + i;
1911            bData.RefH = fData->bRefH = b_RefH + i;
1912            bData.RefV = fData->bRefV = b_RefV + i;
1913            bData.RefHV = fData->bRefHV = b_RefHV + i;
1914            bData.b_RefCU = fData->RefCU = f_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
1915            bData.b_RefCV = fData->RefCV = f_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
1916            bData.RefCU = fData->b_RefCU = b_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
1917            bData.RefCV = fData->b_RefCV = b_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
1918    
1919    
1920            bData.bpredMV = fData->predMV = *f_predMV;
1921            fData->bpredMV = bData.predMV = *b_predMV;
1922            fData->currentMV[0] = fData->currentMV[2];
1923    
1924            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);
1925            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);
1926    
1927            if (fData->currentMV[0].x > fData->max_dx) fData->currentMV[0].x = fData->max_dx;
1928            if (fData->currentMV[0].x < fData->min_dx) fData->currentMV[0].x = fData->min_dx;
1929            if (fData->currentMV[0].y > fData->max_dy) fData->currentMV[0].y = fData->max_dy;
1930            if (fData->currentMV[0].y < fData->min_dy) fData->currentMV[0].y = fData->min_dy;
1931    
1932            if (fData->currentMV[1].x > bData.max_dx) fData->currentMV[1].x = bData.max_dx;
1933            if (fData->currentMV[1].x < bData.min_dx) fData->currentMV[1].x = bData.min_dx;
1934            if (fData->currentMV[1].y > bData.max_dy) fData->currentMV[1].y = bData.max_dy;
1935            if (fData->currentMV[1].y < bData.min_dy) fData->currentMV[1].y = bData.min_dy;
1936    
1937    if (MotionFlags & PMV_USESQUARES8)          CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, 255, &iDirection, fData);
       MainSearchPtr = Square8_MainSearch;  
   else  
1938    
1939          if (MotionFlags & PMV_ADVANCEDDIAMOND8)  //diamond
1940                  MainSearchPtr = AdvDiamond8_MainSearch;          do {
1941          else                  iDirection = 255;
1942                  MainSearchPtr = Diamond8_MainSearch;                  // forward MV moves
1943                    i = fData->currentMV[0].x; j = fData->currentMV[0].y;
1944    
1945                    CheckCandidateInt(i + 1, j, 0, &iDirection, fData);
1946                    CheckCandidateInt(i, j + 1, 0, &iDirection, fData);
1947                    CheckCandidateInt(i - 1, j, 0, &iDirection, fData);
1948                    CheckCandidateInt(i, j - 1, 0, &iDirection, fData);
1949    
1950                    // backward MV moves
1951                    i = fData->currentMV[1].x; j = fData->currentMV[1].y;
1952                    fData->currentMV[2] = fData->currentMV[0];
1953                    CheckCandidateInt(i + 1, j, 0, &iDirection, &bData);
1954                    CheckCandidateInt(i, j + 1, 0, &iDirection, &bData);
1955                    CheckCandidateInt(i - 1, j, 0, &iDirection, &bData);
1956                    CheckCandidateInt(i, j - 1, 0, &iDirection, &bData);
1957    
1958            } while (!(iDirection));
1959    
1960    //qpel refinement
1961            if (fData->qpel) {
1962                    if (*fData->iMinSAD > *best_sad + 500) return;
1963                    CheckCandidate = CheckCandidateInt;
1964                    fData->qpel_precision = bData.qpel_precision = 1;
1965                    get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode, 1, 0);
1966                    get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode, 1, 0);
1967                    fData->currentQMV[2].x = fData->currentQMV[0].x = 2 * fData->currentMV[0].x;
1968                    fData->currentQMV[2].y = fData->currentQMV[0].y = 2 * fData->currentMV[0].y;
1969                    fData->currentQMV[1].x = 2 * fData->currentMV[1].x;
1970                    fData->currentQMV[1].y = 2 * fData->currentMV[1].y;
1971                    SubpelRefine(fData);
1972                    if (*fData->iMinSAD > *best_sad + 300) return;
1973                    fData->currentQMV[2] = fData->currentQMV[0];
1974                    SubpelRefine(&bData);
1975            }
1976    
1977            *fData->iMinSAD += (2+3) * fData->lambda16; // two bits are needed to code interpolate mode.
1978    
1979            if (*fData->iMinSAD < *best_sad) {
1980                    *best_sad = *fData->iMinSAD;
1981                    pMB->mvs[0] = fData->currentMV[0];
1982                    pMB->b_mvs[0] = fData->currentMV[1];
1983                    pMB->mode = MODE_INTERPOLATE;
1984                    if (fData->qpel) {
1985                            pMB->qmvs[0] = fData->currentQMV[0];
1986                            pMB->b_qmvs[0] = fData->currentQMV[1];
1987                            pMB->pmvs[1].x = pMB->qmvs[0].x - f_predMV->x;
1988                            pMB->pmvs[1].y = pMB->qmvs[0].y - f_predMV->y;
1989                            pMB->pmvs[0].x = pMB->b_qmvs[0].x - b_predMV->x;
1990                            pMB->pmvs[0].y = pMB->b_qmvs[0].y - b_predMV->y;
1991                    } else {
1992                            pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;
1993                            pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;
1994                            pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;
1995                            pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;
1996                    }
1997            }
1998    }
1999    
2000          iSAD =  void
2001                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  MotionEstimationBVOP(MBParam * const pParam,
2002                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,                                           FRAMEINFO * const frame,
2003                                                    min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,                                           const int32_t time_bp,
2004                                                    iQuant, 0);                                           const int32_t time_pp,
2005                                             // forward (past) reference
2006                                             const MACROBLOCK * const f_mbs,
2007                                             const IMAGE * const f_ref,
2008                                             const IMAGE * const f_refH,
2009                                             const IMAGE * const f_refV,
2010                                             const IMAGE * const f_refHV,
2011                                             // backward (future) reference
2012                                             const FRAMEINFO * const b_reference,
2013                                             const IMAGE * const b_ref,
2014                                             const IMAGE * const b_refH,
2015                                             const IMAGE * const b_refV,
2016                                             const IMAGE * const b_refHV)
2017    {
2018            uint32_t i, j;
2019            int32_t best_sad;
2020            uint32_t skip_sad;
2021            int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;
2022            const MACROBLOCK * const b_mbs = b_reference->mbs;
2023    
2024            VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
2025    
2026          if (iSAD < iMinSAD) {          const int32_t TRB = time_pp - time_bp;
2027                  *currMV = newMV;          const int32_t TRD = time_pp;
                 iMinSAD = iSAD;  
         }  
2028    
2029          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) */  
2030    
2031                  if (!(MVequal(pmv[0], backupMV))) {          SearchData Data;
2032                          iSAD =          int32_t iMinSAD;
2033                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,          VECTOR currentMV[3];
2034                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,          VECTOR currentQMV[3];
2035                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,          int32_t temp[8];
2036                                                                    iDiamondSize, iFcode, iQuant, 0);          memset(&Data, 0, sizeof(SearchData));
2037            Data.iEdgedWidth = pParam->edged_width;
2038            Data.currentMV = currentMV; Data.currentQMV = currentQMV;
2039            Data.iMinSAD = &iMinSAD;
2040            Data.lambda16 = lambda_vec16[frame->quant];
2041            Data.qpel = pParam->m_quarterpel;
2042            Data.rounding = 0;
2043            Data.chroma = frame->motion_flags & PMV_CHROMA8;
2044            Data.temp = temp;
2045    
2046                          if (iSAD < iMinSAD) {          Data.RefQ = f_refV->u; // a good place, also used in MC (for similar purpose)
2047                                  *currMV = newMV;          // note: i==horizontal, j==vertical
2048                                  iMinSAD = iSAD;          for (j = 0; j < pParam->mb_height; j++) {
                         }  
                 }  
2049    
2050                  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);  
2051    
2052                          if (iSAD < iMinSAD) {                  for (i = 0; i < pParam->mb_width; i++) {
2053                                  *currMV = newMV;                          MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
2054                                  iMinSAD = iSAD;                          const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
2055                          }  
2056                  }  /* special case, if collocated block is SKIPed in P-VOP: encoding is forward (0,0), cpb=0 without further ado */
2057                            if (b_reference->coding_type != S_VOP)
2058                                    if (b_mb->mode == MODE_NOT_CODED) {
2059                                            pMB->mode = MODE_NOT_CODED;
2060                                            continue;
2061          }          }
2062    
2063  /***************        Choose best MV found     **************/                          Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
2064                            Data.CurU = frame->image.u + (j * Data.iEdgedWidth/2 + i) * 8;
2065    EPZS8_Terminate_with_Refine:                          Data.CurV = frame->image.v + (j * Data.iEdgedWidth/2 + i) * 8;
2066          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step                          pMB->quant = frame->quant;
2067                  iMinSAD =  
2068                          Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  /* direct search comes first, because it (1) checks for SKIP-mode
2069                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,          and (2) sets very good predictions for forward and backward search */
2070                                                          iFcode, iQuant, iEdgedWidth);                          skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2071                                                                            b_ref, b_refH->y, b_refV->y, b_refHV->y,
2072                                                                            &frame->image,
2073                                                                            i, j,
2074                                                                            frame->motion_flags,
2075                                                                            TRB, TRD,
2076                                                                            pParam,
2077                                                                            pMB, b_mb,
2078                                                                            &best_sad,
2079                                                                            &Data);
2080    
2081    EPZS8_Terminate_without_Refine:                          if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
2082    
2083          currPMV->x = currMV->x - center_x;                          // forward search
2084          currPMV->y = currMV->y - center_y;                          SearchBF(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2085          return iMinSAD;                                                  &frame->image, i, j,
2086  }                                                  frame->motion_flags,
2087                                                    frame->fcode, pParam,
2088                                                    pMB, &f_predMV, &best_sad,
2089                                                    MODE_FORWARD, &Data);
2090    
2091                            // backward search
2092                            SearchBF(b_ref, b_refH->y, b_refV->y, b_refHV->y,
2093                                                    &frame->image, i, j,
2094                                                    frame->motion_flags,
2095                                                    frame->bcode, pParam,
2096                                                    pMB, &b_predMV, &best_sad,
2097                                                    MODE_BACKWARD, &Data);
2098    
2099                            // interpolate search comes last, because it uses data from forward and backward as prediction
2100                            SearchInterpolate(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2101                                                    b_ref, b_refH->y, b_refV->y, b_refHV->y,
2102                                                    &frame->image,
2103                                                    i, j,
2104                                                    frame->fcode, frame->bcode,
2105                                                    frame->motion_flags,
2106                                                    pParam,
2107                                                    &f_predMV, &b_predMV,
2108                                                    pMB, &best_sad,
2109                                                    &Data);
2110    
2111    // final skip decision
2112                            if ( (skip_sad < frame->quant * MAX_SAD00_FOR_SKIP * 2)
2113                                            && ((100*best_sad)/(skip_sad+1) > FINAL_SKIP_THRESH) )
2114                                    SkipDecisionB(&frame->image, f_ref, b_ref, pMB, i, j, &Data);
2115    
2116                            switch (pMB->mode) {
2117                                    case MODE_FORWARD:
2118                                            f_count++;
2119                                            f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2120                                            break;
2121                                    case MODE_BACKWARD:
2122                                            b_count++;
2123                                            b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2124                                            break;
2125                                    case MODE_INTERPOLATE:
2126                                            i_count++;
2127                                            f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2128                                            b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2129                                            break;
2130                                    case MODE_DIRECT:
2131                                    case MODE_DIRECT_NO4V:
2132                                            d_count++;
2133                                    default:
2134                                            break;
2135                            }
2136                    }
2137            }
2138    }
2139    
2140  int32_t  static __inline void
2141  PMVfastIntSearch16(const uint8_t * const pRef,  MEanalyzeMB (   const uint8_t * const pRef,
2142                                  const uint8_t * const pRefH,                                  const uint8_t * const pCur,
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const IMAGE * const pCur,  
2143                                  const int x,                                  const int x,
2144                                  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,  
2145                                  const MBParam * const pParam,                                  const MBParam * const pParam,
2146                                  const MACROBLOCK * const pMBs,                                  MACROBLOCK * const pMBs,
2147                                  const MACROBLOCK * const prevMBs,                                  SearchData * const Data)
                                 VECTOR * const currMV,  
                                 VECTOR * const currPMV)  
2148  {  {
         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;  
2149    
2150          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          int i, mask;
2151          const VECTOR zeroMV = { 0, 0 };          VECTOR pmv[3];
2152            MACROBLOCK * const pMB = &pMBs[x + y * pParam->mb_width];
2153    
2154          int32_t iDiamondSize;          for (i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;
2155    
2156          int32_t min_dx;          //median is only used as prediction. it doesn't have to be real
2157          int32_t max_dx;          if (x == 1 && y == 1) Data->predMV.x = Data->predMV.y = 0;
2158          int32_t min_dy;          else
2159          int32_t max_dy;                  if (x == 1) //left macroblock does not have any vector now
2160                            Data->predMV = (pMB - pParam->mb_width)->mvs[0]; // top instead of median
2161          int32_t iFound;                  else if (y == 1) // top macroblock doesn't have it's vector
2162                            Data->predMV = (pMB - 1)->mvs[0]; // left instead of median
2163                            else Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); //else median
2164    
2165          VECTOR newMV;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2166          VECTOR backupMV;                                  pParam->width, pParam->height, Data->iFcode - pParam->m_quarterpel, 0, 0);
2167    
2168          VECTOR pmv[4];          Data->Cur = pCur + (x + y * pParam->edged_width) * 16;
2169          int32_t psad[4];          Data->Ref = pRef + (x + y * pParam->edged_width) * 16;
2170    
2171          MainSearch16FuncPtr MainSearchPtr;          pmv[1].x = EVEN(pMB->mvs[0].x);
2172            pmv[1].y = EVEN(pMB->mvs[0].y);
2173            pmv[2].x = EVEN(Data->predMV.x);
2174            pmv[2].y = EVEN(Data->predMV.y);
2175            pmv[0].x = pmv[0].y = 0;
2176    
2177          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;          CheckCandidate32I(0, 0, 255, &i, Data);
2178          MACROBLOCK *const pMB = pMBs + x + y * iWcount;          Data->iMinSAD[1] -= 50;
2179            Data->iMinSAD[2] -= 50;
2180            Data->iMinSAD[3] -= 50;
2181            Data->iMinSAD[4] -= 50;
2182    
2183          int32_t threshA, threshB;          if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP) {
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD;  
2184    
2185                    if (!(mask = make_mask(pmv, 1)))
2186                            CheckCandidate32I(pmv[1].x, pmv[1].y, mask, &i, Data);
2187                    if (!(mask = make_mask(pmv, 2)))
2188                            CheckCandidate32I(pmv[2].x, pmv[2].y, mask, &i, Data);
2189    
2190  /* Get maximum range */                  if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP) // diamond only if needed
2191          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,                          DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, i);
2192                            iFcode);          }
2193    
2194  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          for (i = 0; i < 4; i++) {
2195                    MACROBLOCK * MB = &pMBs[x + (i&1) + (y+(i>>1)) * pParam->mb_width];
2196                    MB->mvs[0] = MB->mvs[1] = MB->mvs[2] = MB->mvs[3] = Data->currentMV[i];
2197                    MB->mode = MODE_INTER;
2198                    MB->sad16 = Data->iMinSAD[i+1];
2199            }
2200    }
2201    
2202          if ((x == 0) && (y == 0)) {  #define INTRA_THRESH    2400
2203                  threshA = 512;  #define INTER_THRESH    1100
                 threshB = 1024;  
2204    
2205                  bPredEq = 0;  int
2206                  psad[0] = psad[1] = psad[2] = psad[3] = 0;  MEanalysis(     const IMAGE * const pRef,
2207                  *currMV = pmv[0] = pmv[1] = pmv[2] = pmv[3] = zeroMV;                          const FRAMEINFO * const Current,
2208                            const MBParam * const pParam,
2209                            const int maxIntra, //maximum number if non-I frames
2210                            const int intraCount, //number of non-I frames after last I frame; 0 if we force P/B frame
2211                            const int bCount,  // number of B frames in a row
2212                            const int b_thresh)
2213    {
2214            uint32_t x, y, intra = 0;
2215            int sSAD = 0;
2216            MACROBLOCK * const pMBs = Current->mbs;
2217            const IMAGE * const pCurrent = &Current->image;
2218            int IntraThresh = INTRA_THRESH, InterThresh = INTER_THRESH + 10*b_thresh;
2219            int s = 0, blocks = 0;
2220    
2221            int32_t iMinSAD[5], temp[5];
2222            VECTOR currentMV[5];
2223            SearchData Data;
2224            Data.iEdgedWidth = pParam->edged_width;
2225            Data.currentMV = currentMV;
2226            Data.iMinSAD = iMinSAD;
2227            Data.iFcode = Current->fcode;
2228            Data.temp = temp;
2229            CheckCandidate = CheckCandidate32I;
2230    
2231          } else {          if (intraCount != 0 && intraCount < 10) // we're right after an I frame
2232                    IntraThresh += 8 * (intraCount - 10) * (intraCount - 10);
2233            else
2234                    if ( 5*(maxIntra - intraCount) < maxIntra) // we're close to maximum. 2 sec when max is 10 sec
2235                            IntraThresh -= (IntraThresh * (maxIntra - 5*(maxIntra - intraCount)))/maxIntra;
2236    
2237                  bPredEq = get_ipmvdata(pMBs, iWcount, 0, x, y, 0, pmv, psad);          InterThresh -= (350 - 8*b_thresh) * bCount;
2238            if (InterThresh < 300 + 5*b_thresh) InterThresh = 300 + 5*b_thresh;
2239    
2240                  threshA = psad[0];          if (sadInit) (*sadInit) ();
                 threshB = threshA + 256;  
                 if (threshA < 512)  
                         threshA = 512;  
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
2241    
2242                  *currMV = pmv[0];                       /* current best := prediction */          for (y = 1; y < pParam->mb_height-1; y += 2) {
2243                    for (x = 1; x < pParam->mb_width-1; x += 2) {
2244                            int i;
2245                            blocks += 4;
2246    
2247                            if (bCount == 0) pMBs[x + y * pParam->mb_width].mvs[0] = zeroMV;
2248                            else { //extrapolation of the vector found for last frame
2249                                    pMBs[x + y * pParam->mb_width].mvs[0].x =
2250                                            (pMBs[x + y * pParam->mb_width].mvs[0].x * (bCount+1) ) / bCount;
2251                                    pMBs[x + y * pParam->mb_width].mvs[0].y =
2252                                            (pMBs[x + y * pParam->mb_width].mvs[0].y * (bCount+1) ) / bCount;
2253                            }
2254    
2255                            MEanalyzeMB(pRef->y, pCurrent->y, x, y, pParam, pMBs, &Data);
2256    
2257                            for (i = 0; i < 4; i++) {
2258                                    int dev;
2259                                    MACROBLOCK *pMB = &pMBs[x+(i&1) + (y+(i>>1)) * pParam->mb_width];
2260                                    if (pMB->sad16 > IntraThresh) {
2261                                            dev = dev16(pCurrent->y + (x + (i&1) + (y + (i>>1)) * pParam->edged_width) * 16,
2262                                                                            pParam->edged_width);
2263                                            if (dev + IntraThresh < pMB->sad16) {
2264                                                    pMB->mode = MODE_INTRA;
2265                                                    if (++intra > ((pParam->mb_height-2)*(pParam->mb_width-2))/2) return I_VOP;
2266          }          }
   
         iFound = 0;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
   
         if (currMV->x > max_dx) {  
                 currMV->x = EVEN(max_dx);  
2267          }          }
2268          if (currMV->x < min_dx) {                                  if (pMB->mvs[0].x == 0 && pMB->mvs[0].y == 0) s++;
2269                  currMV->x = EVEN(min_dx);  
2270                                    sSAD += pMB->sad16;
2271          }          }
         if (currMV->y > max_dy) {  
                 currMV->y = EVEN(max_dy);  
2272          }          }
         if (currMV->y < min_dy) {  
                 currMV->y = EVEN(min_dy);  
2273          }          }
2274    
2275          iMinSAD =          sSAD /= blocks;
2276                  sad16(cur,          s = (10*s) / blocks;
                           get_iref_mv(pRef, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
2277    
2278          if ((iMinSAD < 256) ||          if (s > 5) sSAD += (s - 4) * (180 - 2*b_thresh); //static block - looks bad when in bframe...
                 ((MVequal(*currMV, prevMB->i_mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->i_sad16))) {  
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
                 {  
                         if (!MVzero(*currMV)) {  
                                 iMinSAD += MV16_00_BIAS;  
                                 CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures  
                                 iMinSAD -= MV16_00_BIAS;  
                         }  
                 }  
2279    
2280                  if (MotionFlags & PMV_EARLYSTOP16)          if (sSAD > InterThresh ) return P_VOP;
2281                          goto PMVfastInt16_Terminate_with_Refine;          emms();
2282            return B_VOP;
2283          }          }
2284    
2285    
2286  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  static WARPPOINTS
2287     vector of the median.  GlobalMotionEst(const MACROBLOCK * const pMBs,
2288     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2                                  const MBParam * const pParam,
2289  */                                  const FRAMEINFO * const current,
2290                                    const FRAMEINFO * const reference,
2291          if ((bPredEq) && (MVequal(pmv[0], prevMB->i_mvs[0])))                                  const IMAGE * const pRefH,
2292                  iFound = 2;                                  const IMAGE * const pRefV,
2293                                    const IMAGE * const pRefHV      )
2294    {
2295    
2296  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          const int deltax=8;             // upper bound for difference between a MV and it's neighbour MVs
2297     Otherwise select large Diamond Search.          const int deltay=8;
2298  */          const int grad=512;             // lower bound for deviation in MB
2299    
2300          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))          WARPPOINTS gmc;
                 iDiamondSize = 2;               // halfpel units!  
         else  
                 iDiamondSize = 4;               // halfpel units!  
2301    
2302  /*          uint32_t mx, my;
    Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  
    Also calculate (0,0) but do not subtract offset.  
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset.  
 */  
2303    
2304  // (0,0) is often a good choice          int MBh = pParam->mb_height;
2305            int MBw = pParam->mb_width;
2306    
2307          if (!MVzero(pmv[0]))          int *MBmask= calloc(MBh*MBw,sizeof(int));
2308                  CHECK_MV16_ZERO;          double DtimesF[4] = { 0.,0., 0., 0. };
2309            double sol[4] = { 0., 0., 0., 0. };
2310            double a,b,c,n,denom;
2311            double meanx,meany;
2312            int num,oldnum;
2313    
2314  // previous frame MV is always possible          if (!MBmask) { fprintf(stderr,"Mem error\n");
2315                                   gmc.duv[0].x= gmc.duv[0].y =
2316                                                    gmc.duv[1].x= gmc.duv[1].y =
2317                                                    gmc.duv[2].x= gmc.duv[2].y = 0;
2318                                            return gmc; }
2319    
2320          if (!MVzero(prevMB->i_mvs[0]))  // filter mask of all blocks
                 if (!MVequal(prevMB->i_mvs[0], pmv[0]))  
                         CHECK_MV16_CANDIDATE(prevMB->i_mvs[0].x, prevMB->i_mvs[0].y);  
   
 // left neighbour, if allowed  
   
         if (!MVzero(pmv[1]))  
                 if (!MVequal(pmv[1], prevMB->i_mvs[0]))  
                         if (!MVequal(pmv[1], pmv[0]))  
                                 CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
   
 // top neighbour, if allowed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], prevMB->i_mvs[0]))  
                         if (!MVequal(pmv[2], pmv[0]))  
                                 if (!MVequal(pmv[2], pmv[1]))  
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed  
                                         if (!MVzero(pmv[3]))  
                                                 if (!MVequal(pmv[3], prevMB->i_mvs[0]))  
                                                         if (!MVequal(pmv[3], pmv[0]))  
                                                                 if (!MVequal(pmv[3], pmv[1]))  
                                                                         if (!MVequal(pmv[3], pmv[2]))  
                                                                                 CHECK_MV16_CANDIDATE(pmv[3].x,  
                                                                                                                          pmv[3].y);  
   
         if ((MVzero(*currMV)) &&  
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV16_00_BIAS;  
2321    
2322            for (my = 1; my < (uint32_t)MBh-1; my++)
2323            for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2324            {
2325                    const int mbnum = mx + my * MBw;
2326                    const MACROBLOCK *pMB = &pMBs[mbnum];
2327                    const VECTOR mv = pMB->mvs[0];
2328    
2329  /* Step 6: If MinSAD <= thresa goto Step 10.                  if (pMB->mode == MODE_INTRA || pMB->mode == MODE_NOT_CODED)
2330     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.                          continue;
 */  
2331    
2332          if ((iMinSAD <= threshA) ||                  if ( ( (ABS(mv.x -   (pMB-1)->mvs[0].x) < deltax) && (ABS(mv.y -   (pMB-1)->mvs[0].y) < deltay) )
2333                  (MVequal(*currMV, prevMB->i_mvs[0]) &&                  &&   ( (ABS(mv.x -   (pMB+1)->mvs[0].x) < deltax) && (ABS(mv.y -   (pMB+1)->mvs[0].y) < deltay) )
2334                   ((int32_t) iMinSAD < prevMB->i_sad16))) {                  &&   ( (ABS(mv.x - (pMB-MBw)->mvs[0].x) < deltax) && (ABS(mv.y - (pMB-MBw)->mvs[0].y) < deltay) )
2335                    &&   ( (ABS(mv.x - (pMB+MBw)->mvs[0].x) < deltax) && (ABS(mv.y - (pMB+MBw)->mvs[0].y) < deltay) ) )
2336                  if (MotionFlags & PMV_EARLYSTOP16)                          MBmask[mbnum]=1;
                         goto PMVfastInt16_Terminate_with_Refine;  
2337          }          }
2338    
2339            for (my = 1; my < (uint32_t)MBh-1; my++)
2340            for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2341            {
2342                    const uint8_t *const pCur = current->image.y + 16*my*pParam->edged_width + 16*mx;
2343    
2344  /************ (Diamond Search)  **************/                  const int mbnum = mx + my * MBw;
2345  /*                  if (!MBmask[mbnum])
2346     Step 7: Perform Diamond search, with either the small or large diamond.                          continue;
    If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
    Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
    If center then goto step 10.  
    Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
    Refine by using small diamond and goto step 10.  
 */  
   
         if (MotionFlags & PMV_USESQUARES16)  
                 MainSearchPtr = Square16_MainSearch;  
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
2347    
2348          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                  if (sad16 ( pCur, pCur+1 , pParam->edged_width, 65536) <= (uint32_t)grad )
2349                            MBmask[mbnum] = 0;
2350                    if (sad16 ( pCur, pCur+pParam->edged_width, pParam->edged_width, 65536) <= (uint32_t)grad )
2351                            MBmask[mbnum] = 0;
2352    
2353            }
2354    
2355  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          emms();
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  
                                                   currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
2356    
2357          if (iSAD < iMinSAD) {          do {            /* until convergence */
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
2358    
2359          if (MotionFlags & PMV_EXTSEARCH16) {          a = b = c = n = 0;
2360  /* extended: search (up to) two more times: orignal prediction and (0,0) */          DtimesF[0] = DtimesF[1] = DtimesF[2] = DtimesF[3] = 0.;
2361            for (my = 0; my < (uint32_t)MBh; my++)
2362                    for (mx = 0; mx < (uint32_t)MBw; mx++)
2363                    {
2364                            const int mbnum = mx + my * MBw;
2365                            const MACROBLOCK *pMB = &pMBs[mbnum];
2366                            const VECTOR mv = pMB->mvs[0];
2367    
2368                  if (!(MVequal(pmv[0], backupMV))) {                          if (!MBmask[mbnum])
2369                          iSAD =                                  continue;
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
2370    
2371                          if (iSAD < iMinSAD) {                          n++;
2372                                  *currMV = newMV;                          a += 16*mx+8;
2373                                  iMinSAD = iSAD;                          b += 16*my+8;
2374                          }                          c += (16*mx+8)*(16*mx+8)+(16*my+8)*(16*my+8);
2375                  }  
2376                            DtimesF[0] += (double)mv.x;
2377                            DtimesF[1] += (double)mv.x*(16*mx+8) + (double)mv.y*(16*my+8);
2378                            DtimesF[2] += (double)mv.x*(16*my+8) - (double)mv.y*(16*mx+8);
2379                            DtimesF[3] += (double)mv.y;
2380                    }
2381    
2382            denom = a*a+b*b-c*n;
2383    
2384    /* Solve the system:     sol = (D'*E*D)^{-1} D'*E*F   */
2385    /* D'*E*F has been calculated in the same loop as matrix */
2386    
2387            sol[0] = -c*DtimesF[0] + a*DtimesF[1] + b*DtimesF[2];
2388            sol[1] =  a*DtimesF[0] - n*DtimesF[1]                + b*DtimesF[3];
2389            sol[2] =  b*DtimesF[0]                - n*DtimesF[2] - a*DtimesF[3];
2390            sol[3] =                 b*DtimesF[1] - a*DtimesF[2] - c*DtimesF[3];
2391    
2392            sol[0] /= denom;
2393            sol[1] /= denom;
2394            sol[2] /= denom;
2395            sol[3] /= denom;
2396    
2397            meanx = meany = 0.;
2398            oldnum = 0;
2399            for (my = 0; my < (uint32_t)MBh; my++)
2400                    for (mx = 0; mx < (uint32_t)MBw; mx++)
2401                    {
2402                            const int mbnum = mx + my * MBw;
2403                            const MACROBLOCK *pMB = &pMBs[mbnum];
2404                            const VECTOR mv = pMB->mvs[0];
2405    
2406                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                          if (!MBmask[mbnum])
2407                          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);  
2408    
2409                          if (iSAD < iMinSAD) {                          oldnum++;
2410                                  *currMV = newMV;                          meanx += ABS(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - mv.x );
2411                                  iMinSAD = iSAD;                          meany += ABS(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - mv.y );
                         }  
2412                  }                  }
         }  
   
 /*  
    Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  
 */  
2413    
2414  PMVfastInt16_Terminate_with_Refine:          if (4*meanx > oldnum)   /* better fit than 0.25 is useless */
2415                    meanx /= oldnum;
2416            else
2417                    meanx = 0.25;
2418    
2419          pMB->i_mvs[0] = pMB->i_mvs[1] = pMB->i_mvs[2] = pMB->i_mvs[3] = pMB->i_mv16 = *currMV;          if (4*meany > oldnum)
2420          pMB->i_sad8[0] = pMB->i_sad8[1] = pMB->i_sad8[2] = pMB->i_sad8[3] = pMB->i_sad16 = iMinSAD;                  meany /= oldnum;
2421            else
2422                    meany = 0.25;
2423    
2424          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step  /*      fprintf(stderr,"sol = (%8.5f, %8.5f, %8.5f, %8.5f)\n",sol[0],sol[1],sol[2],sol[3]);
2425                  iMinSAD =          fprintf(stderr,"meanx = %8.5f  meany = %8.5f   %d\n",meanx,meany, oldnum);
2426                          Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  */
2427                                                           iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,          num = 0;
2428                                                           iFcode, iQuant, iEdgedWidth);          for (my = 0; my < (uint32_t)MBh; my++)
2429                    for (mx = 0; mx < (uint32_t)MBw; mx++)
2430                    {
2431                            const int mbnum = mx + my * MBw;
2432                            const MACROBLOCK *pMB = &pMBs[mbnum];
2433                            const VECTOR mv = pMB->mvs[0];
2434    
2435          pmv[0] = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          // get _REAL_ prediction (halfpel possible)                          if (!MBmask[mbnum])
2436                                    continue;
2437    
2438  PMVfastInt16_Terminate_without_Refine:                          if  ( ( ABS(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - mv.x ) > meanx )
2439          currPMV->x = currMV->x - center_x;                             || ( ABS(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - mv.y ) > meany ) )
2440          currPMV->y = currMV->y - center_y;                                  MBmask[mbnum]=0;
2441          return iMinSAD;                          else
2442                                    num++;
2443  }  }
2444    
2445            } while ( (oldnum != num) && (num>=4) );
2446    
2447            if (num < 4)
 /* ***********************************************************  
         bvop motion estimation  
 ***************************************************************/  
   
 void  
 MotionEstimationBVOP(MBParam * const pParam,  
                                          FRAMEINFO * const frame,  
                                          const int32_t time_bp,  
                                          const int32_t time_pp,  
                                          // forward (past) reference  
                                          const MACROBLOCK * const f_mbs,  
                                          const IMAGE * const f_ref,  
                                          const IMAGE * const f_refH,  
                                          const IMAGE * const f_refV,  
                                          const IMAGE * const f_refHV,  
                                          // backward (future) reference  
                                          const MACROBLOCK * const b_mbs,  
                                          const IMAGE * const b_ref,  
                                          const IMAGE * const b_refH,  
                                          const IMAGE * const b_refV,  
                                          const IMAGE * const b_refHV)  
2448  {  {
2449          const int mb_width = pParam->mb_width;                  gmc.duv[0].x= gmc.duv[0].y= gmc.duv[1].x= gmc.duv[1].y= gmc.duv[2].x= gmc.duv[2].y=0;
2450          const int mb_height = pParam->mb_height;          } else {
         const int edged_width = pParam->edged_width;  
   
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
2451    
2452          int i, j, k;                  gmc.duv[0].x=(int)(sol[0]+0.5);
2453                    gmc.duv[0].y=(int)(sol[3]+0.5);
2454    
2455          static const VECTOR zeroMV={0,0};                  gmc.duv[1].x=(int)(sol[1]*pParam->width+0.5);
2456                    gmc.duv[1].y=(int)(-sol[2]*pParam->width+0.5);
2457    
2458          int f_sad16;    /* forward (as usual) search */                  gmc.duv[2].x=0;
2459          int b_sad16;    /* backward (only in b-frames) search */                  gmc.duv[2].y=0;
2460          int i_sad16;    /* interpolated (both direction, b-frames only) */          }
2461          int d_sad16;    /* direct mode (assume almost linear motion) */  //      fprintf(stderr,"wp1 = ( %4d, %4d)  wp2 = ( %4d, %4d) \n", gmc.duv[0].x, gmc.duv[0].y, gmc.duv[1].x, gmc.duv[1].y);
2462    
2463          int best_sad;          free(MBmask);
2464    
2465          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/          return gmc;
2466          VECTOR f_interpolMV, b_interpolMV;  }
         VECTOR pmv_dontcare;  
2467    
2468          int min_dx, max_dx, min_dy, max_dy;  // functions which perform BITS-based search/bitcount
         int f_min_dx, f_max_dx, f_min_dy, f_max_dy;  
         int b_min_dx, b_max_dx, b_min_dy, b_max_dy;  
   
         int f_count=0;  
         int b_count=0;  
         int i_count=0;  
         int d_count=0;  
2469    
2470          const int64_t TRB = (int32_t)time_pp - (int32_t)time_bp;  static int
2471      const int64_t TRD = (int32_t)time_pp;  CountMBBitsInter(SearchData * const Data,
2472                                    const MACROBLOCK * const pMBs, const int x, const int y,
2473                                    const MBParam * const pParam,
2474                                    const uint32_t MotionFlags)
2475    {
2476            int i, iDirection;
2477            int32_t bsad[5];
2478    
2479          // fprintf(stderr,"TRB = %lld  TRD = %lld  time_bp =%d time_pp =%d\n\n",TRB,TRD,time_bp,time_pp);          CheckCandidate = CheckCandidateBits16;
         // note: i==horizontal, j==vertical  
         for (j = 0; j < mb_height; j++) {  
2480    
2481                  f_predMV = zeroMV;      /* prediction is reset at left boundary */          if (Data->qpel) {
2482                  b_predMV = zeroMV;                  for(i = 0; i < 5; i++) {
2483                            Data->currentMV[i].x = Data->currentQMV[i].x/2;
2484                            Data->currentMV[i].y = Data->currentQMV[i].y/2;
2485                    }
2486                    Data->qpel_precision = 1;
2487                    CheckCandidateBits16(Data->currentQMV[0].x, Data->currentQMV[0].y, 255, &iDirection, Data);
2488    
2489                  for (i = 0; i < mb_width; i++) {                  //checking if this vector is perfect. if it is, we stop.
2490                          MACROBLOCK *mb = &frame->mbs[i + j * mb_width];                  if (Data->temp[0] == 0 && Data->temp[1] == 0 && Data->temp[2] == 0 && Data->temp[3] == 0)
2491                          const MACROBLOCK *f_mb = &f_mbs[i + j * mb_width];                          return 0; //quick stop
                         const MACROBLOCK *b_mb = &b_mbs[i + j * mb_width];  
2492    
2493                          mb->deltamv=zeroMV;                  if (MotionFlags & (HALFPELREFINE16_BITS | EXTSEARCH_BITS)) { //we have to prepare for halfpixel-precision search
2494                            for(i = 0; i < 5; i++) bsad[i] = Data->iMinSAD[i];
2495                            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2496                                                    pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
2497                            Data->qpel_precision = 0;
2498                            if (Data->currentQMV->x & 1 || Data->currentQMV->y & 1)
2499                                    CheckCandidateBits16(Data->currentMV[0].x, Data->currentMV[0].y, 255, &iDirection, Data);
2500                    }
2501    
2502  /* special case, if collocated block is SKIPed: encoding is forward (0,0), cpb=0 without further ado */          } else { // not qpel
2503    
2504                          if (b_mb->mode == MODE_INTER && b_mb->cbp == 0 &&                  CheckCandidateBits16(Data->currentMV[0].x, Data->currentMV[0].y, 255, &iDirection, Data);
2505                                  b_mb->mvs[0].x == 0 && b_mb->mvs[0].y == 0) {                  //checking if this vector is perfect. if it is, we stop.
2506                                  mb->mode = MODE_NOT_CODED;                  if (Data->temp[0] == 0 && Data->temp[1] == 0 && Data->temp[2] == 0 && Data->temp[3] == 0) {
2507                                  mb->b_mvs[0] = mb->mvs[0] = zeroMV;                          return 0; //inter
2508                                  continue;                  }
2509                          }                          }
2510    
2511                          if (b_mb->mode == MODE_INTER4V)          if (MotionFlags&EXTSEARCH_BITS) SquareSearch(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
                         {  
                                 d_sad16 = 0;  
                         /* same method of scaling as in decoder.c, so we copy from there */  
                     for (k = 0; k < 4; k++) {  
2512    
2513                                          mb->directmv[k] = b_mb->mvs[k];          if (MotionFlags&HALFPELREFINE16_BITS) SubpelRefine(Data);
2514    
2515                                          mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);          if (Data->qpel) {
2516                      mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)                  if (MotionFlags&(EXTSEARCH_BITS | HALFPELREFINE16_BITS)) { // there was halfpel-precision search
2517                                                                                  ? ((TRB - TRD) * mb->directmv[k].x) / TRD                          for(i = 0; i < 5; i++) if (bsad[i] > Data->iMinSAD[i]) {
2518                                              : mb->mvs[k].x - mb->directmv[k].x);                                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // we have found a better match
2519                                    Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
                     mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);  
                         mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)  
                                                                                 ? ((TRB - TRD) * mb->directmv[k].y) / TRD  
                                             : mb->mvs[k].y - mb->directmv[k].y);  
   
                                         d_sad16 +=  
                                                 sad8bi(frame->image.y + (2*i+(k&1))*8 + (2*j+(k>>1))*8*edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 (2*i+(k&1)), (2*j+(k>>1)), 8, &mb->mvs[k], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 (2*i+(k&1)), (2*j+(k>>1)), 8, &mb->b_mvs[k], edged_width),  
                                                   edged_width);  
                                 }  
2520                          }                          }
                         else  
                         {  
                                 mb->directmv[3] = mb->directmv[2] = mb->directmv[1] =  
                                         mb->directmv[0] = b_mb->mvs[0];  
2521    
2522                                  mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);                          // preparing for qpel-precision search
2523                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)                          Data->qpel_precision = 1;
2524                                                                          ? ((TRB - TRD) * mb->directmv[0].x) / TRD                          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2525                                      : mb->mvs[0].x - mb->directmv[0].x);                                          pParam->width, pParam->height, Data->iFcode, 1, 0);
2526                    }
2527                      mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);                  if (MotionFlags&QUARTERPELREFINE16_BITS) SubpelRefine(Data);
2528                  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);  
2529    
2530            if (MotionFlags&CHECKPREDICTION_BITS) { //let's check vector equal to prediction
2531                    VECTOR * v = Data->qpel ? Data->currentQMV : Data->currentMV;
2532                    if (!(Data->predMV.x == v->x && Data->predMV.y == v->y))
2533                            CheckCandidateBits16(Data->predMV.x, Data->predMV.y, 255, &iDirection, Data);
2534            }
2535            return Data->iMinSAD[0];
2536              }              }
                     d_sad16 += calc_delta_16(mb->deltamv.x, mb->deltamv.y, 1, frame->quant);  
2537    
                         // forward search  
                         f_sad16 = SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 &frame->image, i, j,  
                                                 mb->mvs[0].x, mb->mvs[0].y,                     /* start point f_directMV */  
                                                 f_predMV.x, f_predMV.y,                         /* center is f-prediction */  
                                                 frame->motion_flags,  
                                                 frame->quant, frame->fcode, pParam,  
                                                 f_mbs, f_mbs,  
                                                 &mb->mvs[0], &pmv_dontcare);  
2538    
2539    static int
2540    CountMBBitsInter4v(const SearchData * const Data,
2541                                            MACROBLOCK * const pMB, const MACROBLOCK * const pMBs,
2542                                            const int x, const int y,
2543                                            const MBParam * const pParam, const uint32_t MotionFlags,
2544                                            const VECTOR * const backup)
2545    {
2546    
2547                          // backward search          int cbp = 0, bits = 0, t = 0, i, iDirection;
2548                          b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,          SearchData Data2, *Data8 = &Data2;
2549                                                  &frame->image, i, j,          int sumx = 0, sumy = 0;
2550                                                  mb->b_mvs[0].x, mb->b_mvs[0].y,         /* start point b_directMV */          int16_t in[64], coeff[64];
2551                                                  b_predMV.x, b_predMV.y,                         /* center is b-prediction */  
2552                                                  frame->motion_flags,          memcpy(Data8, Data, sizeof(SearchData));
2553                                                  frame->quant, frame->bcode, pParam,          CheckCandidate = CheckCandidateBits8;
2554                                                  b_mbs, b_mbs,  
2555                                                  &mb->b_mvs[0], &pmv_dontcare);          for (i = 0; i < 4; i++) {
2556                    Data8->iMinSAD = Data->iMinSAD + i + 1;
2557                          i_sad16 =                  Data8->currentMV = Data->currentMV + i + 1;
2558                                  sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,                  Data8->currentQMV = Data->currentQMV + i + 1;
2559                                                    get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,                  Data8->Cur = Data->Cur + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2560                                                                  i, j, 16, &mb->mvs[0], edged_width),                  Data8->Ref = Data->Ref + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2561                                                    get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,                  Data8->RefH = Data->RefH + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2562                                                                  i, j, 16, &mb->b_mvs[0], edged_width),                  Data8->RefV = Data->RefV + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2563                                                    edged_width);                  Data8->RefHV = Data->RefHV + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2564                      i_sad16 += calc_delta_16(mb->mvs[0].x-f_predMV.x, mb->mvs[0].y-f_predMV.y,  
2565                                                                  frame->fcode, frame->quant);                  if(Data->qpel) {
2566                      i_sad16 += calc_delta_16(mb->b_mvs[0].x-b_predMV.x, mb->b_mvs[0].y-b_predMV.y,                          Data8->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, i);
2567                                                                  frame->bcode, frame->quant);                          if (i != 0)     t = d_mv_bits(  Data8->currentQMV->x, Data8->currentQMV->y,
2568                                                                                    Data8->predMV, Data8->iFcode, 0, 0);
                         get_range(&f_min_dx, &f_max_dx, &f_min_dy, &f_max_dy, i, j, 16, iWidth, iHeight,  
                           frame->fcode);  
                         get_range(&b_min_dx, &b_max_dx, &b_min_dy, &b_max_dy, i, j, 16, iWidth, iHeight,  
                           frame->bcode);  
   
 /* Interpolated MC motion vector search, this is tedious and more complicated because there are  
    two values for everything, always one for backward and one for forward ME. Still, we don't gain  
    much from this search, maybe it should simply be skipped and simply current i_sad16 value used  
    as "optimal". */  
   
                         i_sad16 = Diamond16_InterpolMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i * 16 + j * 16 * edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 mb->mvs[0].x, mb->mvs[0].y,  
                                                 mb->b_mvs[0].x, mb->b_mvs[0].y,  
                                                 i_sad16,  
                                                 &f_interpolMV, &b_interpolMV,  
                                                 f_predMV.x, f_predMV.y, b_predMV.x, b_predMV.y,  
                                                 f_min_dx, f_max_dx, f_min_dy, f_max_dy,  
                                                 b_min_dx, b_max_dx, b_min_dy, b_max_dy,  
                                                 edged_width,  2,  
                                                 frame->fcode, frame->bcode,frame->quant,0);  
   
                         i_sad16 = Diamond16_InterpolMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i * 16 + j * 16 * edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 f_interpolMV.x, f_interpolMV.y,  
                                                 b_interpolMV.x, b_interpolMV.y,  
                                                 i_sad16,  
                                                 &f_interpolMV, &b_interpolMV,  
                                                 f_predMV.x, f_predMV.y, b_predMV.x, b_predMV.y,  
                                                 f_min_dx, f_max_dx, f_min_dy, f_max_dy,  
                                                 b_min_dx, b_max_dx, b_min_dy, b_max_dy,  
                                                 edged_width,  1,  
                                                 frame->fcode, frame->bcode,frame->quant,0);             // equiv to halfpel refine  
   
   
 /*  DIRECT MODE DELTA VECTOR SEARCH.  
     This has to be made more effective, but at the moment I'm happy it's running at all */  
   
 /* There are two range restrictions for direct mode: deltaMV is limited to [-32,31] in halfpel units, and  
    absolute vector must not lie outside of image dimensions. Constraint one is dealt with by CHECK_MV16_DIRECT  
    and for constraint two we need distance to boundary. This is done by get_range very large fcode (hack!) */  
   
                         get_range(&min_dx, &max_dx, &min_dy, &max_dy, i, j, 16, iWidth, iHeight, 19);  
   
                         d_sad16 = Diamond16_DirectMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i*16 + j*16*edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 TRB,TRD,  
                                                 0,0,  
                                                 d_sad16,  
                                                 &mb->deltamv,  
                                                 mb->directmv, // this has to be pre-initialized with b_mb->mvs[]  
                                         min_dx, max_dx, min_dy, max_dy,  
                                                 edged_width, 2, frame->quant, 0);  
   
                         d_sad16 = Diamond16_DirectMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i*16 + j*16*edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 TRB,TRD,  
                                                 mb->deltamv.x, mb->deltamv.y,  
                                                 d_sad16,  
                                                 &mb->deltamv,  
                                                 mb->directmv, // this has to be pre-initialized with b_mb->mvs[]  
                                         min_dx, max_dx, min_dy, max_dy,  
                                                 edged_width, 1, frame->quant, 0);               // equiv to halfpel refine  
   
   
 //                      i_sad16 = 65535;                /* remove the comment to disable any of the MODEs */  
 //                      f_sad16 = 65535;  
 //                      b_sad16 = 65535;  
 //                      d_sad16 = 65535;  
   
                         if (f_sad16 < b_sad16) {  
                                 best_sad = f_sad16;  
                                 mb->mode = MODE_FORWARD;  
2569                          } else {                          } else {
2570                                  best_sad = b_sad16;                          Data8->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, i);
2571                                  mb->mode = MODE_BACKWARD;                          if (i != 0)     t = d_mv_bits(  Data8->currentMV->x, Data8->currentMV->y,
2572                                                                                    Data8->predMV, Data8->iFcode, 0, 0);
2573                          }                          }
2574    
2575                          if (i_sad16 < best_sad) {                  get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 8,
2576                                  best_sad = i_sad16;                                          pParam->width, pParam->height, Data8->iFcode, Data8->qpel, 0);
2577                                  mb->mode = MODE_INTERPOLATE;  
2578                    *Data8->iMinSAD += t;
2579    
2580                    Data8->qpel_precision = Data8->qpel;
2581                    // checking the vector which has been found by SAD-based 8x8 search (if it's different than the one found so far)
2582                    if (Data8->qpel) {
2583                            if (!(Data8->currentQMV->x == backup[i+1].x && Data8->currentQMV->y == backup[i+1].y))
2584                                    CheckCandidateBits8(backup[i+1].x, backup[i+1].y, 255, &iDirection, Data8);
2585                    } else {
2586                            if (!(Data8->currentMV->x == backup[i+1].x && Data8->currentMV->y == backup[i+1].y))
2587                                    CheckCandidateBits8(backup[i+1].x, backup[i+1].y, 255, &iDirection, Data8);
2588                          }                          }
2589    
2590                          if (d_sad16 < best_sad) {                  if (Data8->qpel) {
2591                            if (MotionFlags&HALFPELREFINE8_BITS || (MotionFlags&PMV_EXTSEARCH8 && MotionFlags&EXTSEARCH_BITS)) { // halfpixel motion search follows
2592                                    int32_t s = *Data8->iMinSAD;
2593                                    Data8->currentMV->x = Data8->currentQMV->x/2;
2594                                    Data8->currentMV->y = Data8->currentQMV->y/2;
2595                                    Data8->qpel_precision = 0;
2596                                    get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 8,
2597                                                            pParam->width, pParam->height, Data8->iFcode - 1, 0, 0);
2598    
2599                                  if (b_mb->mode == MODE_INTER4V)                                  if (Data8->currentQMV->x & 1 || Data8->currentQMV->y & 1)
2600                                  {                                          CheckCandidateBits8(Data8->currentMV->x, Data8->currentMV->y, 255, &iDirection, Data8);
2601    
2602                                  /* how to calc vectors is defined in standard. mvs[] and b_mvs[] are only for motion compensation */                                  if (MotionFlags & PMV_EXTSEARCH8 && MotionFlags & EXTSEARCH_BITS)
2603                                  /* for the bitstream, the value mb->deltamv is read directly */                                          SquareSearch(Data8->currentMV->x, Data8->currentMV->x, Data8, 255);
2604    
2605                              for (k = 0; k < 4; k++) {                                  if (MotionFlags & HALFPELREFINE8_BITS) SubpelRefine(Data8);
2606    
2607                                                  mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);                                  if(s > *Data8->iMinSAD) { //we have found a better match
2608                              mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)                                          Data8->currentQMV->x = 2*Data8->currentMV->x;
2609                                                                                          ? ((TRB - TRD) * mb->directmv[k].x) / TRD                                          Data8->currentQMV->y = 2*Data8->currentMV->y;
                                                     : mb->mvs[k].x - mb->directmv[k].x);  
   
                             mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);  
                         mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)  
                                                                                         ? ((TRB - TRD) * mb->directmv[k].y) / TRD  
                                             : mb->mvs[k].y - mb->directmv[k].y);  
2610                                          }                                          }
                                 }  
                                 else  
                                 {  
                                         mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);  
2611    
2612                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)                                  Data8->qpel_precision = 1;
2613                                                                                  ? ((TRB - TRD) * mb->directmv[0].x) / TRD                                  get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 8,
2614                                          : mb->mvs[0].x - mb->directmv[0].x);                                                          pParam->width, pParam->height, Data8->iFcode, 1, 0);
2615    
2616                              mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);                          }
2617                            if (MotionFlags & QUARTERPELREFINE8_BITS) SubpelRefine(Data8);
2618    
2619                          mb->b_mvs[0].y = (int32_t) ((mb->deltamv.y == 0)                  } else // not qpel
2620                                                                                  ? ((TRB - TRD) * mb->directmv[0].y) / TRD                          if (MotionFlags & HALFPELREFINE8_BITS) SubpelRefine(Data8); //halfpel mode, halfpel refinement
                                             : mb->mvs[0].y - mb->directmv[0].y);  
2621    
2622                                          mb->mvs[3] = mb->mvs[2] = mb->mvs[1] = mb->mvs[0];                  //checking vector equal to predicion
2623                                          mb->b_mvs[3] = mb->b_mvs[2] = mb->b_mvs[1] = mb->b_mvs[0];                  if (i != 0 && MotionFlags & CHECKPREDICTION_BITS) {
2624                            const VECTOR * v = Data->qpel ? Data8->currentQMV : Data8->currentMV;
2625                            if (!(Data8->predMV.x == v->x && Data8->predMV.y == v->y))
2626                                    CheckCandidateBits8(Data8->predMV.x, Data8->predMV.y, 255, &iDirection, Data8);
2627                  }                  }
2628    
2629                                  best_sad = d_sad16;                  bits += *Data8->iMinSAD;
2630                                  mb->mode = MODE_DIRECT;                  if (bits >= Data->iMinSAD[0]) break; // no chances for INTER4V
                         }  
2631    
2632                          switch (mb->mode)                  // MB structures for INTER4V mode; we have to set them here, we don't have predictor anywhere else
2633                          {                  if(Data->qpel) {
2634                                  case MODE_FORWARD:                          pMB->pmvs[i].x = Data8->currentQMV->x - Data8->predMV.x;
2635                                          f_count++;                          pMB->pmvs[i].y = Data8->currentQMV->y - Data8->predMV.y;
2636                                          f_predMV = mb->mvs[0];                          pMB->qmvs[i] = *Data8->currentQMV;
2637                                          break;                          sumx += Data8->currentQMV->x/2;
2638                                  case MODE_BACKWARD:                          sumy += Data8->currentQMV->y/2;
2639                                          b_count++;                  } else {
2640                                          b_predMV = mb->b_mvs[0];                          pMB->pmvs[i].x = Data8->currentMV->x - Data8->predMV.x;
2641                            pMB->pmvs[i].y = Data8->currentMV->y - Data8->predMV.y;
2642                            sumx += Data8->currentMV->x;
2643                            sumy += Data8->currentMV->y;
2644                    }
2645                    pMB->mvs[i] = *Data8->currentMV;
2646                    pMB->sad8[i] = 4 * *Data8->iMinSAD;
2647                    if (Data8->temp[0]) cbp |= 1 << (5 - i);
2648            }
2649    
2650            if (bits < *Data->iMinSAD) { // there is still a chance for inter4v mode. let's check chroma
2651                    const uint8_t * ptr;
2652                    sumx = (sumx >> 3) + roundtab_76[sumx & 0xf];
2653                    sumy = (sumy >> 3) + roundtab_76[sumy & 0xf];
2654    
2655                    //chroma U
2656                    ptr = interpolate8x8_switch2(Data->RefQ + 64, Data->RefCU, 0, 0, sumx, sumy, Data->iEdgedWidth/2, Data->rounding);
2657                    transfer_8to16subro(in, Data->CurU, ptr, Data->iEdgedWidth/2);
2658                    fdct(in);
2659                    if (Data->lambda8 == 0) i = quant_inter(coeff, in, Data->lambda16);
2660                    else i = quant4_inter(coeff, in, Data->lambda16);
2661                    if (i > 0) {
2662                            bits += CodeCoeffInter_CalcBits(coeff, scan_tables[0]);
2663                            cbp |= 1 << (5 - 4);
2664                    }
2665    
2666                    if (bits < *Data->iMinSAD) { // still possible
2667                            //chroma V
2668                            ptr = interpolate8x8_switch2(Data->RefQ + 64, Data->RefCV, 0, 0, sumx, sumy, Data->iEdgedWidth/2, Data->rounding);
2669                            transfer_8to16subro(in, Data->CurV, ptr, Data->iEdgedWidth/2);
2670                            fdct(in);
2671                            if (Data->lambda8 == 0) i = quant_inter(coeff, in, Data->lambda16);
2672                            else i = quant4_inter(coeff, in, Data->lambda16);
2673                            if (i > 0) {
2674                                    bits += CodeCoeffInter_CalcBits(coeff, scan_tables[0]);
2675                                    cbp |= 1 << (5 - 5);
2676                            }
2677                            bits += xvid_cbpy_tab[15-(cbp>>2)].len;
2678                            bits += mcbpc_inter_tab[(MODE_INTER4V & 7) | ((cbp & 3) << 3)].len;
2679                    }
2680            }
2681    
2682            return bits;
2683    }
2684    
2685    
2686    static int
2687    CountMBBitsIntra(const SearchData * const Data)
2688    {
2689            int bits = 1; //this one is ac/dc prediction flag. always 1.
2690            int cbp = 0, i, t, dc = 0, b_dc = 1024;
2691            const uint32_t iQuant = Data->lambda16;
2692            int16_t in[64], coeff[64];
2693    
2694            for(i = 0; i < 4; i++) {
2695                    uint32_t iDcScaler = get_dc_scaler(iQuant, 1);
2696    
2697                    int s = 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2698                    transfer_8to16copy(in, Data->Cur + s, Data->iEdgedWidth);
2699                    fdct(in);
2700                    b_dc = dc;
2701                    dc = in[0];
2702                    in[0] -= b_dc;
2703                    if (Data->lambda8 == 0) quant_intra_c(coeff, in, iQuant, iDcScaler);
2704                    else quant4_intra_c(coeff, in, iQuant, iDcScaler);
2705    
2706                    b_dc = dc;
2707                    dc = coeff[0];
2708                    if (i != 0) coeff[0] -= b_dc;
2709    
2710                    bits += t = CodeCoeffIntra_CalcBits(coeff, scan_tables[0]) + dcy_tab[coeff[0] + 255].len;;
2711                    Data->temp[i] = t;
2712                    if (t != 0)  cbp |= 1 << (5 - i);
2713                    if (bits >= Data->iMinSAD[0]) break;
2714            }
2715    
2716            if (bits < Data->iMinSAD[0]) { // INTRA still looks good, let's add chroma
2717                    uint32_t iDcScaler = get_dc_scaler(iQuant, 0);
2718                    //chroma U
2719                    transfer_8to16copy(in, Data->CurU, Data->iEdgedWidth/2);
2720                    fdct(in);
2721                    in[0] -= 1024;
2722                    if (Data->lambda8 == 0) quant_intra(coeff, in, iQuant, iDcScaler);
2723                    else quant4_intra(coeff, in, iQuant, iDcScaler);
2724    
2725                    bits += t = CodeCoeffIntra_CalcBits(coeff, scan_tables[0]) + dcc_tab[coeff[0] + 255].len;
2726                    if (t != 0) cbp |= 1 << (5 - 4);
2727    
2728                    if (bits < Data->iMinSAD[0]) {
2729                            iDcScaler = get_dc_scaler(iQuant, 1);
2730                            //chroma V
2731                            transfer_8to16copy(in, Data->CurV, Data->iEdgedWidth/2);
2732                            fdct(in);
2733                            in[0] -= 1024;
2734                            if (Data->lambda8 == 0) quant_intra(coeff, in, iQuant, iDcScaler);
2735                            else quant4_intra(coeff, in, iQuant, iDcScaler);
2736    
2737                                          break;                          bits += t = CodeCoeffIntra_CalcBits(coeff, scan_tables[0]) + dcc_tab[coeff[0] + 255].len;
2738                                  case MODE_INTERPOLATE:                          if (t != 0) cbp |= 1 << (5 - 5);
                                         i_count++;  
                                         mb->mvs[0] = f_interpolMV;  
                                         mb->b_mvs[0] = b_interpolMV;  
                                         f_predMV = mb->mvs[0];  
                                         b_predMV = mb->b_mvs[0];  
                                         break;  
                                 case MODE_DIRECT:  
                                         d_count++;  
                                         break;  
                                 default:  
                                         break;  
                         }  
2739    
2740                            bits += xvid_cbpy_tab[cbp>>2].len;
2741                            bits += mcbpc_inter_tab[(MODE_INTRA & 7) | ((cbp & 3) << 3)].len;
2742                  }                  }
2743          }          }
2744            return bits;
 #ifdef _DEBUG_BFRAME_STAT  
         fprintf(stderr,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d\n",  
                                 f_count,b_count,i_count,d_count);  
 #endif  
   
2745  }  }

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

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