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

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

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

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

Legend:
Removed from v.346  
changed lines
  Added in v.712

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