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

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

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

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

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

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