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

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

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

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

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

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