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

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

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