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

Legend:
Removed from v.348  
changed lines
  Added in v.721

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