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

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

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

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

Legend:
Removed from v.1.44  
changed lines
  Added in v.1.44.2.51

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