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

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

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

trunk/xvidcore/src/motion/motion_est.c revision 346, Sun Jul 28 02:55:41 2002 UTC branches/dev-api-3/xvidcore/src/motion/motion_est.c revision 662, Tue Nov 19 13:48:42 2002 UTC
# Line 28  Line 28 
28   *   *
29   *************************************************************************/   *************************************************************************/
30    
 /**************************************************************************  
  *  
  *  Modifications:  
  *  
  *      01.05.2002      updated MotionEstimationBVOP  
  *      25.04.2002 partial prevMB conversion  
  *  22.04.2002 remove some compile warning by chenm001 <chenm001@163.com>  
  *  14.04.2002 added MotionEstimationBVOP()  
  *  02.04.2002 add EPZS(^2) as ME algorithm, use PMV_USESQUARES to choose between  
  *             EPZS and EPZS^2  
  *  08.02.2002 split up PMVfast into three routines: PMVFast, PMVFast_MainLoop  
  *             PMVFast_Refine to support multiple searches with different start points  
  *  07.01.2002 uv-block-based interpolation  
  *  06.01.2002 INTER/INTRA-decision is now done before any SEARCH8 (speedup)  
  *             changed INTER_BIAS to 150 (as suggested by suxen_drol)  
  *             removed halfpel refinement step in PMVfastSearch8 + quality=5  
  *             added new quality mode = 6 which performs halfpel refinement  
  *             filesize difference between quality 5 and 6 is smaller than 1%  
  *             (Isibaar)  
  *  31.12.2001 PMVfastSearch16 and PMVfastSearch8 (gruel)  
  *  30.12.2001 get_range/MotionSearchX simplified; blue/green bug fix  
  *  22.12.2001 commented best_point==99 check  
  *  19.12.2001 modified get_range (purple bug fix)  
  *  15.12.2001 moved pmv displacement from mbprediction  
  *  02.12.2001 motion estimation/compensation split (Isibaar)  
  *  16.11.2001 rewrote/tweaked search algorithms; pross@cs.rmit.edu.au  
  *  10.11.2001 support for sad16/sad8 functions  
  *  28.08.2001 reactivated MODE_INTER4V for EXT_MODE  
  *  24.08.2001 removed MODE_INTER4V_Q, disabled MODE_INTER4V for EXT_MODE  
  *  22.08.2001 added MODE_INTER4V_Q  
  *  20.08.2001 added pragma to get rid of internal compiler error with VC6  
  *             idea by Cyril. Thanks.  
  *  
  *  Michael Militzer <isibaar@videocoding.de>  
  *  
  **************************************************************************/  
   
31  #include <assert.h>  #include <assert.h>
32  #include <stdio.h>  #include <stdio.h>
33  #include <stdlib.h>  #include <stdlib.h>
# Line 74  Line 37 
37  #include "../prediction/mbprediction.h"  #include "../prediction/mbprediction.h"
38  #include "../global.h"  #include "../global.h"
39  #include "../utils/timer.h"  #include "../utils/timer.h"
40    #include "../image/interpolate8x8.h"
41    #include "motion_est.h"
42  #include "motion.h"  #include "motion.h"
43  #include "sad.h"  #include "sad.h"
44    #include "../utils/emms.h"
45    
46    #define INITIAL_SKIP_THRESH     (10)
47    #define FINAL_SKIP_THRESH       (50)
48    #define MAX_SAD00_FOR_SKIP      (20)
49    #define MAX_CHROMA_SAD_FOR_SKIP (22)
50    #define SKIP_THRESH_B (25)
51    
52    #define CHECK_CANDIDATE(X,Y,D) { \
53    (*CheckCandidate)((const int)(X),(const int)(Y), (D), &iDirection, data ); }
54    
55  static int32_t lambda_vec16[32] =       /* rounded values for lambda param for weight of motion bits as in modified H.26L */  #define GET_REFERENCE(X, Y, REF) { \
56  { 0, (int) (1.00235 + 0.5), (int) (1.15582 + 0.5), (int) (1.31976 + 0.5),          switch ( (((X)&1)<<1) + ((Y)&1) ) \
57                  (int) (1.49591 + 0.5), (int) (1.68601 + 0.5),          { \
58          (int) (1.89187 + 0.5), (int) (2.11542 + 0.5), (int) (2.35878 + 0.5),                  case 0 : REF = (uint8_t *)data->Ref + (X)/2 + ((Y)/2)*(data->iEdgedWidth); break; \
59                  (int) (2.62429 + 0.5), (int) (2.91455 + 0.5),                  case 1 : REF = (uint8_t *)data->RefV + (X)/2 + (((Y)-1)/2)*(data->iEdgedWidth); break; \
60          (int) (3.23253 + 0.5), (int) (3.58158 + 0.5), (int) (3.96555 + 0.5),                  case 2 : REF = (uint8_t *)data->RefH + ((X)-1)/2 + ((Y)/2)*(data->iEdgedWidth); break; \
61                  (int) (4.38887 + 0.5), (int) (4.85673 + 0.5),                  default : REF = (uint8_t *)data->RefHV + ((X)-1)/2 + (((Y)-1)/2)*(data->iEdgedWidth); break; \
62          (int) (5.37519 + 0.5), (int) (5.95144 + 0.5), (int) (6.59408 + 0.5),          } \
63                  (int) (7.31349 + 0.5), (int) (8.12242 + 0.5),  }
64          (int) (9.03669 + 0.5), (int) (10.0763 + 0.5), (int) (11.2669 + 0.5),  // I hate those macros :/
65                  (int) (12.6426 + 0.5), (int) (14.2493 + 0.5),  #define GET_REFERENCE2(X, Y, REF) { \
66          (int) (16.1512 + 0.5), (int) (18.442 + 0.5), (int) (21.2656 + 0.5),          switch ( (((X)&1)<<1) + ((Y)&1) ) \
67                  (int) (24.8580 + 0.5), (int) (29.6436 + 0.5),          { \
68          (int) (36.4949 + 0.5)                  case 0 : REF = (uint8_t *)data->bRef + (X)/2 + ((Y)/2)*(data->iEdgedWidth); break; \
69  };                  case 1 : REF = (uint8_t *)data->bRefV + (X)/2 + (((Y)-1)/2)*(data->iEdgedWidth); break; \
70                    case 2 : REF = (uint8_t *)data->bRefH + ((X)-1)/2 + ((Y)/2)*(data->iEdgedWidth); break; \
71  static int32_t *lambda_vec8 = lambda_vec16;     /* same table for INTER and INTER4V for now */                  default : REF = (uint8_t *)data->bRefHV + ((X)-1)/2 + (((Y)-1)/2)*(data->iEdgedWidth); break; \
72            } \
73    }
74    
75    
76    #define iDiamondSize 2
77    
78  // mv.length table  static __inline int
79  static const uint32_t mvtab[33] = {  d_mv_bits(int x, int y, const uint32_t iFcode)
         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  
 };  
   
   
 static __inline uint32_t  
 mv_bits(int32_t component,  
                 const uint32_t iFcode)  
80  {  {
81          if (component == 0)          int xb, yb;
82                  return 1;  
83            if (x == 0) xb = 1;
84            else {
85                    if (x < 0) x = -x;
86                    x += (1 << (iFcode - 1)) - 1;
87                    x >>= (iFcode - 1);
88                    if (x > 32) x = 32;
89                    xb = mvtab[x] + iFcode;
90            }
91    
92            if (y == 0) yb = 1;
93            else {
94                    if (y < 0) y = -y;
95                    y += (1 << (iFcode - 1)) - 1;
96                    y >>= (iFcode - 1);
97                    if (y > 32) y = 32;
98                    yb = mvtab[y] + iFcode;
99            }
100            return xb + yb;
101    }
102    
103    static int32_t
104    ChromaSAD(int dx, int dy, const SearchData * const data)
105    {
106            int sad;
107            dx = (dx >> 1) + roundtab_79[dx & 0x3];
108            dy = (dy >> 1) + roundtab_79[dy & 0x3];
109    
110            switch (((dx & 1) << 1) + (dy & 1))     { // ((dx%2)?2:0)+((dy%2)?1:0)
111                    case 0:
112                            sad = sad8(data->CurU, data->RefCU + (dy/2) * (data->iEdgedWidth/2) + dx/2, data->iEdgedWidth/2);
113                            sad += sad8(data->CurV, data->RefCV + (dy/2) * (data->iEdgedWidth/2) + dx/2, data->iEdgedWidth/2);
114                            break;
115                    case 1:
116                            dx = dx / 2; dy = (dy - 1) / 2;
117                            sad = sad8bi(data->CurU, data->RefCU + dy * (data->iEdgedWidth/2) + dx, data->RefCU + (dy+1) * (data->iEdgedWidth/2) + dx, data->iEdgedWidth/2);
118                            sad += sad8bi(data->CurV, data->RefCV + dy * (data->iEdgedWidth/2) + dx, data->RefCV + (dy+1) * (data->iEdgedWidth/2) + dx, data->iEdgedWidth/2);
119                            break;
120                    case 2:
121                            dx = (dx - 1) / 2; dy = dy / 2;
122                            sad = sad8bi(data->CurU, data->RefCU + dy * (data->iEdgedWidth/2) + dx, data->RefCU + dy * (data->iEdgedWidth/2) + dx+1, data->iEdgedWidth/2);
123                            sad += sad8bi(data->CurV, data->RefCV + dy * (data->iEdgedWidth/2) + dx, data->RefCV + dy * (data->iEdgedWidth/2) + dx+1, data->iEdgedWidth/2);
124                            break;
125                    default:
126                            dx = (dx - 1) / 2; dy = (dy - 1) / 2;
127                            interpolate8x8_halfpel_hv(data->RefQ,
128                                                                             data->RefCU + dy * (data->iEdgedWidth/2) + dx, data->iEdgedWidth/2,
129                                                                             data->rounding);
130                            sad = sad8(data->CurU, data->RefQ, data->iEdgedWidth/2);
131                            interpolate8x8_halfpel_hv(data->RefQ,
132                                                                             data->RefCV + dy * (data->iEdgedWidth/2) + dx, data->iEdgedWidth/2,
133                                                                             data->rounding);
134                            sad += sad8(data->CurV, data->RefQ, data->iEdgedWidth/2);
135                            break;
136            }
137            return sad;
138    }
139    
140    
141    /* CHECK_CANDIATE FUNCTIONS START */
142    
         if (component < 0)  
                 component = -component;  
143    
144          if (iFcode == 1) {  static void
145                  if (component > 32)  CheckCandidate16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
146                          component = 32;  {
147            int t;
148            const uint8_t * Reference;
149    
150            if (( x > data->max_dx) || ( x < data->min_dx)
151                    || ( y > data->max_dy) || (y < data->min_dy)) return;
152    
153                  return mvtab[component] + 1;          switch ( ((x&1)<<1) + (y&1) ) {
154                    case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
155                    case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;
156                    case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;
157                    default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
158          }          }
159    
160          component += (1 << (iFcode - 1)) - 1;          data->temp[0] = sad16v(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
161          component >>= (iFcode - 1);  
162            if (data->qpel) t = d_mv_bits(2*x - data->predQMV.x, 2*y - data->predQMV.y, data->iFcode);
163            else t = d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
164    
165            data->temp[0] += (data->lambda16 * t * data->temp[0])/1000;
166            data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))/100;
167    
168          if (component > 32)          if (data->chroma) data->temp[0] += ChromaSAD(x, y, data);
169                  component = 32;  
170            if (data->temp[0] < data->iMinSAD[0]) {
171                    data->iMinSAD[0] = data->temp[0];
172                    data->currentMV[0].x = x; data->currentMV[0].y = y;
173                    *dir = Direction; }
174    
175            if (data->temp[1] < data->iMinSAD[1]) {
176                    data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
177            if (data->temp[2] < data->iMinSAD[2]) {
178                    data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
179            if (data->temp[3] < data->iMinSAD[3]) {
180                    data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
181            if (data->temp[4] < data->iMinSAD[4]) {
182                    data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
183    
         return mvtab[component] + 1 + iFcode - 1;  
184  }  }
185    
186    static void
187    CheckCandidate16no4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
188    {
189            int32_t sad;
190            const uint8_t * Reference;
191    
192  static __inline uint32_t          if (( x > data->max_dx) || ( x < data->min_dx)
193  calc_delta_16(const int32_t dx,                  || ( y > data->max_dy) || (y < data->min_dy)) return;
194                            const int32_t dy,  
195                            const uint32_t iFcode,          switch ( ((x&1)<<1) + (y&1) )
                           const uint32_t iQuant)  
196  {  {
197          return NEIGH_TEND_16X16 * lambda_vec16[iQuant] * (mv_bits(dx, iFcode) +                  case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
198                                                                                                            mv_bits(dy, iFcode));                  case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;
199                    case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;
200                    default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
201  }  }
202    
203  static __inline uint32_t          sad = sad16(data->Cur, Reference, data->iEdgedWidth, MV_MAX_ERROR);
204  calc_delta_8(const int32_t dx,          if (data->qpel) //only to be used in b-frames' ME
205                           const int32_t dy,                  sad += (data->lambda16 * d_mv_bits(2*x - data->predMV.x, 2*y - data->predMV.y, data->iFcode) * sad)/1000;
206                           const uint32_t iFcode,          else
207                           const uint32_t iQuant)                  sad += (data->lambda16 * d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode) * sad)/1000;
208  {  
209          return NEIGH_TEND_8X8 * lambda_vec8[iQuant] * (mv_bits(dx, iFcode) +          if (sad < *(data->iMinSAD)) {
210                                                                                                     mv_bits(dy, iFcode));                  *(data->iMinSAD) = sad;
211                    data->currentMV[0].x = x; data->currentMV[0].y = y;
212                    *dir = Direction; }
213  }  }
214    
215  bool  static void
216  MotionEstimation(MBParam * const pParam,  CheckCandidate16_qpel(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
217                                   FRAMEINFO * const current,  
218                                   FRAMEINFO * const reference,  // CheckCandidate16 variant which expects x and y in quarter pixel resolution
219                                   const IMAGE * const pRefH,  // Important: This is no general usable routine! x and y must be +/-1 (qpel resolution!)
220                                   const IMAGE * const pRefV,  // around currentMV!
                                  const IMAGE * const pRefHV,  
                                  const uint32_t iLimit)  
221  {  {
222          const uint32_t iWcount = pParam->mb_width;          int t;
223          const uint32_t iHcount = pParam->mb_height;          uint8_t * Reference = (uint8_t *)data->RefQ;
224          MACROBLOCK *const pMBs = current->mbs;          const uint8_t *ref1, *ref2, *ref3, *ref4;
225          MACROBLOCK *const prevMBs = reference->mbs;          VECTOR halfpelMV = *(data->currentMV);
         const IMAGE *const pCurrent = &current->image;  
         const IMAGE *const pRef = &reference->image;  
226    
227          static const VECTOR zeroMV = { 0, 0 };          int32_t iEdgedWidth = data->iEdgedWidth;
228          VECTOR predMV;          uint32_t rounding = data->rounding;
229    
230          int32_t x, y;          if (( x > data->max_dx) || ( x < data->min_dx)
231          int32_t iIntra = 0;                  || ( y > data->max_dy) || (y < data->min_dy)) return;
         VECTOR pmv;  
232    
233          if (sadInit)          GET_REFERENCE(halfpelMV.x, halfpelMV.y, ref1); // this refenrence is used in all cases
234                  (*sadInit) ();          switch( ((x&1)<<1) + (y&1) )
235            {
236            case 0: // pure halfpel position - shouldn't happen during a refinement step
237                    GET_REFERENCE(halfpelMV.x, halfpelMV.y, Reference);
238                    break;
239    
240          for (y = 0; y < iHcount; y++)   {          case 1: // x halfpel, y qpel - top or bottom during qpel refinement
241                  for (x = 0; x < iWcount; x ++)  {                  GET_REFERENCE(halfpelMV.x, y - halfpelMV.y, ref2);
242                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding);
243                    interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding);
244                    interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding);
245                    interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding);
246                    break;
247    
248                          MACROBLOCK *const pMB = &pMBs[x + y * iWcount];          case 2: // x qpel, y halfpel - left or right during qpel refinement
249                    GET_REFERENCE(x - halfpelMV.x, halfpelMV.y, ref2);
250                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding);
251                    interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding);
252                    interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding);
253                    interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding);
254                    break;
255    
256                          predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          default: // x and y in qpel resolution - the "corners" (top left/right and
257                             // bottom left/right) during qpel refinement
258                    GET_REFERENCE(halfpelMV.x, y - halfpelMV.y, ref2);
259                    GET_REFERENCE(x - halfpelMV.x, halfpelMV.y, ref3);
260                    GET_REFERENCE(x - halfpelMV.x, y - halfpelMV.y, ref4);
261    
262                          pMB->sad16 =                  interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
263                                  SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,                  interpolate8x8_avg4(Reference+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, rounding);
264                                                   x, y, predMV.x, predMV.y, predMV.x, predMV.y,                  interpolate8x8_avg4(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, rounding);
265                                                   current->motion_flags, current->quant,                  interpolate8x8_avg4(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, rounding);
266                                                   current->fcode, pParam, pMBs, prevMBs, &pMB->mv16,                  break;
267                                                   &pMB->pmvs[0]);          }
268    
269                          if (0 < (pMB->sad16 - MV16_INTER_BIAS)) {          data->temp[0] = sad16v(data->Cur, Reference, data->iEdgedWidth, data->temp+1);
                                 int32_t deviation;  
270    
271                                  deviation =          t = d_mv_bits(x - data->predQMV.x, y - data->predQMV.y, data->iFcode);
272                                          dev16(pCurrent->y + x * 16 + y * 16 * pParam->edged_width,          data->temp[0] += (data->lambda16 * t * data->temp[0])/1000;
273                                                    pParam->edged_width);          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))/100;
274    
275                                  if (deviation < (pMB->sad16 - MV16_INTER_BIAS)) {          if (data->chroma)
276                                          pMB->mode = MODE_INTRA;                  data->temp[0] += ChromaSAD(x/2, y/2, data);
                                         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;  
277    
278                                          iIntra++;          if (data->temp[0] < data->iMinSAD[0]) {
279                                          if (iIntra >= iLimit)                  data->iMinSAD[0] = data->temp[0];
280                                                  return 1;                  data->currentQMV[0].x = x; data->currentQMV[0].y = y;
281            /*      *dir = Direction;*/ }
282    
283                                          continue;          if (data->temp[1] < data->iMinSAD[1]) {
284                                  }                  data->iMinSAD[1] = data->temp[1]; data->currentQMV[1].x = x; data->currentQMV[1].y = y; }
285            if (data->temp[2] < data->iMinSAD[2]) {
286                    data->iMinSAD[2] = data->temp[2]; data->currentQMV[2].x = x; data->currentQMV[2].y = y; }
287            if (data->temp[3] < data->iMinSAD[3]) {
288                    data->iMinSAD[3] = data->temp[3]; data->currentQMV[3].x = x; data->currentQMV[3].y = y; }
289            if (data->temp[4] < data->iMinSAD[4]) {
290                    data->iMinSAD[4] = data->temp[4]; data->currentQMV[4].x = x; data->currentQMV[4].y = y; }
291                          }                          }
292    
293                          pmv = pMB->pmvs[0];  static void
294                          if (current->global_flags & XVID_INTER4V)  CheckCandidate16no4v_qpel(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                                 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  
                                          */  
295    
296                                          if (sad8 < pMB->sad16) {  // CheckCandidate16no4v variant which expects x and y in quarter pixel resolution
297                                                  pMB->mode = MODE_INTER4V;  // Important: This is no general usable routine! x and y must be +/-1 (qpel resolution!)
298                                                  pMB->sad8[0] *= 4;  // around currentMV!
299                                                  pMB->sad8[1] *= 4;  // this function is for B-frames' search only
300                                                  pMB->sad8[2] *= 4;  {
301                                                  pMB->sad8[3] *= 4;          uint8_t * Reference = (uint8_t *)data->RefQ;
302                                                  continue;          const uint8_t *ref1, *ref2, *ref3, *ref4;
303                                          }          VECTOR halfpelMV = *(data->currentMV);
304    
305                                  }          int32_t iEdgedWidth = data->iEdgedWidth;
306            int32_t sad;
307    
308                          pMB->mode = MODE_INTER;          if (( x > data->max_dx) || ( x < data->min_dx)
309                          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;  
                         }  
                         }  
310    
311          return 0;          GET_REFERENCE(halfpelMV.x, halfpelMV.y, ref1); // this refenrence is used in all cases
312  }          switch( ((x&1)<<1) + (y&1) )
313            {
314            case 0: // pure halfpel position - shouldn't happen during a refinement step
315                    GET_REFERENCE(halfpelMV.x, halfpelMV.y, Reference);
316                    break;
317    
318            case 1: // x halfpel, y qpel - top or bottom during qpel refinement
319                    GET_REFERENCE(halfpelMV.x, y - halfpelMV.y, ref2);
320                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, 0);
321                    interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, 0);
322                    interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, 0);
323                    interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, 0);
324                    break;
325    
326  #define CHECK_MV16_ZERO {\          case 2: // x qpel, y halfpel - left or right during qpel refinement
327    if ( (0 <= max_dx) && (0 >= min_dx) \                  GET_REFERENCE(x - halfpelMV.x, halfpelMV.y, ref2);
328      && (0 <= max_dy) && (0 >= min_dy) ) \                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, 0);
329    { \                  interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, 0);
330      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \                  interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, 0);
331      iSAD += calc_delta_16(-center_x, -center_y, (uint8_t)iFcode, iQuant);\                  interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, 0);
332      if (iSAD < iMinSAD) \                  break;
     {  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); } } \  
 }  
333    
334  #define CHECK_MV16_CANDIDATE_DIR(X,Y,D) { \          default: // x and y in qpel resolution - the "corners" (top left/right and
335    if ( ((X) <= max_dx) && ((X) >= min_dx) \                           // bottom left/right) during qpel refinement
336      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \                  GET_REFERENCE(halfpelMV.x, y - halfpelMV.y, ref2);
337    { \                  GET_REFERENCE(x - halfpelMV.x, halfpelMV.y, ref3);
338      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \                  GET_REFERENCE(x - halfpelMV.x, y - halfpelMV.y, ref4);
     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); } } \  
 }  
339    
340  #define CHECK_MV16_CANDIDATE_FOUND(X,Y,D) { \                  interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, 0);
341    if ( ((X) <= max_dx) && ((X) >= min_dx) \                  interpolate8x8_avg4(Reference+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, 0);
342      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \                  interpolate8x8_avg4(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, 0);
343    { \                  interpolate8x8_avg4(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, 0);
344      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \                  break;
     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; } } \  
345  }  }
346    
347            sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
348            sad += (data->lambda16 * d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode) * sad)/1000;
349    
350  #define CHECK_MV8_ZERO {\          if (sad < data->iMinSAD[0]) {
351    iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, 0, 0 , iEdgedWidth), iEdgedWidth); \                  data->iMinSAD[0] = sad;
352    iSAD += calc_delta_8(-center_x, -center_y, (uint8_t)iFcode, iQuant);\                  data->currentQMV[0].x = x; data->currentQMV[0].y = y;
353    if (iSAD < iMinSAD) \          /*      *dir = Direction;*/ }
   { iMinSAD=iSAD; currMV->x=0; currMV->y=0; } \  
354  }  }
355    
356  #define NOCHECK_MV8_CANDIDATE(X,Y) \  static void
357    { \  CheckCandidate16no4vI(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
358      iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  {
359      iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  // maximum speed - for P/B/I decision
360      if (iSAD < iMinSAD) \          int32_t sad;
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \  
 }  
361    
362  #define CHECK_MV8_CANDIDATE(X,Y) { \          if (( x > data->max_dx) || ( x < data->min_dx)
363    if ( ((X) <= max_dx) && ((X) >= min_dx) \                  || ( y > data->max_dy) || (y < data->min_dy)) return;
     && ((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); } } \  
 }  
364    
365  #define CHECK_MV8_CANDIDATE_DIR(X,Y,D) { \          sad = sad16(data->Cur, data->Ref + x/2 + (y/2)*(data->iEdgedWidth),
366    if ( ((X) <= max_dx) && ((X) >= min_dx) \                                          data->iEdgedWidth, 256*4096);
     && ((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); } } \  
 }  
367    
368  #define CHECK_MV8_CANDIDATE_FOUND(X,Y,D) { \          if (sad < *(data->iMinSAD)) {
369    if ( ((X) <= max_dx) && ((X) >= min_dx) \                  *(data->iMinSAD) = sad;
370      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \                  data->currentMV[0].x = x; data->currentMV[0].y = y;
371    { \                  *dir = Direction; }
     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; } } \  
372  }  }
373    
374  /* too slow and not fully functional at the moment */  
375  /*  static void
376  int32_t ZeroSearch16(  CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)
                                         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)  
377  {  {
378          const int32_t iEdgedWidth = pParam->edged_width;          int32_t sad;
379          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;          const int xb = data->currentMV[1].x;
380          int32_t iSAD;          const int yb = data->currentMV[1].y;
381          VECTOR pred;          const uint8_t *ReferenceF, *ReferenceB;
382    
383            if (( xf > data->max_dx) || ( xf < data->min_dx)
384                    || ( yf > data->max_dy) || (yf < data->min_dy)) return;
385    
386          pred = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          switch ( ((xf&1)<<1) + (yf&1) ) {
387                    case 0 : ReferenceF = data->Ref + xf/2 + (yf/2)*(data->iEdgedWidth); break;
388                    case 1 : ReferenceF = data->RefV + xf/2 + ((yf-1)/2)*(data->iEdgedWidth); break;
389                    case 2 : ReferenceF = data->RefH + (xf-1)/2 + (yf/2)*(data->iEdgedWidth); break;
390                    default : ReferenceF = data->RefHV + (xf-1)/2 + ((yf-1)/2)*(data->iEdgedWidth); break;
391            }
392    
393          iSAD = sad16( cur,          switch ( ((xb&1)<<1) + (yb&1) ) {
394                  get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth),                  case 0 : ReferenceB = data->bRef + xb/2 + (yb/2)*(data->iEdgedWidth); break;
395                  iEdgedWidth, MV_MAX_ERROR);                  case 1 : ReferenceB = data->bRefV + xb/2 + ((yb-1)/2)*(data->iEdgedWidth); break;
396          if (iSAD <= iQuant * 96)                  case 2 : ReferenceB = data->bRefH + (xb-1)/2 + (yb/2)*(data->iEdgedWidth); break;
397                  iSAD -= MV16_00_BIAS;                  default : ReferenceB = data->bRefHV + (xb-1)/2 + ((yb-1)/2)*(data->iEdgedWidth); break;
398            }
399    
400          currMV->x = 0;          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
         currMV->y = 0;  
         currPMV->x = -pred.x;  
         currPMV->y = -pred.y;  
401    
402          return iSAD;          if (data->qpel)
403                    sad += (data->lambda16 *
404                            ( d_mv_bits(2*xf - data->predMV.x, 2*yf - data->predMV.y, data->iFcode) +
405                              d_mv_bits(2*xb - data->bpredMV.x, 2*yb - data->bpredMV.y, data->iFcode)) * sad)/1000;
406            else
407                    sad += (data->lambda16 *
408                            ( d_mv_bits(xf - data->predMV.x, yf - data->predMV.y, data->iFcode) +
409                              d_mv_bits(xb - data->bpredMV.x, yb - data->bpredMV.y, data->iFcode)) * sad)/1000;
410    
411            if (sad < *(data->iMinSAD)) {
412                    *(data->iMinSAD) = sad;
413                    data->currentMV->x = xf; data->currentMV->y = yf;
414                    *dir = Direction; }
415  }  }
 */  
   
 int32_t  
 Diamond16_MainSearch(const uint8_t * const pRef,  
                                          const uint8_t * const pRefH,  
                                          const uint8_t * const pRefV,  
                                          const uint8_t * const pRefHV,  
                                          const uint8_t * const cur,  
                                          const int x,  
                                          const int y,  
                                    const int start_x,  
                                    const int start_y,  
                                    int iMinSAD,  
                                    VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                          const int32_t min_dx,  
                                          const int32_t max_dx,  
                                          const int32_t min_dy,  
                                          const int32_t max_dy,  
                                          const int32_t iEdgedWidth,  
                                          const int32_t iDiamondSize,  
                                          const int32_t iFcode,  
                                          const int32_t iQuant,  
                                          int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iDirectionBackup;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
416    
         if (iDirection) {  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;  
                         iDirectionBackup = iDirection;  
   
                         if (iDirectionBackup != 2)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                    backupMV.y, 1);  
                         if (iDirectionBackup != 1)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                    backupMV.y, 2);  
                         if (iDirectionBackup != 4)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,  
                                                                                    backupMV.y - iDiamondSize, 3);  
                         if (iDirectionBackup != 3)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,  
                                                                                    backupMV.y + iDiamondSize, 4);  
                 }  
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
         }  
         return iMinSAD;  
 }  
417    
418  int32_t  static void
419  Square16_MainSearch(const uint8_t * const pRef,  CheckCandidateInt_qpel(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)
420                                          const uint8_t * const pRefH,  {
421                                          const uint8_t * const pRefV,  // CheckCandidateInt variant which expects x and y in quarter pixel resolution
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x,  
                                         const int y,  
                                    const int start_x,  
                                    const int start_y,  
                                    int iMinSAD,  
                                    VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a square search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* It's one search with full square pattern, and new parts for all following diamonds */  
   
 /*   new direction are extra, so 1-4 is normal diamond  
       537  
       1*2  
       648  
 */  
   
         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);  
422    
423            int32_t sad;
424            const int xb = data->currentQMV[1].x;
425            const int yb = data->currentQMV[1].y;
426            uint8_t * ReferenceF = (uint8_t *)data->RefQ;
427            uint8_t * ReferenceB = (uint8_t *)data->RefQ + 16;
428            const uint8_t *ref1, *ref2, *ref3, *ref4;
429            VECTOR halfpelMV;
430            const int32_t iEdgedWidth = data->iEdgedWidth;
431    
432          if (iDirection) {          if (( xf > data->max_dx) || ( xf < data->min_dx)
433                  while (!iFound) {                  || ( yf > data->max_dy) || (yf < data->min_dy)) return;
                         iFound = 1;  
                         backupMV = *currMV;  
434    
435                          switch (iDirection) {          halfpelMV.x = xf/2; //forward first
436                          case 1:          halfpelMV.y = yf/2;
437                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          GET_REFERENCE(halfpelMV.x, halfpelMV.y, ref1); // this reference is used in all cases
438                                                                                     backupMV.y, 1);          switch( ((xf&1)<<1) + (yf&1) )
439                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          {
440                                                                                   backupMV.y - iDiamondSize, 5);          case 0: // pure halfpel position - shouldn't happen during a refinement step
441                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                  GET_REFERENCE(halfpelMV.x, halfpelMV.y, ReferenceF);
                                                                                  backupMV.y - iDiamondSize, 7);  
442                                  break;                                  break;
443                          case 2:  
444                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,          case 1: // x halfpel, y qpel - top or bottom during qpel refinement
445                                                                                   2);                  GET_REFERENCE(halfpelMV.x, yf - halfpelMV.y, ref2);
446                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  interpolate8x8_avg2(ReferenceF, ref1, ref2, iEdgedWidth, 0);
447                                                                                   backupMV.y + iDiamondSize, 6);                  interpolate8x8_avg2(ReferenceF+8, ref1+8, ref2+8, iEdgedWidth, 0);
448                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                  interpolate8x8_avg2(ReferenceF+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, 0);
449                                                                                   backupMV.y + iDiamondSize, 8);                  interpolate8x8_avg2(ReferenceF+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, 0);
450                                  break;                                  break;
451    
452                          case 3:          case 2: // x qpel, y halfpel - left or right during qpel refinement
453                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                  GET_REFERENCE(xf - halfpelMV.x, halfpelMV.y, ref2);
454                                                                                   4);                  interpolate8x8_avg2(ReferenceF, ref1, ref2, iEdgedWidth, 0);
455                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                  interpolate8x8_avg2(ReferenceF+8, ref1+8, ref2+8, iEdgedWidth, 0);
456                                                                                   backupMV.y - iDiamondSize, 7);                  interpolate8x8_avg2(ReferenceF+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, 0);
457                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                  interpolate8x8_avg2(ReferenceF+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, 0);
                                                                                  backupMV.y + iDiamondSize, 8);  
458                                  break;                                  break;
459    
460                          case 4:          default: // x and y in qpel resolution - the "corners" (top left/right and
461                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,                           // bottom left/right) during qpel refinement
462                                                                                   3);                  GET_REFERENCE(halfpelMV.x, yf - halfpelMV.y, ref2);
463                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  GET_REFERENCE(xf - halfpelMV.x, halfpelMV.y, ref3);
464                                                                                   backupMV.y - iDiamondSize, 5);                  GET_REFERENCE(xf - halfpelMV.x, yf - halfpelMV.y, ref4);
                                 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);  
465    
466                    interpolate8x8_avg4(ReferenceF, ref1, ref2, ref3, ref4, iEdgedWidth, 0);
467                    interpolate8x8_avg4(ReferenceF+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, 0);
468                    interpolate8x8_avg4(ReferenceF+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, 0);
469                    interpolate8x8_avg4(ReferenceF+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, 0);
470                                  break;                                  break;
471            }
472    
473                          case 7:          halfpelMV.x = xb/2; //backward
474                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          halfpelMV.y = yb/2;
475                                                                                     backupMV.y, 1);          GET_REFERENCE2(halfpelMV.x, halfpelMV.y, ref1); // this reference is used in all cases
476                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,          switch( ((xb&1)<<1) + (yb&1) )
477                                                                                   4);          {
478                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          case 0: // pure halfpel position - shouldn't happen during a refinement step
479                                                                                   backupMV.y - iDiamondSize, 5);                  GET_REFERENCE2(halfpelMV.x, halfpelMV.y, ReferenceB);
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
480                                  break;                                  break;
481    
482                          case 8:          case 1: // x halfpel, y qpel - top or bottom during qpel refinement
483                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,                  GET_REFERENCE2(halfpelMV.x, yb - halfpelMV.y, ref2);
484                                                                                   2);                  interpolate8x8_avg2(ReferenceB, ref1, ref2, iEdgedWidth, 0);
485                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                  interpolate8x8_avg2(ReferenceB+8, ref1+8, ref2+8, iEdgedWidth, 0);
486                                                                                   4);                  interpolate8x8_avg2(ReferenceB+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, 0);
487                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  interpolate8x8_avg2(ReferenceB+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, 0);
                                                                                  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);  
488                                  break;                                  break;
489                          default:  
490                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,          case 2: // x qpel, y halfpel - left or right during qpel refinement
491                                                                                   1);                  GET_REFERENCE2(xb - halfpelMV.x, halfpelMV.y, ref2);
492                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,                  interpolate8x8_avg2(ReferenceB, ref1, ref2, iEdgedWidth, 0);
493                                                                                   2);                  interpolate8x8_avg2(ReferenceB+8, ref1+8, ref2+8, iEdgedWidth, 0);
494                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,                  interpolate8x8_avg2(ReferenceB+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, 0);
495                                                                                   3);                  interpolate8x8_avg2(ReferenceB+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, 0);
496                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                  break;
497                                                                                   4);  
498            default: // x and y in qpel resolution - the "corners" (top left/right and
499                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                           // bottom left/right) during qpel refinement
500                                                                                   backupMV.y - iDiamondSize, 5);                  GET_REFERENCE2(halfpelMV.x, yb - halfpelMV.y, ref2);
501                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  GET_REFERENCE2(xb - halfpelMV.x, halfpelMV.y, ref3);
502                                                                                   backupMV.y + iDiamondSize, 6);                  GET_REFERENCE2(xb - halfpelMV.x, yb - halfpelMV.y, ref4);
503                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
504                                                                                   backupMV.y - iDiamondSize, 7);                  interpolate8x8_avg4(ReferenceB, ref1, ref2, ref3, ref4, iEdgedWidth, 0);
505                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                  interpolate8x8_avg4(ReferenceB+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, 0);
506                                                                                   backupMV.y + iDiamondSize, 8);                  interpolate8x8_avg4(ReferenceB+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, 0);
507                    interpolate8x8_avg4(ReferenceB+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, 0);
508                                  break;                                  break;
                         }  
                 }  
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
         }  
         return iMinSAD;  
509  }  }
510    
511            sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
512    
513  int32_t          sad += (data->lambda16 *
514  Full16_MainSearch(const uint8_t * const pRef,                          ( d_mv_bits(xf - data->predMV.x, yf - data->predMV.y, data->iFcode) +
515                                    const uint8_t * const pRefH,                            d_mv_bits(xb - data->bpredMV.x, yb - data->bpredMV.y, data->iFcode)) * sad)/1000;
                                   const uint8_t * const pRefV,  
                                   const uint8_t * const pRefHV,  
                                   const uint8_t * const cur,  
                                   const int x,  
                                   const int y,  
                                    const int start_x,  
                                    const int start_y,  
                                    int iMinSAD,  
                                    VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                   const int32_t min_dx,  
                                   const int32_t max_dx,  
                                   const int32_t min_dy,  
                                   const int32_t max_dy,  
                                   const int32_t iEdgedWidth,  
                                   const int32_t iDiamondSize,  
                                   const int32_t iFcode,  
                                   const int32_t iQuant,  
                                   int iFound)  
 {  
         int32_t iSAD;  
         int32_t dx, dy;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV16_CANDIDATE(dx, dy);  
516    
517          return iMinSAD;          if (sad < *(data->iMinSAD)) {
518                    *(data->iMinSAD) = sad;
519                    data->currentQMV->x = xf; data->currentQMV->y = yf;
520                    *dir = Direction; }
521  }  }
522    
523  int32_t  static void
524  AdvDiamond16_MainSearch(const uint8_t * const pRef,  CheckCandidateDirect(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                                                 const uint8_t * const pRefH,  
                                                 const uint8_t * const pRefV,  
                                                 const uint8_t * const pRefHV,  
                                                 const uint8_t * const cur,  
                                                 const int x,  
                                                 const int y,  
                                            int start_x,  
                                            int start_y,  
                                            int iMinSAD,  
                                            VECTOR * const currMV,  
                                            const int center_x,  
                                            const int center_y,  
                                                 const int32_t min_dx,  
                                                 const int32_t max_dx,  
                                                 const int32_t min_dy,  
                                                 const int32_t max_dy,  
                                                 const int32_t iEdgedWidth,  
                                                 const int32_t iDiamondSize,  
                                                 const int32_t iFcode,  
                                                 const int32_t iQuant,  
                                                 int iDirection)  
525  {  {
526            int32_t sad = 0;
527            int k;
528            const uint8_t *ReferenceF;
529            const uint8_t *ReferenceB;
530            VECTOR mvs, b_mvs;
531    
532          int32_t iSAD;          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
533    
534  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */          for (k = 0; k < 4; k++) {
535                    mvs.x = data->directmvF[k].x + x;
536                    b_mvs.x = ((x == 0) ?
537                            data->directmvB[k].x
538                            : mvs.x - data->referencemv[k].x);
539    
540          if (iDirection) {                  mvs.y = data->directmvF[k].y + y;
541                  CHECK_MV16_CANDIDATE(start_x - iDiamondSize, start_y);                  b_mvs.y = ((y == 0) ?
542                  CHECK_MV16_CANDIDATE(start_x + iDiamondSize, start_y);                          data->directmvB[k].y
543                  CHECK_MV16_CANDIDATE(start_x, start_y - iDiamondSize);                          : mvs.y - data->referencemv[k].y);
                 CHECK_MV16_CANDIDATE(start_x, start_y + iDiamondSize);  
         } else {  
                 int bDirection = 1 + 2 + 4 + 8;  
544    
545                  do {                  if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
546                          iDirection = 0;                          || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
547                          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)                          || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
548                                  CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);                          || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
549    
550                          if (bDirection & 2)                  switch ( ((mvs.x&1)<<1) + (mvs.y&1) ) {
551                                  CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);                          case 0 : ReferenceF = data->Ref + mvs.x/2 + (mvs.y/2)*(data->iEdgedWidth); break;
552                            case 1 : ReferenceF = data->RefV + mvs.x/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
553                            case 2 : ReferenceF = data->RefH + (mvs.x-1)/2 + (mvs.y/2)*(data->iEdgedWidth); break;
554                            default : ReferenceF = data->RefHV + (mvs.x-1)/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
555                    }
556    
557                          if (bDirection & 4)                  switch ( ((b_mvs.x&1)<<1) + (b_mvs.y&1) ) {
558                                  CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);                          case 0 : ReferenceB = data->bRef + b_mvs.x/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
559                            case 1 : ReferenceB = data->bRefV + b_mvs.x/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
560                            case 2 : ReferenceB = data->bRefH + (b_mvs.x-1)/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
561                            default : ReferenceB = data->bRefHV + (b_mvs.x-1)/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
562                    }
563    
564                          if (bDirection & 8)                  sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
565                                  CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);                                                  ReferenceF + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
566                                                    ReferenceB + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
567                                                    data->iEdgedWidth);
568                    if (sad > *(data->iMinSAD)) return;
569            }
570    
571                          /* now we're doing diagonal checks near our candidate */          sad += (data->lambda16 * d_mv_bits(x, y, 1) * sad)/1000;
572    
573                          if (iDirection)         //checking if anything found          if (sad < *(data->iMinSAD)) {
574                          {                  *(data->iMinSAD) = sad;
575                                  bDirection = iDirection;                  data->currentMV->x = x; data->currentMV->y = y;
576                                  iDirection = 0;                  *dir = Direction; }
                                 start_x = currMV->x;  
                                 start_y = currMV->y;  
                                 if (bDirection & 3)     //our candidate is left or right  
                                 {  
                                         CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);  
                                 } else                  // what remains here is up or down  
                                 {  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
577                                  }                                  }
578    
579                                  if (iDirection) {  
580                                          bDirection += iDirection;  static void
581                                          start_x = currMV->x;  CheckCandidateDirect_qpel(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                                         start_y = currMV->y;  
                                 }  
                         } else                          //about to quit, eh? not so fast....  
582                          {                          {
583                                  switch (bDirection) {          int32_t sad = 0;
584                                  case 2:          int k;
585                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,          VECTOR mvs, b_mvs, halfpelMV;
586                                                                                           start_y - iDiamondSize, 2 + 4);          const uint8_t *ref1, *ref2, *ref3, *ref4;
587                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,          uint8_t *ReferenceF, *ReferenceB;
588                                                                                           start_y + iDiamondSize, 2 + 8);          const uint32_t iEdgedWidth = data->iEdgedWidth;
589                                          break;  
590                                  case 1:          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
591    
592            for (k = 0; k < 4; k++) {
593                    ReferenceF = (uint8_t *)data->RefQ;
594                    ReferenceB = (uint8_t *)data->RefQ + 64;
595    
596                    mvs.x = data->directmvF[k].x + x;
597                    b_mvs.x = ((x == 0) ?
598                            data->directmvB[k].x
599                            : mvs.x - data->referencemv[k].x);
600    
601                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                  mvs.y = data->directmvF[k].y + y;
602                                                                                           start_y - iDiamondSize, 1 + 4);                  b_mvs.y = ((y == 0) ?
603                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                          data->directmvB[k].y
604                                                                                           start_y + iDiamondSize, 1 + 8);                          : mvs.y - data->referencemv[k].y);
605    
606                    if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
607                            || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
608                            || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
609                            || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
610    
611                    halfpelMV.x = mvs.x/2; //forward first
612                    halfpelMV.y = mvs.y/2;
613                    GET_REFERENCE(halfpelMV.x, halfpelMV.y, ref1); // this reference is used in all cases
614                    switch( ((mvs.x&1)<<1) + (mvs.y&1) ) {
615                    case 0: // pure halfpel position
616                            GET_REFERENCE(halfpelMV.x + 16*(k&1), halfpelMV.y + 16*(k>>1), ReferenceF);
617                                          break;                                          break;
618                                  case 2 + 4:  
619                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                  case 1: // x halfpel, y qpel - top or bottom during qpel refinement
620                                                                                           start_y - iDiamondSize, 1 + 4);                          GET_REFERENCE(halfpelMV.x, mvs.y - halfpelMV.y, ref2);
621                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                          interpolate8x8_avg2(ReferenceF, ref1+8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
622                                                                                           start_y - iDiamondSize, 2 + 4);                                                          ref2+ 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth), iEdgedWidth, 0);
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
623                                          break;                                          break;
624                                  case 4:  
625                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                  case 2: // x qpel, y halfpel - left or right during qpel refinement
626                                                                                           start_y - iDiamondSize, 2 + 4);                          GET_REFERENCE(mvs.x - halfpelMV.x, halfpelMV.y, ref2);
627                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                          interpolate8x8_avg2(ReferenceF, ref1 + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
628                                                                                           start_y - iDiamondSize, 1 + 4);                                                          ref2 + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth), iEdgedWidth, 0);
629                                          break;                                          break;
630                                  case 8:  
631                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                  default: // x and y in qpel resolution - the "corners" (top left/right and
632                                                                                           start_y + iDiamondSize, 2 + 8);                                   // bottom left/right) during qpel refinement
633                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                          GET_REFERENCE(halfpelMV.x, mvs.y - halfpelMV.y, ref2);
634                                                                                           start_y + iDiamondSize, 1 + 8);                          GET_REFERENCE(mvs.x - halfpelMV.x, halfpelMV.y, ref3);
635                            GET_REFERENCE(mvs.x - halfpelMV.x, mvs.y - halfpelMV.y, ref4);
636                            interpolate8x8_avg4(ReferenceF, ref1 + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
637                                                                    ref2 + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
638                                                                    ref3 + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
639                                                                    ref4 + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth), iEdgedWidth, 0);
640                                          break;                                          break;
641                                  case 1 + 4:                  }
642                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
643                                                                                           start_y + iDiamondSize, 1 + 8);                  halfpelMV.x = b_mvs.x/2;
644                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                  halfpelMV.y = b_mvs.y/2;
645                                                                                           start_y - iDiamondSize, 1 + 4);                  GET_REFERENCE2(halfpelMV.x, halfpelMV.y, ref1); // this reference is used in most cases
646                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                  switch( ((b_mvs.x&1)<<1) + (b_mvs.y&1) ) {
647                                                                                           start_y - iDiamondSize, 2 + 4);                  case 0: // pure halfpel position
648                            GET_REFERENCE2(halfpelMV.x + 16*(k&1), halfpelMV.y + 16*(k>>1), ReferenceB);
649                                          break;                                          break;
650                                  case 2 + 8:  
651                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                  case 1: // x halfpel, y qpel - top or bottom during qpel refinement
652                                                                                           start_y - iDiamondSize, 1 + 4);                          GET_REFERENCE2(halfpelMV.x, b_mvs.y - halfpelMV.y, ref2);
653                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                          interpolate8x8_avg2(ReferenceB, ref1+8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
654                                                                                           start_y + iDiamondSize, 1 + 8);                                                                  ref2+ 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth), iEdgedWidth, 0);
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
655                                          break;                                          break;
656                                  case 1 + 8:  
657                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                  case 2: // x qpel, y halfpel - left or right during qpel refinement
658                                                                                           start_y - iDiamondSize, 2 + 4);                          GET_REFERENCE2(b_mvs.x - halfpelMV.x, halfpelMV.y, ref2);
659                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                          interpolate8x8_avg2(ReferenceB, ref1 + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
660                                                                                           start_y + iDiamondSize, 2 + 8);                                                                  ref2 + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth), iEdgedWidth, 0);
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
661                                          break;                                          break;
662                                  default:                //1+2+4+8 == we didn't find anything at all  
663                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                  default: // x and y in qpel resolution - the "corners" (top left/right and
664                                                                                           start_y - iDiamondSize, 1 + 4);                                   // bottom left/right) during qpel refinement
665                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                          GET_REFERENCE2(halfpelMV.x, b_mvs.y - halfpelMV.y, ref2);
666                                                                                           start_y + iDiamondSize, 1 + 8);                          GET_REFERENCE2(b_mvs.x - halfpelMV.x, halfpelMV.y, ref3);
667                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                          GET_REFERENCE2(b_mvs.x - halfpelMV.x, b_mvs.y - halfpelMV.y, ref4);
668                                                                                           start_y - iDiamondSize, 2 + 4);                          interpolate8x8_avg4(ReferenceB, ref1 + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
669                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                                                                  ref2 + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
670                                                                                           start_y + iDiamondSize, 2 + 8);                                                                  ref3 + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
671                                                                    ref4 + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth), iEdgedWidth, 0);
672                                          break;                                          break;
673                                  }                                  }
                                 if (!iDirection)  
                                         break;          //ok, the end. really  
                                 else {  
                                         bDirection = iDirection;  
                                         start_x = currMV->x;  
                                         start_y = currMV->y;  
                                 }  
                         }  
                 }  
                 while (1);                              //forever  
         }  
         return iMinSAD;  
 }  
674    
675  #define CHECK_MV16_F_INTERPOL(X,Y) { \                  sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
676    if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \                                                  ReferenceF,
677      && ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \                                                  ReferenceB,
678    { \                                                  data->iEdgedWidth);
679      iSAD = sad16bi( cur, \                  if (sad > *(data->iMinSAD)) return;
                         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); } } \  
680  }  }
681    
682  #define CHECK_MV16_F_INTERPOL_FOUND(X,Y) { \          sad += (data->lambda16 * d_mv_bits(x, y, 1) * sad)/1000;
   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;} } \  
 }  
683    
684  #define CHECK_MV16_B_INTERPOL(X,Y) { \          if (sad < *(data->iMinSAD)) {
685    if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \                  *(data->iMinSAD) = sad;
686      && ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \                  data->currentMV->x = x; data->currentMV->y = y;
687    { \                  *dir = Direction; }
     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); } } \  
688  }  }
689    
690  #define CHECK_MV16_B_INTERPOL_FOUND(X,Y) { \  static void
691    if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \  CheckCandidateDirectno4v_qpel(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
692      && ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \  {
693    { \          int32_t sad = 0;
694      iSAD = sad16bi( cur, \          VECTOR mvs, b_mvs, halfpelMV;
695                          get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth),   \          const uint8_t *ref1, *ref2, *ref3, *ref4;
696                          get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \          const uint32_t iEdgedWidth = data->iEdgedWidth;
697                          iEdgedWidth); \          uint8_t * ReferenceF = (uint8_t *)data->RefQ;
698      iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\          uint8_t * ReferenceB = (uint8_t *)data->RefQ + 64;
     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,  
699    
700                                     const int f_start_x,          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
                                    const int f_start_y,  
                                    const int b_start_x,  
                                    const int b_start_y,  
   
                                    int iMinSAD,  
                                    VECTOR * const f_currMV,  
                                    VECTOR * const b_currMV,  
   
                                    const int f_center_x,  
                                    const int f_center_y,  
                                    const int b_center_x,  
                                    const int b_center_y,  
   
                                     const int32_t f_min_dx,  
                                         const int32_t f_max_dx,  
                                         const int32_t f_min_dy,  
                                         const int32_t f_max_dy,  
   
                                     const int32_t b_min_dx,  
                                         const int32_t b_max_dx,  
                                         const int32_t b_min_dy,  
                                         const int32_t b_max_dy,  
   
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
   
                                         const int32_t f_iFcode,  
                                         const int32_t b_iFcode,  
   
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iSAD;  
   
         VECTOR f_backupMV;  
         VECTOR b_backupMV;  
   
         f_currMV->x = f_start_x;  
         f_currMV->y = f_start_y;  
         b_currMV->x = b_start_x;  
         b_currMV->y = b_start_y;  
   
         do  
         {  
                 iFound = 1;  
   
                 f_backupMV = *f_currMV;  
   
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x - iDiamondSize, f_backupMV.y);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x + iDiamondSize, f_backupMV.y);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y - iDiamondSize);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y + iDiamondSize);  
   
                 b_backupMV = *b_currMV;  
   
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x - iDiamondSize, b_backupMV.y);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x + iDiamondSize, b_backupMV.y);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y - iDiamondSize);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y + iDiamondSize);  
   
         } while (!iFound);  
   
         return iMinSAD;  
 }  
   
 /* Sorry, these MACROS really got too large... I'll turn them into function soon! */  
   
 #define CHECK_MV16_DIRECT_FOUND(X,Y) \  
         if ( (X)>=(-32) && (X)<=(31) && ((Y)>=-32) && ((Y)<=31) ) \  
         { int k;\  
         VECTOR mvs,b_mvs;       \  
         iSAD = 0;\  
         for (k = 0; k < 4; k++) {       \  
                                         mvs.x = (int32_t) ((TRB * directmv[k].x) / TRD + (X));          \  
                     b_mvs.x = (int32_t) (((X) == 0)                                                     \  
                                                                                 ? ((TRB - TRD) * directmv[k].x) / TRD   \  
                                             : mvs.x - directmv[k].x);                           \  
                                                                                                                                                                 \  
                     mvs.y = (int32_t) ((TRB * directmv[k].y) / TRD + (Y));              \  
                         b_mvs.y = (int32_t) (((Y) == 0)                                                         \  
                                                                                 ? ((TRB - TRD) * directmv[k].y) / TRD   \  
                                             : mvs.y - directmv[k].y);                           \  
                                                                                                                                                                 \  
   if ( (mvs.x <= max_dx) && (mvs.x >= min_dx) \  
     && (mvs.y <= max_dy) && (mvs.y >= min_dy)  \  
         && (b_mvs.x <= max_dx) && (b_mvs.x >= min_dx)  \  
     && (b_mvs.y <= max_dy) && (b_mvs.y >= min_dy) ) { \  
             iSAD += sad8bi( cur + 8*(k&1) + 8*(k>>1)*iEdgedWidth,                                                                                                       \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \  
                                         mvs.x, mvs.y, iEdgedWidth),                                                             \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \  
                                         b_mvs.x, b_mvs.y, iEdgedWidth),                                                         \  
                         iEdgedWidth); \  
                 }       \  
         else    \  
                 iSAD = 65535;   \  
         } \  
         iSAD += calc_delta_16((X),(Y), 1, iQuant);\  
         if (iSAD < iMinSAD) \  
             {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iFound=0; } \  
 }  
701    
702            mvs.x = data->directmvF[0].x + x;
703            b_mvs.x = ((x == 0) ?
704                            data->directmvB[0].x
705                            : mvs.x - data->referencemv[0].x);
706    
707            mvs.y = data->directmvF[0].y + y;
708            b_mvs.y = ((y == 0) ?
709                            data->directmvB[0].y
710                            : mvs.y - data->referencemv[0].y);
711    
712  int32_t          if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
713  Diamond16_DirectMainSearch(                          || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
714                                          const uint8_t * const f_pRef,                          || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
715                                          const uint8_t * const f_pRefH,                          || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
                                         const uint8_t * const f_pRefV,  
                                         const uint8_t * const f_pRefHV,  
716    
717                                          const uint8_t * const cur,          halfpelMV.x = mvs.x/2; //forward first
718            halfpelMV.y = mvs.y/2;
719            GET_REFERENCE(halfpelMV.x, halfpelMV.y, ref1); // this reference is used in all cases
720            switch( ((mvs.x&1)<<1) + (mvs.y&1) ) {
721            case 0: // pure halfpel position
722                    GET_REFERENCE(halfpelMV.x, halfpelMV.y, ReferenceF);
723                    break;
724    
725                                          const uint8_t * const b_pRef,          case 1: // x halfpel, y qpel - top or bottom during qpel refinement
726                                          const uint8_t * const b_pRefH,                  GET_REFERENCE(halfpelMV.x, mvs.y - halfpelMV.y, ref2);
727                                          const uint8_t * const b_pRefV,                  interpolate8x8_avg2(ReferenceF, ref1, ref2, iEdgedWidth, 0);
728                                          const uint8_t * const b_pRefHV,                  interpolate8x8_avg2(ReferenceF+8, ref1+8, ref2+8, iEdgedWidth, 0);
729                    interpolate8x8_avg2(ReferenceF+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, 0);
730                    interpolate8x8_avg2(ReferenceF+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, 0);
731                    break;
732    
733                                          const int x,          case 2: // x qpel, y halfpel - left or right during qpel refinement
734                                          const int y,                  GET_REFERENCE(mvs.x - halfpelMV.x, halfpelMV.y, ref2);
735                    interpolate8x8_avg2(ReferenceF, ref1, ref2, iEdgedWidth, 0);
736                    interpolate8x8_avg2(ReferenceF+8, ref1+8, ref2+8, iEdgedWidth, 0);
737                    interpolate8x8_avg2(ReferenceF+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, 0);
738                    interpolate8x8_avg2(ReferenceF+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, 0);
739                    break;
740    
741                                          const int TRB,          default: // x and y in qpel resolution
742                                          const int TRD,                  GET_REFERENCE(halfpelMV.x, mvs.y - halfpelMV.y, ref2);
743                    GET_REFERENCE(mvs.x - halfpelMV.x, halfpelMV.y, ref3);
744                    GET_REFERENCE(mvs.x - halfpelMV.x, mvs.y - halfpelMV.y, ref4);
745    
746                                      const int start_x,                  interpolate8x8_avg4(ReferenceF, ref1, ref2, ref3, ref4, iEdgedWidth, 0);
747                                      const int start_y,                  interpolate8x8_avg4(ReferenceF+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, 0);
748                    interpolate8x8_avg4(ReferenceF+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, 0);
749                    interpolate8x8_avg4(ReferenceF+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, 0);
750                    break;
751            }
752    
753                                      int iMinSAD,          halfpelMV.x = b_mvs.x/2; //backward
754                                      VECTOR * const currMV,          halfpelMV.y = b_mvs.y/2;
755                                          const VECTOR * const directmv,          GET_REFERENCE2(halfpelMV.x, halfpelMV.y, ref1);
756            switch( ((b_mvs.x&1)<<1) + (b_mvs.y&1) )
757            {
758            case 0: // pure halfpel position
759                    GET_REFERENCE2(halfpelMV.x, halfpelMV.y, ReferenceB);
760                    break;
761    
762                                      const int32_t min_dx,          case 1: // x halfpel, y qpel - top or bottom during qpel refinement
763                                          const int32_t max_dx,                  GET_REFERENCE2(halfpelMV.x, b_mvs.y - halfpelMV.y, ref2);
764                                          const int32_t min_dy,                  interpolate8x8_avg2(ReferenceB, ref1, ref2, iEdgedWidth, 0);
765                                          const int32_t max_dy,                  interpolate8x8_avg2(ReferenceB+8, ref1+8, ref2+8, iEdgedWidth, 0);
766                    interpolate8x8_avg2(ReferenceB+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, 0);
767                    interpolate8x8_avg2(ReferenceB+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, 0);
768                    break;
769    
770                                          const int32_t iEdgedWidth,          case 2: // x qpel, y halfpel - left or right during qpel refinement
771                                          const int32_t iDiamondSize,                  GET_REFERENCE2(b_mvs.x - halfpelMV.x, halfpelMV.y, ref2);
772                    interpolate8x8_avg2(ReferenceB, ref1, ref2, iEdgedWidth, 0);
773                    interpolate8x8_avg2(ReferenceB+8, ref1+8, ref2+8, iEdgedWidth, 0);
774                    interpolate8x8_avg2(ReferenceB+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, 0);
775                    interpolate8x8_avg2(ReferenceB+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, 0);
776                    break;
777    
778                                          const int32_t iQuant,          default: // x and y in qpel resolution - the "corners" (top left/right and
779                                          int iFound)                           // bottom left/right) during qpel refinement
780  {                  GET_REFERENCE2(halfpelMV.x, b_mvs.y - halfpelMV.y, ref2);
781  /* Do a diamond search around given starting point, return SAD of best */                  GET_REFERENCE2(b_mvs.x - halfpelMV.x, halfpelMV.y, ref3);
782                    GET_REFERENCE2(b_mvs.x - halfpelMV.x, b_mvs.y - halfpelMV.y, ref4);
783    
784          int32_t iSAD;                  interpolate8x8_avg4(ReferenceB, ref1, ref2, ref3, ref4, iEdgedWidth, 0);
785                    interpolate8x8_avg4(ReferenceB+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, 0);
786                    interpolate8x8_avg4(ReferenceB+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, 0);
787                    interpolate8x8_avg4(ReferenceB+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, 0);
788                    break;
789            }
790    
791          VECTOR backupMV;          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
792            sad += (data->lambda16 * d_mv_bits(x, y, 1) * sad)/1000;
793    
794          currMV->x = start_x;          if (sad < *(data->iMinSAD)) {
795          currMV->y = start_y;                  *(data->iMinSAD) = sad;
796                    data->currentMV->x = x; data->currentMV->y = y;
797                    *dir = Direction; }
798    }
799    
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
800    
801          do  static void
802    CheckCandidateDirectno4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
803          {          {
804                  iFound = 1;          int32_t sad;
805            const uint8_t *ReferenceF;
806            const uint8_t *ReferenceB;
807            VECTOR mvs, b_mvs;
808    
809                  backupMV = *currMV;          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
810    
811                  CHECK_MV16_DIRECT_FOUND(backupMV.x - iDiamondSize, backupMV.y);          mvs.x = data->directmvF[0].x + x;
812                  CHECK_MV16_DIRECT_FOUND(backupMV.x + iDiamondSize, backupMV.y);          b_mvs.x = ((x == 0) ?
813                  CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y - iDiamondSize);                  data->directmvB[0].x
814                  CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y + iDiamondSize);                  : mvs.x - data->referencemv[0].x);
815    
816          } while (!iFound);          mvs.y = data->directmvF[0].y + y;
817            b_mvs.y = ((y == 0) ?
818                    data->directmvB[0].y
819                    : mvs.y - data->referencemv[0].y);
820    
821          return iMinSAD;          if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
822                    || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
823                    || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
824                    || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
825    
826            switch ( ((mvs.x&1)<<1) + (mvs.y&1) ) {
827                    case 0 : ReferenceF = data->Ref + mvs.x/2 + (mvs.y/2)*(data->iEdgedWidth); break;
828                    case 1 : ReferenceF = data->RefV + mvs.x/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
829                    case 2 : ReferenceF = data->RefH + (mvs.x-1)/2 + (mvs.y/2)*(data->iEdgedWidth); break;
830                    default : ReferenceF = data->RefHV + (mvs.x-1)/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
831  }  }
832    
833            switch ( ((b_mvs.x&1)<<1) + (b_mvs.y&1) ) {
834                    case 0 : ReferenceB = data->bRef + b_mvs.x/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
835                    case 1 : ReferenceB = data->bRefV + b_mvs.x/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
836                    case 2 : ReferenceB = data->bRefH + (b_mvs.x-1)/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
837                    default : ReferenceB = data->bRefHV + (b_mvs.x-1)/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
838            }
839    
840  int32_t          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
841  AdvDiamond8_MainSearch(const uint8_t * const pRef,          sad += (data->lambda16 * d_mv_bits(x, y, 1) * sad)/1000;
                                            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)  
 {  
842    
843          int32_t iSAD;          if (sad < *(data->iMinSAD)) {
844                    *(data->iMinSAD) = sad;
845                    data->currentMV->x = x; data->currentMV->y = y;
846                    *dir = Direction; }
847    }
848    
849  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */  static void
850    CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
851    {
852            int32_t sad; int t;
853            const uint8_t * Reference;
854    
855          if (iDirection) {          if (( x > data->max_dx) || ( x < data->min_dx)
856                  CHECK_MV8_CANDIDATE(start_x - iDiamondSize, start_y);                  || ( y > data->max_dy) || (y < data->min_dy)) return;
                 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;  
857    
858                  do {          switch ( ((x&1)<<1) + (y&1) )
859                          iDirection = 0;          {
860                          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)                  case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
861                                  CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);                  case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;
862                    case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;
863                    default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
864            }
865    
866                          if (bDirection & 2)          sad = sad8(data->Cur, Reference, data->iEdgedWidth);
867                                  CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);          if (data->qpel) t = d_mv_bits(2 * x - data->predQMV.x, 2 * y - data->predQMV.y, data->iFcode);
868            else t = d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
869    
870                          if (bDirection & 4)          sad += (data->lambda8 * t * (sad+NEIGH_8X8_BIAS))/100;
                                 CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);  
871    
872                          if (bDirection & 8)          if (sad < *(data->iMinSAD)) {
873                                  CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);                  *(data->iMinSAD) = sad;
874                    data->currentMV->x = x; data->currentMV->y = y;
875                    *dir = Direction; }
876    }
877    
878                          /* now we're doing diagonal checks near our candidate */  static void
879    CheckCandidate8_qpel(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
880    // CheckCandidate8 variant which expects x and y in quarter pixel resolution
881    // Important: This is no general usable routine! x and y must be +/-1 (qpel resolution!)
882    // around currentMV!
883    
                         if (iDirection)         //checking if anything found  
884                          {                          {
885                                  bDirection = iDirection;          int32_t sad;
886                                  iDirection = 0;          uint8_t *Reference = (uint8_t *) data->RefQ;
887                                  start_x = currMV->x;          const uint8_t *ref1, *ref2, *ref3, *ref4;
888                                  start_y = currMV->y;          VECTOR halfpelMV = *(data->currentMV);
889                                  if (bDirection & 3)     //our candidate is left or right  
890                                  {          int32_t iEdgedWidth = data->iEdgedWidth;
891                                          CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);          uint32_t rounding = data->rounding;
892                                          CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);  
893                                  } else                  // what remains here is up or down          if (( x > data->max_dx) || ( x < data->min_dx)
894                    || ( y > data->max_dy) || (y < data->min_dy)) return;
895    
896            GET_REFERENCE(halfpelMV.x, halfpelMV.y, ref1);
897            switch( ((x&1)<<1) + (y&1) )
898                                  {                                  {
899                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);          case 0: // pure halfpel position - shouldn't happen during a refinement step
900                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);                  GET_REFERENCE(halfpelMV.x, halfpelMV.y, Reference);
901                    break;
902    
903            case 1: // x halfpel, y qpel - top or bottom during qpel refinement
904                    GET_REFERENCE(halfpelMV.x, y - halfpelMV.y, ref2);
905    
906                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding);
907                    break;
908    
909            case 2: // x qpel, y halfpel - left or right during qpel refinement
910                    GET_REFERENCE(x - halfpelMV.x, halfpelMV.y, ref2);
911    
912                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding);
913                    break;
914    
915            default: // x and y in qpel resolution - the "corners" (top left/right and
916                             // bottom left/right) during qpel refinement
917                    GET_REFERENCE(halfpelMV.x, y - halfpelMV.y, ref2);
918                    GET_REFERENCE(x - halfpelMV.x, halfpelMV.y, ref3);
919                    GET_REFERENCE(x - halfpelMV.x, y - halfpelMV.y, ref4);
920    
921                    interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
922                    break;
923                                  }                                  }
924    
925                                  if (iDirection) {          sad = sad8(data->Cur, Reference, data->iEdgedWidth);
926                                          bDirection += iDirection;          sad += (data->lambda8 * d_mv_bits(x - data->predQMV.x, y - data->predQMV.y, data->iFcode) * (sad+NEIGH_8X8_BIAS))/100;
927                                          start_x = currMV->x;  
928                                          start_y = currMV->y;          if (sad < *(data->iMinSAD)) {
929                    *(data->iMinSAD) = sad;
930                    data->currentQMV->x = x; data->currentQMV->y = y;
931                    *dir = Direction; }
932                                  }                                  }
933                          } else                          //about to quit, eh? not so fast....  
934    /* CHECK_CANDIATE FUNCTIONS END */
935    
936    /* MAINSEARCH FUNCTIONS START */
937    
938    static void
939    AdvDiamondSearch(int x, int y, const SearchData * const data, int bDirection)
940                          {                          {
941    
942    /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
943    
944                    int iDirection;
945    
946                    do {
947                            iDirection = 0;
948                            if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
949                            if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
950                            if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
951                            if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
952    
953                            /* now we're doing diagonal checks near our candidate */
954    
955                            if (iDirection) {               //checking if anything found
956                                    bDirection = iDirection;
957                                    iDirection = 0;
958                                    x = data->currentMV->x; y = data->currentMV->y;
959                                    if (bDirection & 3) {   //our candidate is left or right
960                                            CHECK_CANDIDATE(x, y + iDiamondSize, 8);
961                                            CHECK_CANDIDATE(x, y - iDiamondSize, 4);
962                                    } else {                        // what remains here is up or down
963                                            CHECK_CANDIDATE(x + iDiamondSize, y, 2);
964                                            CHECK_CANDIDATE(x - iDiamondSize, y, 1); }
965    
966                                    if (iDirection) {
967                                            bDirection += iDirection;
968                                            x = data->currentMV->x; y = data->currentMV->y; }
969                            } else {                                //about to quit, eh? not so fast....
970                                  switch (bDirection) {                                  switch (bDirection) {
971                                  case 2:                                  case 2:
972                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
973                                                                                          start_y - iDiamondSize, 2 + 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
974                                          break;                                          break;
975                                  case 1:                                  case 1:
976                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
977                                                                                          start_y - iDiamondSize, 1 + 4);                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
978                                          break;                                          break;
979                                  case 2 + 4:                                  case 2 + 4:
980                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
981                                                                                          start_y - iDiamondSize, 1 + 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
982                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
983                                          break;                                          break;
984                                  case 4:                                  case 4:
985                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
986                                                                                          start_y - iDiamondSize, 2 + 4);                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
987                                          break;                                          break;
988                                  case 8:                                  case 8:
989                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
990                                                                                          start_y + iDiamondSize, 2 + 8);                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
991                                          break;                                          break;
992                                  case 1 + 4:                                  case 1 + 4:
993                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
994                                                                                          start_y + iDiamondSize, 1 + 8);                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
995                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
996                                          break;                                          break;
997                                  case 2 + 8:                                  case 2 + 8:
998                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
999                                                                                          start_y - iDiamondSize, 1 + 4);                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
1000                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
1001                                          break;                                          break;
1002                                  case 1 + 8:                                  case 1 + 8:
1003                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
1004                                                                                          start_y - iDiamondSize, 2 + 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
1005                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
1006                                          break;                                          break;
1007                                  default:                //1+2+4+8 == we didn't find anything at all                                  default:                //1+2+4+8 == we didn't find anything at all
1008                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
1009                                                                                          start_y - iDiamondSize, 1 + 4);                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
1010                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
1011                                                                                          start_y + iDiamondSize, 1 + 8);                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
1012                                          break;                                          break;
1013                                  }                                  }
1014                                  if (!(iDirection))                                  if (!iDirection) break;         //ok, the end. really
                                         break;          //ok, the end. really  
                                 else {  
1015                                          bDirection = iDirection;                                          bDirection = iDirection;
1016                                          start_x = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
                                         start_y = currMV->y;  
                                 }  
1017                          }                          }
1018                  }                  }
1019                  while (1);                              //forever                  while (1);                              //forever
1020          }          }
1021          return iMinSAD;  
1022    static void
1023    SquareSearch(int x, int y, const SearchData * const data, int bDirection)
1024    {
1025            int iDirection;
1026    
1027            do {
1028                    iDirection = 0;
1029                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);
1030                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);
1031                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);
1032                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128);
1033                    if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64);
1034                    if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128);
1035                    if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128);
1036                    if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128);
1037    
1038                    bDirection = iDirection;
1039                    x = data->currentMV->x; y = data->currentMV->y;
1040            } while (iDirection);
1041  }  }
1042    
1043    static void
1044    DiamondSearch(int x, int y, const SearchData * const data, int bDirection)
1045    {
1046    
1047  int32_t  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
1048  Full8_MainSearch(const uint8_t * const pRef,  
1049                                   const uint8_t * const pRefH,                  int iDirection;
1050                                   const uint8_t * const pRefV,  
1051                                   const uint8_t * const pRefHV,                  do {
1052                                   const uint8_t * const cur,                          iDirection = 0;
1053                                   const int x,                          if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
1054                                   const int y,                          if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
1055                             const int start_x,                          if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
1056                             const int start_y,                          if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
1057                             int iMinSAD,  
1058                             VECTOR * const currMV,                          /* now we're doing diagonal checks near our candidate */
                            const int center_x,  
                            const int center_y,  
                                  const int32_t min_dx,  
                                  const int32_t max_dx,  
                                  const int32_t min_dy,  
                                  const int32_t max_dy,  
                                  const int32_t iEdgedWidth,  
                                  const int32_t iDiamondSize,  
                                  const int32_t iFcode,  
                                  const int32_t iQuant,  
                                  int iFound)  
 {  
         int32_t iSAD;  
         int32_t dx, dy;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV8_CANDIDATE(dx, dy);  
1059    
1060          return iMinSAD;                          if (iDirection) {               //checking if anything found
1061                                    bDirection = iDirection;
1062                                    iDirection = 0;
1063                                    x = data->currentMV->x; y = data->currentMV->y;
1064                                    if (bDirection & 3) {   //our candidate is left or right
1065                                            CHECK_CANDIDATE(x, y + iDiamondSize, 8);
1066                                            CHECK_CANDIDATE(x, y - iDiamondSize, 4);
1067                                    } else {                        // what remains here is up or down
1068                                            CHECK_CANDIDATE(x + iDiamondSize, y, 2);
1069                                            CHECK_CANDIDATE(x - iDiamondSize, y, 1); }
1070    
1071                                    bDirection += iDirection;
1072                                    x = data->currentMV->x; y = data->currentMV->y;
1073                            }
1074                    }
1075                    while (iDirection);
1076  }  }
1077    
1078  Halfpel8_RefineFuncPtr Halfpel8_Refine;  /* MAINSEARCH FUNCTIONS END */
1079    
1080  int32_t  /* HALFPELREFINE COULD BE A MAINSEARCH FUNCTION, BUT THERE IS NO NEED FOR IT */
1081  Halfpel16_Refine(const uint8_t * const pRef,  
1082                                   const uint8_t * const pRefH,  static void
1083                                   const uint8_t * const pRefV,  HalfpelRefine(const SearchData * const data)
                                  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)  
1084  {  {
1085  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */
1086    
1087          int32_t iSAD;          VECTOR backupMV = *(data->currentMV);
1088          VECTOR backupMV = *currMV;          int iDirection; //not needed
1089    
1090          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y - 1);          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y - 1, 0);
1091          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y - 1);          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y - 1, 0);
1092          CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y - 1);          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y + 1, 0);
1093          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y);          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y + 1, 0);
         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);  
1094    
1095          return iMinSAD;          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y, 0);
1096            CHECK_CANDIDATE(backupMV.x + 1, backupMV.y, 0);
1097    
1098            CHECK_CANDIDATE(backupMV.x, backupMV.y + 1, 0);
1099            CHECK_CANDIDATE(backupMV.x, backupMV.y - 1, 0);
1100  }  }
1101    
 #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)  
1102    
1103    static void
1104    QuarterpelRefine(const SearchData * const data)
1105    {
1106    /* Perform quarter pixel refinement*/
1107    
1108            VECTOR backupMV = *(data->currentQMV);
1109            int iDirection; //not needed
1110    
1111  int32_t          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y - 1, 0);
1112  PMVfastSearch16(const uint8_t * const pRef,          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y - 1, 0);
1113                                  const uint8_t * const pRefH,          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y + 1, 0);
1114                                  const uint8_t * const pRefV,          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y + 1, 0);
1115                                  const uint8_t * const pRefHV,  
1116                                  const IMAGE * const pCur,          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y, 0);
1117                                  const int x,          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y, 0);
                                 const int y,  
                                 const int start_x,      /* start is searched first, so it should contain the most */  
                                 const int start_y,  /* likely motion vector for this block */  
                                 const int center_x,     /* center is from where length of MVs is measured */  
                                 const int center_y,  
                                 const uint32_t MotionFlags,  
                                 const uint32_t iQuant,  
                                 const uint32_t iFcode,  
                                 const MBParam * const pParam,  
                                 const MACROBLOCK * const pMBs,  
                                 const MACROBLOCK * const prevMBs,  
                                 VECTOR * const currMV,  
                                 VECTOR * const currPMV)  
 {  
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
1118    
1119          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          CHECK_CANDIDATE(backupMV.x, backupMV.y + 1, 0);
1120            CHECK_CANDIDATE(backupMV.x, backupMV.y - 1, 0);
1121    
1122          int32_t iDiamondSize;  }
1123    
1124          int32_t min_dx;  static __inline int
1125          int32_t max_dx;  SkipDecisionP(const IMAGE * current, const IMAGE * reference,
1126          int32_t min_dy;                                                          const int x, const int y,
1127          int32_t max_dy;                                                          const uint32_t iEdgedWidth, const uint32_t iQuant)
1128    
1129          int32_t iFound;  {
1130    /*      keep repeating checks for all b-frames before this P frame,
1131            to make sure that SKIP is possible (todo)
1132            how: if skip is not possible set sad00 to a very high value */
1133    
1134            uint32_t sadC = sad8(current->u + x*8 + y*(iEdgedWidth/2)*8,
1135                                            reference->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2);
1136            if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
1137            sadC += sad8(current->v + (x + y*(iEdgedWidth/2))*8,
1138                                            reference->v + (x + y*(iEdgedWidth/2))*8, iEdgedWidth/2);
1139            if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
1140    
1141          VECTOR newMV;          return 1;
1142          VECTOR backupMV;                        /* just for PMVFAST */  }
1143    
1144          VECTOR pmv[4];  static __inline void
1145          int32_t psad[4];  SkipMacroblockP(MACROBLOCK *pMB, const int32_t sad)
1146    {
1147            pMB->mode = MODE_NOT_CODED;
1148            pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = 0;
1149            pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = 0;
1150    
1151          MainSearch16FuncPtr MainSearchPtr;          pMB->qmvs[0].x = pMB->qmvs[1].x = pMB->qmvs[2].x = pMB->qmvs[3].x = 0;
1152            pMB->qmvs[0].y = pMB->qmvs[1].y = pMB->qmvs[2].y = pMB->qmvs[3].y = 0;
1153    
1154          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
1155    }
1156    
1157          int32_t threshA, threshB;  bool
1158          int32_t bPredEq;  MotionEstimation(MBParam * const pParam,
1159          int32_t iMinSAD, iSAD;                                   FRAMEINFO * const current,
1160                                     FRAMEINFO * const reference,
1161                                     const IMAGE * const pRefH,
1162                                     const IMAGE * const pRefV,
1163                                     const IMAGE * const pRefHV,
1164                                     const uint32_t iLimit)
1165    {
1166            MACROBLOCK *const pMBs = current->mbs;
1167            const IMAGE *const pCurrent = &current->image;
1168            const IMAGE *const pRef = &reference->image;
1169    
1170  /* Get maximum range */          const VECTOR zeroMV = { 0, 0 };
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
1171    
1172  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          uint32_t x, y;
1173            uint32_t iIntra = 0;
1174            int32_t InterBias, quant = current->quant, sad00;
1175            uint8_t *qimage;
1176    
1177            // some pre-initialized thingies for SearchP
1178            int32_t temp[5];
1179            VECTOR currentMV[5];
1180            VECTOR currentQMV[5];
1181            int32_t iMinSAD[5];
1182            SearchData Data;
1183            Data.iEdgedWidth = pParam->edged_width;
1184            Data.currentMV = currentMV;
1185            Data.currentQMV = currentQMV;
1186            Data.iMinSAD = iMinSAD;
1187            Data.temp = temp;
1188            Data.iFcode = current->fcode;
1189            Data.rounding = pParam->m_rounding_type;
1190            Data.qpel = pParam->m_quarterpel;
1191            Data.chroma = current->global_flags & XVID_ME_COLOUR;
1192    
1193            if((qimage = (uint8_t *) malloc(32 * pParam->edged_width)) == NULL)
1194                    return 1; // allocate some mem for qpel interpolated blocks
1195                                      // somehow this is dirty since I think we shouldn't use malloc outside
1196                                      // encoder_create() - so please fix me!
1197            Data.RefQ = qimage;
1198            if (sadInit) (*sadInit) ();
1199    
1200            for (y = 0; y < pParam->mb_height; y++) {
1201                    for (x = 0; x < pParam->mb_width; x++)  {
1202                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1203    
1204                            pMB->sad16
1205                                    = sad16v(pCurrent->y + (x + y * pParam->edged_width) * 16,
1206                                                            pRef->y + (x + y * pParam->edged_width) * 16,
1207                                                            pParam->edged_width, pMB->sad8 );
1208    
1209                            if (Data.chroma) {
1210                                    pMB->sad16 += sad8(pCurrent->u + x*8 + y*(pParam->edged_width/2)*8,
1211                                                                    pRef->u + x*8 + y*(pParam->edged_width/2)*8, pParam->edged_width/2);
1212    
1213                                    pMB->sad16 += sad8(pCurrent->v + (x + y*(pParam->edged_width/2))*8,
1214                                                                    pRef->v + (x + y*(pParam->edged_width/2))*8, pParam->edged_width/2);
1215                            }
1216    
1217                            sad00 = pMB->sad16; //if no gmc; else sad00 = (..)
1218    
1219                            if (!(current->global_flags & XVID_LUMIMASKING)) {
1220                                    pMB->dquant = NO_CHANGE;
1221                                    pMB->quant = current->quant;
1222                            } else {
1223                                    if (pMB->dquant != NO_CHANGE) {
1224                                            quant += DQtab[pMB->dquant];
1225                                            if (quant > 31) quant = 31;
1226                                            else if (quant < 1) quant = 1;
1227                                    }
1228                                    pMB->quant = quant;
1229                            }
1230    
1231          if (!(MotionFlags & PMV_HALFPEL16)) {  //initial skip decision
1232                  min_dx = EVEN(min_dx);  /* no early skip for GMC (global vector = skip vector is unknown!)  */
1233                  max_dx = EVEN(max_dx);                          if (current->coding_type == P_VOP)      { /* no fast SKIP for S(GMC)-VOPs */
1234                  min_dy = EVEN(min_dy);                                  if (pMB->dquant == NO_CHANGE && sad00 < pMB->quant * INITIAL_SKIP_THRESH)
1235                  max_dy = EVEN(max_dy);                                          if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, pParam->edged_width, pMB->quant)) {
1236                                                    SkipMacroblockP(pMB, sad00);
1237                                                    continue;
1238                                            }
1239          }          }
1240    
1241          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */                          SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1242          //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);                                                  y, current->motion_flags, pMB->quant,
1243          bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);                                                  &Data, pParam, pMBs, reference->mbs,
1244                                                    current->global_flags & XVID_INTER4V, pMB);
1245          if ((x == 0) && (y == 0)) {  
1246                  threshA = 512;  /* final skip decision, a.k.a. "the vector you found, really that good?" */
1247                  threshB = 1024;                          if (current->coding_type == P_VOP)      {
1248          } else {                                  if ( (pMB->dquant == NO_CHANGE) && (sad00 < pMB->quant * MAX_SAD00_FOR_SKIP)
1249                  threshA = psad[0];                                  && ((100*pMB->sad16)/(sad00+1) > FINAL_SKIP_THRESH) )
1250                  threshB = threshA + 256;                                          if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, pParam->edged_width, pMB->quant)) {
1251                  if (threshA < 512)                                                  SkipMacroblockP(pMB, sad00);
1252                          threshA = 512;                                                  continue;
1253                  if (threshA > 1024)                                          }
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
1254          }          }
1255    
1256          iFound = 0;  /* finally, intra decision */
1257    
1258  /* Step 4: Calculate SAD around the Median prediction.                          InterBias = MV16_INTER_BIAS;
1259     MinSAD=SAD                          if (pMB->quant > 8)  InterBias += 100 * (pMB->quant - 8); // to make high quants work
1260     If Motion Vector equal to Previous frame motion vector                          if (y != 0)
1261     and MinSAD<PrevFrmSAD goto Step 10.                                  if ((pMB - pParam->mb_width)->mode == MODE_INTRA ) InterBias -= 80;
1262     If SAD<=256 goto Step 10.                          if (x != 0)
1263  */                                  if ((pMB - 1)->mode == MODE_INTRA ) InterBias -= 80;
1264    
1265          currMV->x = start_x;                          if (Data.chroma) InterBias += 50; // to compensate bigger SAD
         currMV->y = start_y;  
1266    
1267          if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */                          if (InterBias < pMB->sad16)  {
1268                  currMV->x = EVEN(currMV->x);                                  const int32_t deviation =
1269                  currMV->y = EVEN(currMV->y);                                          dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,
1270          }                                                    pParam->edged_width);
1271    
1272          if (currMV->x > max_dx) {                                  if (deviation < (pMB->sad16 - InterBias)) {
1273                  currMV->x = max_dx;                                          if (++iIntra >= iLimit) { free(qimage); return 1; }
1274                                            pMB->mode = MODE_INTRA;
1275                                            pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =
1276                                                            pMB->mvs[3] = zeroMV;
1277                                            pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] =
1278                                                            pMB->qmvs[3] = zeroMV;
1279                                            pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =
1280                                                    pMB->sad8[3] = 0;
1281          }          }
         if (currMV->x < min_dx) {  
                 currMV->x = min_dx;  
1282          }          }
         if (currMV->y > max_dy) {  
                 currMV->y = max_dy;  
1283          }          }
         if (currMV->y < min_dy) {  
                 currMV->y = min_dy;  
1284          }          }
1285            free(qimage);
1286    
1287            if (current->coding_type == S_VOP)      /* first GMC step only for S(GMC)-VOPs */
1288                    current->GMC_MV = GlobalMotionEst( pMBs, pParam, current->fcode );
1289            else
1290                    current->GMC_MV = zeroMV;
1291    
1292            return 0;
1293    }
1294    
1295    
1296          iMinSAD =  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)
                 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);  
1297    
1298          if ((iMinSAD < 256) ||  static __inline int
1299                  ((MVequal(*currMV, prevMB->mvs[0])) &&  make_mask(const VECTOR * const pmv, const int i)
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
1300                  {                  {
1301                          if (!MVzero(*currMV)) {          int mask = 255, j;
1302                                  iMinSAD += MV16_00_BIAS;          for (j = 0; j < i; j++) {
1303                                  CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures                  if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already
1304                                  iMinSAD -= MV16_00_BIAS;                  if (pmv[i].x == pmv[j].x) {
1305                            if (pmv[i].y == pmv[j].y + iDiamondSize) { mask &= ~4; continue; }
1306                            if (pmv[i].y == pmv[j].y - iDiamondSize) { mask &= ~8; continue; }
1307                    } else
1308                            if (pmv[i].y == pmv[j].y) {
1309                                    if (pmv[i].x == pmv[j].x + iDiamondSize) { mask &= ~1; continue; }
1310                                    if (pmv[i].x == pmv[j].x - iDiamondSize) { mask &= ~2; continue; }
1311                          }                          }
1312                  }                  }
1313            return mask;
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
1314          }          }
1315    
1316    static __inline void
1317    PreparePredictionsP(VECTOR * const pmv, int x, int y, const int iWcount,
1318                            const int iHcount, const MACROBLOCK * const prevMB)
1319    {
1320    
1321  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself
    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;  
1322    
1323  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          if ( (y != 0) && (x != (iWcount-1)) ) {         // [5] top-right neighbour
1324     Otherwise select large Diamond Search.                  pmv[5].x = EVEN(pmv[3].x);
1325  */                  pmv[5].y = EVEN(pmv[3].y);
1326            } else pmv[5].x = pmv[5].y = 0;
1327    
1328          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))          if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }// pmv[3] is left neighbour
1329                  iDiamondSize = 1;               // halfpel!          else pmv[3].x = pmv[3].y = 0;
         else  
                 iDiamondSize = 2;               // halfpel!  
1330    
1331          if (!(MotionFlags & PMV_HALFPELDIAMOND16))          if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }// [4] top neighbour
1332                  iDiamondSize *= 2;      else pmv[4].x = pmv[4].y = 0;
1333    
1334  /*          // [1] median prediction
1335     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.          pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
    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.  
 */  
1336    
1337  // (0,0) is always possible          pmv[0].x = pmv[0].y = 0; // [0] is zero; not used in the loop (checked before) but needed here for make_mask
1338    
1339          if (!MVzero(pmv[0]))          pmv[2].x = EVEN(prevMB->mvs[0].x); // [2] is last frame
1340                  CHECK_MV16_ZERO;          pmv[2].y = EVEN(prevMB->mvs[0].y);
1341    
1342  // previous frame MV is always possible          if ((x != iWcount-1) && (y != iHcount-1)) {
1343                    pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); //[6] right-down neighbour in last frame
1344                    pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
1345            } else pmv[6].x = pmv[6].y = 0;
1346    }
1347    
1348          if (!MVzero(prevMB->mvs[0]))  static void
1349                  if (!MVequal(prevMB->mvs[0], pmv[0]))  SearchP(const IMAGE * const pRef,
1350                          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);                  const uint8_t * const pRefH,
1351                    const uint8_t * const pRefV,
1352                    const uint8_t * const pRefHV,
1353                    const IMAGE * const pCur,
1354                    const int x,
1355                    const int y,
1356                    const uint32_t MotionFlags,
1357                    const uint32_t iQuant,
1358                    SearchData * const Data,
1359                    const MBParam * const pParam,
1360                    const MACROBLOCK * const pMBs,
1361                    const MACROBLOCK * const prevMBs,
1362                    int inter4v,
1363                    MACROBLOCK * const pMB)
1364    {
1365    
1366  // left neighbour, if allowed          int i, iDirection = 255, mask, threshA;
1367            VECTOR pmv[7];
1368    
1369          if (!MVzero(pmv[1]))          get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);  //has to be changed to get_pmv(2)()
1370                  if (!MVequal(pmv[1], prevMB->mvs[0]))          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1371                          if (!MVequal(pmv[1], pmv[0])) {                                  pParam->width, pParam->height, Data->iFcode, pParam->m_quarterpel);
                                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                                         pmv[1].x = EVEN(pmv[1].x);  
                                         pmv[1].y = EVEN(pmv[1].y);  
                                 }  
1372    
1373                                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);          Data->predMV = pmv[0];
                         }  
 // 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);  
1374    
1375  // top right neighbour, if allowed          Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16;
1376                                          if (!MVzero(pmv[3]))          Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8;
1377                                                  if (!MVequal(pmv[3], prevMB->mvs[0]))          Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8;
                                                         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);  
                                                                         }  
                                 }  
1378    
1379          if ((MVzero(*currMV)) &&          Data->Ref = pRef->y + (x + Data->iEdgedWidth*y) * 16;
1380                  (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )          Data->RefH = pRefH + (x + Data->iEdgedWidth*y) * 16;
1381                  iMinSAD -= MV16_00_BIAS;          Data->RefV = pRefV + (x + Data->iEdgedWidth*y) * 16;
1382            Data->RefHV = pRefHV + (x + Data->iEdgedWidth*y) * 16;
1383            Data->RefCV = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8;
1384            Data->RefCU = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8;
1385    
1386            Data->lambda16 = lambda_vec16[iQuant];
1387            Data->lambda8 = lambda_vec8[iQuant];
1388    
1389  /* Step 6: If MinSAD <= thresa goto Step 10.          if (!(MotionFlags & PMV_HALFPEL16)) {
1390     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.                  Data->min_dx = EVEN(Data->min_dx);
1391  */                  Data->max_dx = EVEN(Data->max_dx);
1392                    Data->min_dy = EVEN(Data->min_dy);
1393                    Data->max_dy = EVEN(Data->max_dy); }
1394    
1395            if (pMB->dquant != NO_CHANGE) inter4v = 0;
1396    
1397            for(i = 0;  i < 5; i++)
1398                    Data->currentMV[i].x = Data->currentMV[i].y = 0;
1399    
1400            if (pParam->m_quarterpel) {
1401                    Data->predQMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1402                    i = d_mv_bits(Data->predQMV.x, Data->predQMV.y, Data->iFcode);
1403            } else i = d_mv_bits(Data->predMV.x, Data->predMV.y, Data->iFcode);
1404    
1405            Data->iMinSAD[0] = pMB->sad16 + (Data->lambda16 * i * pMB->sad16)/1000;
1406            Data->iMinSAD[1] = pMB->sad8[0] + (Data->lambda8 * i * (pMB->sad8[0]+NEIGH_8X8_BIAS))/100;
1407            Data->iMinSAD[2] = pMB->sad8[1];
1408            Data->iMinSAD[3] = pMB->sad8[2];
1409            Data->iMinSAD[4] = pMB->sad8[3];
1410    
1411          if ((iMinSAD <= threshA) ||          if ((x == 0) && (y == 0)) threshA = 512;
1412                  (MVequal(*currMV, prevMB->mvs[0]) &&          else {
1413                   ((int32_t) iMinSAD < prevMB->sad16))) {                  threshA = Data->temp[0]; // that's when we keep this SAD atm
1414                  if (MotionFlags & PMV_QUICKSTOP16)                  if (threshA < 512) threshA = 512;
1415                          goto PMVfast16_Terminate_without_Refine;                  if (threshA > 1024) threshA = 1024; }
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
         }  
1416    
1417            PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
1418                                            prevMBs + x + y * pParam->mb_width);
1419    
1420  /************ (Diamond Search)  **************/          if (inter4v || pParam->m_quarterpel || Data->chroma) CheckCandidate = CheckCandidate16;
1421  /*          else CheckCandidate = CheckCandidate16no4v;
    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.  
 */  
1422    
1423          if (MotionFlags & PMV_USESQUARES16)  /* main loop. checking all predictions */
                 MainSearchPtr = Square16_MainSearch;  
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
1424    
1425          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          for (i = 1; i < 7; i++) {
1426                    if (!(mask = make_mask(pmv, i)) ) continue;
1427                    (*CheckCandidate)(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1428                    if (Data->iMinSAD[0] <= threshA) break;
1429            }
1430    
1431            if ((Data->iMinSAD[0] <= threshA) ||
1432                            (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
1433                            (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16))) {
1434                    inter4v = 0;
1435            } else {
1436    
1437  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                  MainSearchFunc * MainSearchPtr;
1438          iSAD =                  if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1439                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                  else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1440                                                    currMV->x, currMV->y, iMinSAD, &newMV, center_x, center_y,                          else MainSearchPtr = DiamondSearch;
1441                                                    min_dx, max_dx,  
1442                                                    min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,                  (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
1443                                                    iQuant, iFound);  
1444    /* extended search, diamond starting in 0,0 and in prediction.
1445          if (iSAD < iMinSAD) {          note that this search is/might be done in halfpel positions,
1446                  *currMV = newMV;          which makes it more different than the diamond above */
                 iMinSAD = iSAD;  
         }  
1447    
1448          if (MotionFlags & PMV_EXTSEARCH16) {          if (MotionFlags & PMV_EXTSEARCH16) {
1449  /* extended: search (up to) two more times: orignal prediction and (0,0) */                          int32_t bSAD;
1450                            VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
1451                            if (!(MotionFlags & PMV_HALFPELREFINE16)) // who's gonna use extsearch and no halfpel?
1452                                    startMV.x = EVEN(startMV.x); startMV.y = EVEN(startMV.y);
1453                            if (!(MVequal(startMV, backupMV))) {
1454                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1455    
1456                  if (!(MVequal(pmv[0], backupMV))) {                                  (*CheckCandidate)(startMV.x, startMV.y, 255, &iDirection, Data);
1457                          iSAD =                                  (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
1458                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                  if (bSAD < Data->iMinSAD[0]) {
1459                                                                    center_x, center_y, iMinSAD, &newMV, center_x, center_y,                                          Data->currentMV[0] = backupMV;
1460                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,                                          Data->iMinSAD[0] = bSAD; }
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
1461                  }                  }
1462    
1463                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                          backupMV = Data->currentMV[0];
1464                          iSAD =                          if (MotionFlags & PMV_HALFPELREFINE16) startMV.x = startMV.y = 1;
1465                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                          else startMV.x = startMV.y = 0;
1466                                                                    iMinSAD, &newMV, center_x, center_y,                          if (!(MVequal(startMV, backupMV))) {
1467                                                                    min_dx, max_dx, min_dy, max_dy,                                  bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
                                                                   iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
1468    
1469                          if (iSAD < iMinSAD) {                                  (*CheckCandidate)(startMV.x, startMV.y, 255, &iDirection, Data);
1470                                  *currMV = newMV;                                  (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
1471                                  iMinSAD = iSAD;                                  if (bSAD < Data->iMinSAD[0]) {
1472                                            Data->currentMV[0] = backupMV;
1473                                            Data->iMinSAD[0] = bSAD; }
1474                          }                          }
1475                  }                  }
1476          }          }
1477    
1478  /*          if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(Data);
1479     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  
1480  */          for(i = 0; i < 5; i++) {
1481                    Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // initialize qpel vectors
1482                    Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
1483            }
1484    
1485            if((pParam->m_quarterpel) && (MotionFlags & PMV_QUARTERPELREFINE16)) {
1486    
1487    PMVfast16_Terminate_with_Refine:                  CheckCandidate = CheckCandidate16_qpel;
1488          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1489                  iMinSAD =                                  pParam->width, pParam->height, Data->iFcode, 0);
                         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);  
1490    
1491    PMVfast16_Terminate_without_Refine:                  QuarterpelRefine(Data);
         currPMV->x = currMV->x - center_x;  
         currPMV->y = currMV->y - center_y;  
         return iMinSAD;  
1492  }  }
1493    
1494            if (Data->iMinSAD[0] < (int32_t)iQuant * 30 ) inter4v = 0;
1495            if (inter4v) {
1496                    SearchData Data8;
1497                    Data8.iFcode = Data->iFcode;
1498                    Data8.lambda8 = Data->lambda8;
1499                    Data8.iEdgedWidth = Data->iEdgedWidth;
1500                    Data8.RefQ = Data->RefQ;
1501                    Data8.qpel = Data->qpel;
1502                    Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
1503                    Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
1504                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
1505                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
1506    
1507                    if (Data->chroma) {
1508                            int sum, dx, dy;
1509    
1510                            if(pParam->m_quarterpel) {
1511                                    sum = pMB->qmvs[0].y/2 + pMB->qmvs[1].y/2 + pMB->qmvs[2].y/2 + pMB->qmvs[3].y/2;
1512                            } else sum = pMB->mvs[0].y + pMB->mvs[1].y + pMB->mvs[2].y + pMB->mvs[3].y;
1513                            dy = (sum >> 3) + roundtab_76[sum & 0xf];
1514    
1515                            if(pParam->m_quarterpel) {
1516                                    sum = pMB->qmvs[0].x/2 + pMB->qmvs[1].x/2 + pMB->qmvs[2].x/2 + pMB->qmvs[3].x/2;
1517                            } else sum = pMB->mvs[0].x + pMB->mvs[1].x + pMB->mvs[2].x + pMB->mvs[3].x;
1518                            dx = (sum >> 3) + roundtab_76[sum & 0xf];
1519    
1520                            Data->iMinSAD[1] += ChromaSAD(dx, dy, Data);
1521                    }
1522            }
1523    
1524  int32_t          if (!(inter4v) ||
1525  Diamond8_MainSearch(const uint8_t * const pRef,                  (Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
1526                                          const uint8_t * const pRefH,                          Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {
1527                                          const uint8_t * const pRefV,  // INTER MODE
1528                                          const uint8_t * const pRefHV,                  pMB->mode = MODE_INTER;
1529                                          const uint8_t * const cur,                  pMB->mvs[0] = pMB->mvs[1]
1530                                          const int x,                          = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
                                         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);  
1531    
1532          if (iDirection) {                  pMB->qmvs[0] = pMB->qmvs[1]
1533                  while (!iFound) {                          = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1534                          iFound = 1;  
1535                          backupMV = *currMV;     // since iDirection!=0, this is well defined!                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
1536                          iDirectionBackup = iDirection;                          pMB->sad8[2] = pMB->sad8[3] =  Data->iMinSAD[0];
1537    
1538                          if (iDirectionBackup != 2)                  if(pParam->m_quarterpel) {
1539                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predQMV.x;
1540                                                                                    backupMV.y, 1);                          pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predQMV.y;
1541                          if (iDirectionBackup != 1)                  } else {
1542                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                          pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1543                                                                                    backupMV.y, 2);                          pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
                         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);  
1544                  }                  }
1545          } else {          } else {
1546                  currMV->x = start_x;  // INTER4V MODE; all other things are already set in Search8
1547                  currMV->y = start_y;                  pMB->mode = MODE_INTER4V;
1548                    pMB->sad16 = Data->iMinSAD[1] + Data->iMinSAD[2] +
1549                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * iQuant;
1550          }          }
         return iMinSAD;  
1551  }  }
1552    
1553    static void
1554    Search8(const SearchData * const OldData,
1555                    const int x, const int y,
1556                    const uint32_t MotionFlags,
1557                    const MBParam * const pParam,
1558                    MACROBLOCK * const pMB,
1559                    const MACROBLOCK * const pMBs,
1560                    const int block,
1561                    SearchData * const Data)
1562    {
1563            Data->iMinSAD = OldData->iMinSAD + 1 + block;
1564            Data->currentMV = OldData->currentMV + 1 + block;
1565            Data->currentQMV = OldData->currentQMV + 1 + block;
1566    
1567            if(pParam->m_quarterpel) {
1568                    Data->predQMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2 , y/2, block);
1569                    if (block != 0) *(Data->iMinSAD) += (Data->lambda8 *
1570                                                                            d_mv_bits(      Data->currentQMV->x - Data->predQMV.x,
1571                                                                                                    Data->currentQMV->y - Data->predQMV.y,
1572                                                                                                    Data->iFcode) * (*Data->iMinSAD + NEIGH_8X8_BIAS))/100;
1573            } else {
1574                    Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2 , y/2, block);
1575                    if (block != 0) *(Data->iMinSAD) += (Data->lambda8 *
1576                                                                            d_mv_bits(      Data->currentMV->x - Data->predMV.x,
1577                                                                                                    Data->currentMV->y - Data->predMV.y,
1578                                                                                                    Data->iFcode) * (*Data->iMinSAD + NEIGH_8X8_BIAS))/100;
1579            }
1580    
1581            if (MotionFlags & (PMV_EXTSEARCH8|PMV_HALFPELREFINE8)) {
1582    
1583                    Data->Ref = OldData->Ref + 8 * ((block&1) + pParam->edged_width*(block>>1));
1584                    Data->RefH = OldData->RefH + 8 * ((block&1) + pParam->edged_width*(block>>1));
1585                    Data->RefV = OldData->RefV + 8 * ((block&1) + pParam->edged_width*(block>>1));
1586                    Data->RefHV = OldData->RefHV + 8 * ((block&1) + pParam->edged_width*(block>>1));
1587    
1588  int32_t                  Data->Cur = OldData->Cur + 8 * ((block&1) + pParam->edged_width*(block>>1));
 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);  
1589    
1590                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1591                                    pParam->width, pParam->height, OldData->iFcode, pParam->m_quarterpel);
1592                    CheckCandidate = CheckCandidate8;
1593    
1594          if (iDirection) {                  if (MotionFlags & PMV_EXTSEARCH8) {
1595                  while (!iFound) {                          int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
                         iFound = 1;  
                         backupMV = *currMV;  
1596    
1597                          switch (iDirection) {                          MainSearchFunc *MainSearchPtr;
1598                          case 1:                          if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
1599                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                                  else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1600                                                                                     backupMV.y, 1);                                          else MainSearchPtr = DiamondSearch;
                                 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;  
1601    
1602                          case 3:                          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);
                                 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;  
1603    
1604                          case 4:                          if(*(Data->iMinSAD) < temp_sad) {
1605                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,                                          Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1606                                                                                   3);                                          Data->currentQMV->y = 2 * Data->currentMV->y;
1607                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          }
1608                                                                                   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);  
1609    
1610                                  break;                  if (MotionFlags & PMV_HALFPELREFINE8) {
1611                            int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
1612    
1613                          case 7:                          HalfpelRefine(Data); // perform halfpel refine of current best vector
                                 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;  
1614    
1615                          case 8:                          if(*(Data->iMinSAD) < temp_sad) { // we have found a better match
1616                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,                                  Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1617                                                                                   2);                                  Data->currentQMV->y = 2 * Data->currentMV->y;
                                 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;  
1618                          }                          }
1619                  }                  }
1620          } else {  
1621                  currMV->x = start_x;                  if(pParam->m_quarterpel) {
1622                  currMV->y = start_y;                          if((!(Data->currentQMV->x & 1)) && (!(Data->currentQMV->y & 1)) &&
1623                                    (MotionFlags & PMV_QUARTERPELREFINE8)) {
1624                            CheckCandidate = CheckCandidate8_qpel;
1625                            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1626                                    pParam->width, pParam->height, OldData->iFcode, pParam->m_quarterpel);
1627                            QuarterpelRefine(Data);
1628                            }
1629          }          }
         return iMinSAD;  
1630  }  }
1631    
1632            if(pParam->m_quarterpel) {
1633                    pMB->pmvs[block].x = Data->currentQMV->x - Data->predQMV.x;
1634                    pMB->pmvs[block].y = Data->currentQMV->y - Data->predQMV.y;
1635            }
1636            else {
1637                    pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1638                    pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
1639            }
1640    
1641            pMB->mvs[block] = *(Data->currentMV);
1642            pMB->qmvs[block] = *(Data->currentQMV);
1643    
1644            pMB->sad8[block] =  4 * (*Data->iMinSAD);
1645    }
1646    
1647    /* B-frames code starts here */
1648    
1649  int32_t  static __inline VECTOR
1650  Halfpel8_Refine_c(const uint8_t * const pRef,  ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
                                 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)  
1651  {  {
1652  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  /* the stupidiest function ever */
1653            if (mode == MODE_FORWARD) return pMB->mvs[0];
1654            else return pMB->b_mvs[0];
1655    }
1656    
1657          int32_t iSAD;  static void __inline
1658          VECTOR backupMV = *currMV;  PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
1659                                                            const uint32_t iWcount,
1660                                                            const MACROBLOCK * const pMB,
1661                                                            const uint32_t mode_curr)
1662    {
1663    
1664          CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y - 1);          // [0] is prediction
1665          CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y - 1);          pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
         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);  
1666    
1667          return iMinSAD;          pmv[1].x = pmv[1].y = 0; // [1] is zero
1668  }  
1669            pmv[2] = ChoosePred(pMB, mode_curr);
1670            pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
1671    
1672            if ((y != 0)&&(x != (int)(iWcount+1))) {                        // [3] top-right neighbour
1673                    pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
1674                    pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
1675            } else pmv[3].x = pmv[3].y = 0;
1676    
1677            if (y != 0) {
1678                    pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
1679                    pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
1680            } else pmv[4].x = pmv[4].y = 0;
1681    
1682            if (x != 0) {
1683                    pmv[5] = ChoosePred(pMB-1, mode_curr);
1684                    pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1685            } else pmv[5].x = pmv[5].y = 0;
1686    
1687            if ((x != 0)&&(y != 0)) {
1688                    pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
1689                    pmv[6].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1690            } else pmv[6].x = pmv[6].y = 0;
1691    
1692    // more?
1693    }
1694    
 #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)  
1695    
1696  int32_t  /* search backward or forward, for b-frames */
1697  PMVfastSearch8(const uint8_t * const pRef,  static void
1698    SearchBF(       const uint8_t * const pRef,
1699                             const uint8_t * const pRefH,                             const uint8_t * const pRefH,
1700                             const uint8_t * const pRefV,                             const uint8_t * const pRefV,
1701                             const uint8_t * const pRefHV,                             const uint8_t * const pRefHV,
1702                             const IMAGE * const pCur,                             const IMAGE * const pCur,
1703                             const int x,                          const int x, const int y,
                            const int y,  
                            const int start_x,  
                            const int start_y,  
                                 const int center_x,  
                                 const int center_y,  
1704                             const uint32_t MotionFlags,                             const uint32_t MotionFlags,
                            const uint32_t iQuant,  
1705                             const uint32_t iFcode,                             const uint32_t iFcode,
1706                             const MBParam * const pParam,                             const MBParam * const pParam,
1707                             const MACROBLOCK * const pMBs,                          MACROBLOCK * const pMB,
1708                             const MACROBLOCK * const prevMBs,                          const VECTOR * const predMV,
1709                             VECTOR * const currMV,                          int32_t * const best_sad,
1710                             VECTOR * const currPMV)                          const int32_t mode_current,
1711                            SearchData * const Data)
1712  {  {
         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;  
   
         int32_t iDiamondSize;  
   
         int32_t min_dx;  
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
1713    
1714          VECTOR pmv[4];          const int32_t iEdgedWidth = pParam->edged_width;
         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;  
1715    
1716          int32_t iSubBlock = (y & 1) + (y & 1) + (x & 1);          int i, iDirection, mask;
1717            VECTOR pmv[7];
1718            MainSearchFunc *MainSearchPtr;
1719            *Data->iMinSAD = MV_MAX_ERROR;
1720            Data->iFcode = iFcode;
1721    
1722            Data->Ref = pRef + (x + y * iEdgedWidth) * 16;
1723            Data->RefH = pRefH + (x + y * iEdgedWidth) * 16;
1724            Data->RefV = pRefV + (x + y * iEdgedWidth) * 16;
1725            Data->RefHV = pRefHV + (x + y * iEdgedWidth) * 16;
1726    
1727            Data->predMV = *predMV;
1728    
1729            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1730                                    pParam->width, pParam->height, iFcode, pParam->m_quarterpel);
1731    
1732            pmv[0] = Data->predMV;
1733            if (Data->qpel) { pmv[0].x /= 2; pmv[0].y /= 2; }
1734            PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);
1735    
1736            Data->currentMV->x = Data->currentMV->y = 0;
1737    
1738            CheckCandidate = CheckCandidate16no4v;
1739    
1740    // main loop. checking all predictions
1741            for (i = 0; i < 8; i++) {
1742                    if (!(mask = make_mask(pmv, i)) ) continue;
1743                    CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1744            }
1745    
1746          MainSearch8FuncPtr MainSearchPtr;          if (MotionFlags & PMV_USESQUARES16)
1747                    MainSearchPtr = SquareSearch;
1748            else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
1749                    MainSearchPtr = AdvDiamondSearch;
1750                    else MainSearchPtr = DiamondSearch;
1751    
1752          /* Init variables */          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);
         startMV.x = start_x;  
         startMV.y = start_y;  
1753    
1754          /* Get maximum range */          HalfpelRefine(Data);
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,  
                           iFcode);  
1755    
1756          if (!(MotionFlags & PMV_HALFPELDIAMOND8)) {          if (Data->qpel) {
1757                  min_dx = EVEN(min_dx);                  Data->currentQMV->x = 2*Data->currentMV->x;
1758                  max_dx = EVEN(max_dx);                  Data->currentQMV->y = 2*Data->currentMV->y;
1759                  min_dy = EVEN(min_dy);                  CheckCandidate = CheckCandidate16no4v_qpel;
1760                  max_dy = EVEN(max_dy);                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1761                                            pParam->width, pParam->height, iFcode, pParam->m_quarterpel);
1762                    QuarterpelRefine(Data);
1763            }
1764    
1765    // three bits are needed to code backward mode. four for forward
1766    // we treat the bits just like they were vector's
1767            if (mode_current == MODE_FORWARD) *Data->iMinSAD +=  4 * Data->lambda16;
1768            else *Data->iMinSAD +=  3 * Data->lambda16;
1769    
1770            if (*Data->iMinSAD < *best_sad) {
1771                    *best_sad = *Data->iMinSAD;
1772                    pMB->mode = mode_current;
1773                    if (Data->qpel) {
1774                            pMB->pmvs[0].x = Data->currentQMV->x - predMV->x;
1775                            pMB->pmvs[0].y = Data->currentQMV->y - predMV->y;
1776                            if (mode_current == MODE_FORWARD)
1777                                    pMB->qmvs[0] = *Data->currentQMV;
1778                            else
1779                                    pMB->b_qmvs[0] = *Data->currentQMV;
1780                    } else {
1781                            pMB->pmvs[0].x = Data->currentMV->x - predMV->x;
1782                            pMB->pmvs[0].y = Data->currentMV->y - predMV->y;
1783          }          }
1784                    if (mode_current == MODE_FORWARD)
1785                            pMB->mvs[0] = *(Data->currentMV+2) = *Data->currentMV;
1786                    else
1787                            pMB->b_mvs[0] = *(Data->currentMV+1) = *Data->currentMV; //we store currmv for interpolate search
1788    
1789          /* because we might use IF (dx>max_dx) THEN dx=max_dx; */          }
         //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);  
1790    
1791          if ((x == 0) && (y == 0)) {  }
                 threshA = 512 / 4;  
                 threshB = 1024 / 4;  
1792    
1793          } else {  static int32_t
1794                  threshA = psad[0] / 4;  /* good estimate? */  SearchDirect(const IMAGE * const f_Ref,
1795                  threshB = threshA + 256 / 4;                                  const uint8_t * const f_RefH,
1796                  if (threshA < 512 / 4)                                  const uint8_t * const f_RefV,
1797                          threshA = 512 / 4;                                  const uint8_t * const f_RefHV,
1798                  if (threshA > 1024 / 4)                                  const IMAGE * const b_Ref,
1799                          threshA = 1024 / 4;                                  const uint8_t * const b_RefH,
1800                  if (threshB > 1792 / 4)                                  const uint8_t * const b_RefV,
1801                          threshB = 1792 / 4;                                  const uint8_t * const b_RefHV,
1802          }                                  const IMAGE * const pCur,
1803                                    const int x, const int y,
1804          iFound = 0;                                  const uint32_t MotionFlags,
1805                                    const int32_t TRB, const int32_t TRD,
1806  /* Step 4: Calculate SAD around the Median prediction.                                  const MBParam * const pParam,
1807     MinSAD=SAD                                  MACROBLOCK * const pMB,
1808     If Motion Vector equal to Previous frame motion vector                                  const MACROBLOCK * const b_mb,
1809     and MinSAD<PrevFrmSAD goto Step 10.                                  int32_t * const best_sad,
1810     If SAD<=256 goto Step 10.                                  SearchData * const Data)
1811  */  
1812    {
1813            int32_t skip_sad;
1814            int k;
1815    
1816            MainSearchFunc *MainSearchPtr;
1817    
1818            *Data->iMinSAD = 256*4096;
1819    
1820            Data->Ref = f_Ref->y + (x + Data->iEdgedWidth*y) * 16;
1821            Data->RefH = f_RefH + (x + Data->iEdgedWidth*y) * 16;
1822            Data->RefV = f_RefV + (x + Data->iEdgedWidth*y) * 16;
1823            Data->RefHV = f_RefHV + (x + Data->iEdgedWidth*y) * 16;
1824            Data->bRef = b_Ref->y + (x + Data->iEdgedWidth*y) * 16;
1825            Data->bRefH = b_RefH + (x + Data->iEdgedWidth*y) * 16;
1826            Data->bRefV = b_RefV + (x + Data->iEdgedWidth*y) * 16;
1827            Data->bRefHV = b_RefHV + (x + Data->iEdgedWidth*y) * 16;
1828    
1829            Data->max_dx = 2 * pParam->width - 2 * (x) * 16;
1830            Data->max_dy = 2 * pParam->height - 2 * (y) * 16;
1831            Data->min_dx = -(2 * 16 + 2 * (x) * 16);
1832            Data->min_dy = -(2 * 16 + 2 * (y) * 16);
1833            if (Data->qpel) { //we measure in qpixels
1834                    Data->max_dx *= 2;
1835                    Data->max_dy *= 2;
1836                    Data->min_dx *= 2;
1837                    Data->min_dy *= 2;
1838                    Data->referencemv = b_mb->qmvs;
1839            } else Data->referencemv = b_mb->mvs;
1840    
1841            for (k = 0; k < 4; k++) {
1842                    pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);
1843                    pMB->b_mvs[k].x = Data->directmvB[k].x = ((TRB - TRD) * Data->referencemv[k].x) / TRD;
1844                    pMB->mvs[k].y = Data->directmvF[k].y = ((TRB * Data->referencemv[k].y) / TRD);
1845                    pMB->b_mvs[k].y = Data->directmvB[k].y = ((TRB - TRD) * Data->referencemv[k].y) / TRD;
1846    
1847                    if ( ( pMB->b_mvs[k].x > Data->max_dx ) || ( pMB->b_mvs[k].x < Data->min_dx )
1848                            || ( pMB->b_mvs[k].y > Data->max_dy ) || ( pMB->b_mvs[k].y < Data->min_dy )) {
1849    
1850                            *best_sad = 256*4096; // in that case, we won't use direct mode
1851                            pMB->mode = MODE_DIRECT; // just to make sure it doesn't say "MODE_DIRECT_NONE_MV"
1852                            pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;
1853                            return 0;
1854                    }
1855                    if (b_mb->mode != MODE_INTER4V) {
1856                            pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mvs[0];
1857                            pMB->b_mvs[1] = pMB->b_mvs[2] = pMB->b_mvs[3] = pMB->b_mvs[0];
1858                            Data->directmvF[1] = Data->directmvF[2] = Data->directmvF[3] = Data->directmvF[0];
1859                            Data->directmvB[1] = Data->directmvB[2] = Data->directmvB[3] = Data->directmvB[0];
1860                            break;
1861                    }
1862            }
1863    
1864  // Prepare for main loop          if (Data->qpel) {
1865                            if (b_mb->mode == MODE_INTER4V)
1866                    CheckCandidate = CheckCandidateDirect_qpel;
1867                            else CheckCandidate = CheckCandidateDirectno4v_qpel;
1868            } else {
1869                            if (b_mb->mode == MODE_INTER4V) CheckCandidate = CheckCandidateDirect;
1870                            else CheckCandidate = CheckCandidateDirectno4v;
1871            }
1872    
1873    if (MotionFlags & PMV_USESQUARES8)          (*CheckCandidate)(0, 0, 255, &k, Data);
       MainSearchPtr = Square8_MainSearch;  
   else  
1874    
1875          if (MotionFlags & PMV_ADVANCEDDIAMOND8)  // skip decision
1876                  MainSearchPtr = AdvDiamond8_MainSearch;          if (*Data->iMinSAD < pMB->quant * SKIP_THRESH_B) {
1877          else                  //possible skip - checking chroma. everything copied from MC
1878                  MainSearchPtr = Diamond8_MainSearch;                  //this is not full chroma compensation, only it's fullpel approximation. should work though
1879                    int sum, dx, dy, b_dx, b_dy;
1880    
1881                    if (Data->qpel) {
1882                            sum = pMB->mvs[0].y/2 + pMB->mvs[1].y/2 + pMB->mvs[2].y/2 + pMB->mvs[3].y/2;
1883                            dy = (sum >> 3) + roundtab_76[sum & 0xf];
1884                            sum = pMB->mvs[0].x/2 + pMB->mvs[1].x/2 + pMB->mvs[2].x/2 + pMB->mvs[3].x/2;
1885                            dx = (sum >> 3) + roundtab_76[sum & 0xf];
1886    
1887                            sum = pMB->b_mvs[0].y/2 + pMB->b_mvs[1].y/2 + pMB->b_mvs[2].y/2 + pMB->b_mvs[3].y/2;
1888                            b_dy = (sum >> 3) + roundtab_76[sum & 0xf];
1889                            sum = pMB->b_mvs[0].x/2 + pMB->b_mvs[1].x/2 + pMB->b_mvs[2].x/2 + pMB->b_mvs[3].x/2;
1890                            b_dx = (sum >> 3) + roundtab_76[sum & 0xf];
1891    
1892                    } else {
1893                            sum = pMB->mvs[0].x + pMB->mvs[1].x + pMB->mvs[2].x + pMB->mvs[3].x;
1894                            dx = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1895                            sum = pMB->mvs[0].y + pMB->mvs[1].y + pMB->mvs[2].y + pMB->mvs[3].y;
1896                            dy = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1897    
1898          *currMV = startMV;                          sum = pMB->b_mvs[0].x + pMB->b_mvs[1].x + pMB->b_mvs[2].x + pMB->b_mvs[3].x;
1899                            b_dx = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1900                            sum = pMB->b_mvs[0].y + pMB->b_mvs[1].y + pMB->b_mvs[2].y + pMB->b_mvs[3].y;
1901                            b_dy = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1902                    }
1903                    sum = sad8bi(pCur->u + 8*x + 8*y*(Data->iEdgedWidth/2),
1904                                            f_Ref->u + (y*8 + dy/2) * (Data->iEdgedWidth/2) + x*8 + dx/2,
1905                                            b_Ref->u + (y*8 + b_dy/2) * (Data->iEdgedWidth/2) + x*8 + b_dx/2,
1906                                            Data->iEdgedWidth/2);
1907                    sum += sad8bi(pCur->v + 8*x + 8*y*(Data->iEdgedWidth/2),
1908                                            f_Ref->v + (y*8 + dy/2) * (Data->iEdgedWidth/2) + x*8 + dx/2,
1909                                            b_Ref->v + (y*8 + b_dy/2) * (Data->iEdgedWidth/2) + x*8 + b_dx/2,
1910                                            Data->iEdgedWidth/2);
1911    
1912          iMinSAD =                  if (sum < MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) {
1913                  sad8(cur,                          pMB->mode = MODE_DIRECT_NONE_MV;
1914                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,                          return *Data->iMinSAD;
1915                                                  iEdgedWidth), iEdgedWidth);                  }
1916          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.  
 */  
1917    
1918          if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))          skip_sad = *Data->iMinSAD;
                 iDiamondSize = 1;               // 1 halfpel!  
         else  
                 iDiamondSize = 2;               // 2 halfpel = 1 full pixel!  
1919    
1920          if (!(MotionFlags & PMV_HALFPELDIAMOND8))  //  DIRECT MODE DELTA VECTOR SEARCH.
1921                  iDiamondSize *= 2;  //      This has to be made more effective, but at the moment I'm happy it's running at all
1922    
1923            if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1924                    else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1925                            else MainSearchPtr = DiamondSearch;
1926    
1927  /*          (*MainSearchPtr)(0, 0, Data, 255);
    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;  
         }  
1928    
1929          if (MotionFlags & PMV_EXTSEARCH8) {          HalfpelRefine(Data); //or qpel refine, if we're in qpel mode
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
1930    
1931                  if (!(MVequal(pmv[0], backupMV))) {          *Data->iMinSAD +=  1 * Data->lambda16; // one bit is needed to code direct mode
1932                          iSAD =          *best_sad = *Data->iMinSAD;
                                 (*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);  
1933    
1934                          if (iSAD < iMinSAD) {          if (b_mb->mode == MODE_INTER4V)
1935                                  *currMV = newMV;                  pMB->mode = MODE_DIRECT;
1936                                  iMinSAD = iSAD;          else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation
                         }  
                 }  
1937    
1938                  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);  
1939    
1940                          if (iSAD < iMinSAD) {          for (k = 0; k < 4; k++) {
1941                                  *currMV = newMV;                  pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
1942                                  iMinSAD = iSAD;                  pMB->b_mvs[k].x = (     (Data->currentMV->x == 0)
1943                                                            ? Data->directmvB[k].x
1944                                                            :pMB->mvs[k].x - Data->referencemv[k].x);
1945                    pMB->mvs[k].y = (Data->directmvF[k].y + Data->currentMV->y);
1946                    pMB->b_mvs[k].y = ((Data->currentMV->y == 0)
1947                                                            ? Data->directmvB[k].y
1948                                                            : pMB->mvs[k].y - Data->referencemv[k].y);
1949                    if (Data->qpel) {
1950                            pMB->qmvs[k].x = pMB->mvs[k].x; pMB->mvs[k].x /= 2;
1951                            pMB->b_qmvs[k].x = pMB->b_mvs[k].x; pMB->b_mvs[k].x /= 2;
1952                            pMB->qmvs[k].y = pMB->mvs[k].y; pMB->mvs[k].y /= 2;
1953                            pMB->b_qmvs[k].y = pMB->b_mvs[k].y; pMB->b_mvs[k].y /= 2;
1954                    }
1955    
1956                    if (b_mb->mode != MODE_INTER4V) {
1957                            pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1958                            pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1959                            pMB->qmvs[3] = pMB->qmvs[2] = pMB->qmvs[1] = pMB->qmvs[0];
1960                            pMB->b_qmvs[3] = pMB->b_qmvs[2] = pMB->b_qmvs[1] = pMB->b_qmvs[0];
1961                            break;
1962                          }                          }
1963                  }                  }
1964            return skip_sad;
1965          }          }
1966    
 /* 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);  
   
1967    
1968    PMVfast8_Terminate_without_Refine:  static __inline void
1969          currPMV->x = currMV->x - center_x;  SearchInterpolate(const uint8_t * const f_Ref,
1970          currPMV->y = currMV->y - center_y;                                  const uint8_t * const f_RefH,
1971                                    const uint8_t * const f_RefV,
1972          return iMinSAD;                                  const uint8_t * const f_RefHV,
1973  }                                  const uint8_t * const b_Ref,
1974                                    const uint8_t * const b_RefH,
1975  int32_t                                  const uint8_t * const b_RefV,
1976  EPZSSearch16(const uint8_t * const pRef,                                  const uint8_t * const b_RefHV,
                          const uint8_t * const pRefH,  
                          const uint8_t * const pRefV,  
                          const uint8_t * const pRefHV,  
1977                           const IMAGE * const pCur,                           const IMAGE * const pCur,
1978                           const int x,                                  const int x, const int y,
1979                           const int y,                                  const uint32_t fcode,
1980                          const int start_x,                                  const uint32_t bcode,
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
1981                           const uint32_t MotionFlags,                           const uint32_t MotionFlags,
                          const uint32_t iQuant,  
                          const uint32_t iFcode,  
1982                           const MBParam * const pParam,                           const MBParam * const pParam,
1983                           const MACROBLOCK * const pMBs,                                  const VECTOR * const f_predMV,
1984                           const MACROBLOCK * const prevMBs,                                  const VECTOR * const b_predMV,
1985                           VECTOR * const currMV,                                  MACROBLOCK * const pMB,
1986                           VECTOR * const currPMV)                                  int32_t * const best_sad,
1987                                    SearchData * const fData)
1988    
1989  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const uint32_t iHcount = pParam->mb_height;  
1990    
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
1991          const int32_t iEdgedWidth = pParam->edged_width;          const int32_t iEdgedWidth = pParam->edged_width;
1992            int iDirection, i, j;
1993            SearchData bData;
1994    
1995          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          *(bData.iMinSAD = fData->iMinSAD) = 4096*256;
1996            bData.Cur = fData->Cur;
1997          int32_t min_dx;          fData->iEdgedWidth = bData.iEdgedWidth = iEdgedWidth;
1998          int32_t max_dx;          bData.currentMV = fData->currentMV + 1; bData.currentQMV = fData->currentQMV + 1;
1999          int32_t min_dy;          bData.lambda16 = fData->lambda16;
2000          int32_t max_dy;          fData->iFcode = bData.bFcode = fcode; fData->bFcode = bData.iFcode = bcode;
2001    
2002          VECTOR newMV;          bData.bRef = fData->Ref = f_Ref + (x + y * iEdgedWidth) * 16;
2003          VECTOR backupMV;          bData.bRefH = fData->RefH = f_RefH + (x + y * iEdgedWidth) * 16;
2004            bData.bRefV = fData->RefV = f_RefV + (x + y * iEdgedWidth) * 16;
2005          VECTOR pmv[4];          bData.bRefHV = fData->RefHV = f_RefHV + (x + y * iEdgedWidth) * 16;
2006          int32_t psad[8];          bData.Ref = fData->bRef = b_Ref + (x + y * iEdgedWidth) * 16;
2007            bData.RefH = fData->bRefH = b_RefH + (x + y * iEdgedWidth) * 16;
2008            bData.RefV = fData->bRefV = b_RefV + (x + y * iEdgedWidth) * 16;
2009            bData.RefHV = fData->bRefHV = b_RefHV + (x + y * iEdgedWidth) * 16;
2010            bData.RefQ = fData->RefQ;
2011    
2012            bData.bpredMV = fData->predMV = *f_predMV;
2013            fData->bpredMV = bData.predMV = *b_predMV;
2014    
2015            fData->currentMV[0] = fData->currentMV[2];
2016            get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode, pParam->m_quarterpel);
2017            get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode, pParam->m_quarterpel);
2018    
2019            if (fData->currentMV[0].x > fData->max_dx) fData->currentMV[0].x = fData->max_dx;
2020            if (fData->currentMV[0].x < fData->min_dx) fData->currentMV[0].x = fData->min_dy;
2021            if (fData->currentMV[0].y > fData->max_dy) fData->currentMV[0].y = fData->max_dx;
2022            if (fData->currentMV[0].y > fData->min_dy) fData->currentMV[0].y = fData->min_dy;
2023    
2024            if (fData->currentMV[1].x > bData.max_dx) fData->currentMV[1].x = bData.max_dx;
2025            if (fData->currentMV[1].x < bData.min_dx) fData->currentMV[1].x = bData.min_dy;
2026            if (fData->currentMV[1].y > bData.max_dy) fData->currentMV[1].y = bData.max_dx;
2027            if (fData->currentMV[1].y > bData.min_dy) fData->currentMV[1].y = bData.min_dy;
2028    
2029          static MACROBLOCK *oldMBs = NULL;          CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, 255, &iDirection, fData);
2030    
2031  //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;  //diamond. I wish we could use normal mainsearch functions (square, advdiamond)
         const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;  
         MACROBLOCK *oldMB = NULL;  
2032    
2033           int32_t thresh2;          do {
2034          int32_t bPredEq;                  iDirection = 255;
2035          int32_t iMinSAD, iSAD = 9999;                  // forward MV moves
2036                    i = fData->currentMV[0].x; j = fData->currentMV[0].y;
2037          MainSearch16FuncPtr MainSearchPtr;  
2038                    CheckCandidateInt(i + 1, j, 0, &iDirection, fData);
2039          if (oldMBs == NULL) {                  CheckCandidateInt(i, j + 1, 0, &iDirection, fData);
2040                  oldMBs = (MACROBLOCK *) calloc(iWcount * iHcount, sizeof(MACROBLOCK));                  CheckCandidateInt(i - 1, j, 0, &iDirection, fData);
2041  //      fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));                  CheckCandidateInt(i, j - 1, 0, &iDirection, fData);
2042          }  
2043          oldMB = oldMBs + x + y * iWcount;                  // backward MV moves
2044                    i = fData->currentMV[1].x; j = fData->currentMV[1].y;
2045  /* Get maximum range */                  fData->currentMV[2] = fData->currentMV[0];
2046          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,                  CheckCandidateInt(i + 1, j, 0, &iDirection, &bData);
2047                            iFcode);                  CheckCandidateInt(i, j + 1, 0, &iDirection, &bData);
2048                    CheckCandidateInt(i - 1, j, 0, &iDirection, &bData);
2049          if (!(MotionFlags & PMV_HALFPEL16)) {                  CheckCandidateInt(i, j - 1, 0, &iDirection, &bData);
2050                  min_dx = EVEN(min_dx);  
2051                  max_dx = EVEN(max_dx);          } while (!(iDirection));
2052                  min_dy = EVEN(min_dy);  
2053                  max_dy = EVEN(max_dy);          *fData->iMinSAD +=  2 * fData->lambda16; // two bits are needed to code interpolate mode.
2054          }  
2055          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */          if (fData->qpel) {
2056          //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);                  CheckCandidate = CheckCandidateInt_qpel;
2057          bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);                  get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode, 0);
2058                    get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode, 0);
2059  /* Step 4: Calculate SAD around the Median prediction.                  fData->currentQMV[2].x = fData->currentQMV[0].x = 2 * fData->currentMV[0].x;
2060          MinSAD=SAD                  fData->currentQMV[2].y = fData->currentQMV[0].y = 2 * fData->currentMV[0].y;
2061          If Motion Vector equal to Previous frame motion vector                  fData->currentQMV[1].x = 2 * fData->currentMV[1].x;
2062                  and MinSAD<PrevFrmSAD goto Step 10.                  fData->currentQMV[1].y = 2 * fData->currentMV[1].y;
2063          If SAD<=256 goto Step 10.  //              QuarterpelRefine(fData);
2064  */                  fData->currentQMV[2] = fData->currentQMV[0];
2065    //              QuarterpelRefine(&bData);
2066  // Prepare for main loop          }
2067    
2068          currMV->x = start_x;          if (*fData->iMinSAD < *best_sad) {
2069          currMV->y = start_y;                  *best_sad = *fData->iMinSAD;
2070                    pMB->mvs[0] = fData->currentMV[0];
2071          if (!(MotionFlags & PMV_HALFPEL16)) {                  pMB->b_mvs[0] = fData->currentMV[1];
2072                  currMV->x = EVEN(currMV->x);                  pMB->mode = MODE_INTERPOLATE;
2073                  currMV->y = EVEN(currMV->y);                  if (fData->qpel) {
2074          }                          pMB->qmvs[0] = fData->currentQMV[0];
2075                            pMB->b_qmvs[0] = fData->currentQMV[1];
2076          if (currMV->x > max_dx)                          pMB->pmvs[1].x = pMB->qmvs[0].x - f_predMV->x;
2077                  currMV->x = max_dx;                          pMB->pmvs[1].y = pMB->qmvs[0].y - f_predMV->y;
2078          if (currMV->x < min_dx)                          pMB->pmvs[0].x = pMB->b_qmvs[0].x - b_predMV->x;
2079                  currMV->x = min_dx;                          pMB->pmvs[0].y = pMB->b_qmvs[0].y - b_predMV->y;
         if (currMV->y > max_dy)  
                 currMV->y = max_dy;  
         if (currMV->y < min_dy)  
                 currMV->y = min_dy;  
   
 /***************** This is predictor SET A: only median prediction ******************/  
   
         iMinSAD =  
                 sad16(cur,  
                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
   
 // thresh1 is fixed to 256  
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
         }  
   
 /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/  
   
 // previous frame MV  
         CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);  
   
 // set threshhold based on Min of Prediction and SAD of collocated block  
 // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want  
   
         if ((x == 0) && (y == 0)) {  
                 thresh2 = 512;  
2080          } else {          } else {
2081  /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */                          pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;
2082                            pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;
2083                  thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;                          pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;
2084                            pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;
2085          }          }
   
 // MV=(0,0) is often a good choice  
   
         CHECK_MV16_ZERO;  
   
   
 // left neighbour, if allowed  
         if (x != 0) {  
                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                         pmv[1].x = EVEN(pmv[1].x);  
                         pmv[1].y = EVEN(pmv[1].y);  
2086                  }                  }
                 CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
         }  
 // top neighbour, if allowed  
         if (y != 0) {  
                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                         pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
                 }  
                 CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed  
                 if ((uint32_t) x != (iWcount - 1)) {  
                         if (!(MotionFlags & PMV_HALFPEL16)) {  
                                 pmv[3].x = EVEN(pmv[3].x);  
                                 pmv[3].y = EVEN(pmv[3].y);  
                         }  
                         CHECK_MV16_CANDIDATE(pmv[3].x, pmv[3].y);  
                 }  
         }  
   
 /* 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;  
2087          }          }
2088    
2089  /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/  void
2090    MotionEstimationBVOP(MBParam * const pParam,
2091          backupMV = prevMB->mvs[0];      // collocated MV                                           FRAMEINFO * const frame,
2092          backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x);     // acceleration X                                           const int32_t time_bp,
2093          backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y);     // acceleration Y                                           const int32_t time_pp,
2094                                             // forward (past) reference
2095          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y);                                           const MACROBLOCK * const f_mbs,
2096                                             const IMAGE * const f_ref,
2097  // left neighbour                                           const IMAGE * const f_refH,
2098          if (x != 0)                                           const IMAGE * const f_refV,
2099                  CHECK_MV16_CANDIDATE((prevMB - 1)->mvs[0].x, (prevMB - 1)->mvs[0].y);                                           const IMAGE * const f_refHV,
2100                                             // backward (future) reference
2101                                             const FRAMEINFO * const b_reference,
2102                                             const IMAGE * const b_ref,
2103                                             const IMAGE * const b_refH,
2104                                             const IMAGE * const b_refV,
2105                                             const IMAGE * const b_refHV)
2106    {
2107            uint32_t i, j;
2108            int32_t best_sad, skip_sad;
2109            int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;
2110            static const VECTOR zeroMV={0,0};
2111            const MACROBLOCK * const b_mbs = b_reference->mbs;
2112    
2113  // top neighbour          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
         if (y != 0)  
                 CHECK_MV16_CANDIDATE((prevMB - iWcount)->mvs[0].x,  
                                                          (prevMB - iWcount)->mvs[0].y);  
2114    
2115  // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs          const int32_t TRB = time_pp - time_bp;
2116            const int32_t TRD = time_pp;
2117            uint8_t * qimage;
2118    
2119    // some pre-inintialized data for the rest of the search
2120    
2121            SearchData Data;
2122            int32_t iMinSAD;
2123            VECTOR currentMV[3];
2124            VECTOR currentQMV[3];
2125            Data.iEdgedWidth = pParam->edged_width;
2126            Data.currentMV = currentMV; Data.currentQMV = currentQMV;
2127            Data.iMinSAD = &iMinSAD;
2128            Data.lambda16 = lambda_vec16[frame->quant];
2129            Data.qpel = pParam->m_quarterpel;
2130    
2131            if((qimage = (uint8_t *) malloc(32 * pParam->edged_width)) == NULL)
2132                    return; // allocate some mem for qpel interpolated blocks
2133                                      // somehow this is dirty since I think we shouldn't use malloc outside
2134                                      // encoder_create() - so please fix me!
2135            Data.RefQ = qimage;
2136    
2137          if ((uint32_t) x != iWcount - 1)          // note: i==horizontal, j==vertical
2138                  CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);          for (j = 0; j < pParam->mb_height; j++) {
2139    
2140  // bottom neighbour, dito                  f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
         if ((uint32_t) y != iHcount - 1)  
                 CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,  
                                                          (prevMB + iWcount)->mvs[0].y);  
2141    
2142  /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */                  for (i = 0; i < pParam->mb_width; i++) {
2143          if (iMinSAD <= thresh2) {                          MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
2144                  if (MotionFlags & PMV_QUICKSTOP16)                          const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
2145                          goto EPZS16_Terminate_without_Refine;  
2146                  if (MotionFlags & PMV_EARLYSTOP16)  /* special case, if collocated block is SKIPed in P-VOP: encoding is forward (0,0), cpb=0 without further ado */
2147                          goto EPZS16_Terminate_with_Refine;                          if (b_reference->coding_type != S_VOP)
2148                                    if (b_mb->mode == MODE_NOT_CODED) {
2149                                            pMB->mode = MODE_NOT_CODED;
2150                                            continue;
2151          }          }
2152    
2153  /************ (if Diamond Search)  **************/                          Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
2154                            pMB->quant = frame->quant;
2155    
2156          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  /* direct search comes first, because it (1) checks for SKIP-mode
2157            and (2) sets very good predictions for forward and backward search */
2158          if (MotionFlags & PMV_USESQUARES16)                          skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2159                  MainSearchPtr = Square16_MainSearch;                                                                          b_ref, b_refH->y, b_refV->y, b_refHV->y,
2160          else                                                                          &frame->image,
2161           if (MotionFlags & PMV_ADVANCEDDIAMOND16)                                                                          i, j,
2162                  MainSearchPtr = AdvDiamond16_MainSearch;                                                                          frame->motion_flags,
2163          else                                                                          TRB, TRD,
2164                  MainSearchPtr = Diamond16_MainSearch;                                                                          pParam,
2165                                                                            pMB, b_mb,
2166                                                                            &best_sad,
2167                                                                            &Data);
2168    
2169  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                          if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
2170    
2171          iSAD =                          // forward search
2172                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,                          SearchBF(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
2173                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,                                                  &frame->image, i, j,
2174                                                    min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);                                                  frame->motion_flags,
2175                                                    frame->fcode, pParam,
2176          if (iSAD < iMinSAD) {                                                  pMB, &f_predMV, &best_sad,
2177                  *currMV = newMV;                                                  MODE_FORWARD, &Data);
                 iMinSAD = iSAD;  
         }  
2178    
2179                            // backward search
2180                            SearchBF(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
2181                                                    &frame->image, i, j,
2182                                                    frame->motion_flags,
2183                                                    frame->bcode, pParam,
2184                                                    pMB, &b_predMV, &best_sad,
2185                                                    MODE_BACKWARD, &Data);
2186    
2187          if (MotionFlags & PMV_EXTSEARCH16) {                          // interpolate search comes last, because it uses data from forward and backward as prediction
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
2188    
2189                  if (!(MVequal(pmv[0], backupMV))) {                          SearchInterpolate(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
2190                          iSAD =                                                  b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
2191                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                                  &frame->image,
2192                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,                                                  i, j,
2193                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,                                                  frame->fcode, frame->bcode,
2194                                                                    2, iFcode, iQuant, 0);                                                  frame->motion_flags,
2195                  }                                                  pParam,
2196                                                    &f_predMV, &b_predMV,
2197                                                    pMB, &best_sad,
2198                                                    &Data);
2199    
2200                  if (iSAD < iMinSAD) {                          switch (pMB->mode) {
2201                          *currMV = newMV;                                  case MODE_FORWARD:
2202                          iMinSAD = iSAD;                                          f_count++;
2203                                            if (pParam->m_quarterpel) f_predMV = pMB->qmvs[0];
2204                                            else f_predMV = pMB->mvs[0];
2205                                            break;
2206                                    case MODE_BACKWARD:
2207                                            b_count++;
2208                                            if (pParam->m_quarterpel) b_predMV = pMB->b_qmvs[0];
2209                                            else b_predMV = pMB->b_mvs[0];
2210                                            break;
2211                                    case MODE_INTERPOLATE:
2212                                            i_count++;
2213                                            if (pParam->m_quarterpel) {
2214                                                    f_predMV = pMB->qmvs[0];
2215                                                    b_predMV = pMB->b_qmvs[0];
2216                                            } else {
2217                                                    f_predMV = pMB->mvs[0];
2218                                                    b_predMV = pMB->b_mvs[0];
2219                  }                  }
2220                                            break;
2221                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                                  case MODE_DIRECT:
2222                          iSAD =                                  case MODE_DIRECT_NO4V:
2223                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                                          d_count++;
2224                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,                                          break;
2225                                                                    max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);                                  default:
2226                                            break;
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
2227                          }                          }
2228                  }                  }
2229          }          }
2230            free(qimage);
 /***************        Choose best MV found     **************/  
   
   EPZS16_Terminate_with_Refine:  
         if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step  
                 iMinSAD =  
                         Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
   
   EPZS16_Terminate_without_Refine:  
   
         *oldMB = *prevMB;  
   
         currPMV->x = currMV->x - center_x;  
         currPMV->y = currMV->y - center_y;  
         return iMinSAD;  
2231  }  }
2232    
2233    /* Hinted ME starts here */
2234    
2235  int32_t  static void
2236  EPZSSearch8(const uint8_t * const pRef,  SearchPhinted ( const IMAGE * const pRef,
2237                          const uint8_t * const pRefH,                          const uint8_t * const pRefH,
2238                          const uint8_t * const pRefV,                          const uint8_t * const pRefV,
2239                          const uint8_t * const pRefHV,                          const uint8_t * const pRefHV,
2240                          const IMAGE * const pCur,                          const IMAGE * const pCur,
2241                          const int x,                          const int x,
2242                          const int y,                          const int y,
                         const int start_x,  
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
2243                          const uint32_t MotionFlags,                          const uint32_t MotionFlags,
2244                          const uint32_t iQuant,                          const uint32_t iQuant,
                         const uint32_t iFcode,  
2245                          const MBParam * const pParam,                          const MBParam * const pParam,
2246                          const MACROBLOCK * const pMBs,                          const MACROBLOCK * const pMBs,
2247                          const MACROBLOCK * const prevMBs,                                  int inter4v,
2248                          VECTOR * const currMV,                                  MACROBLOCK * const pMB,
2249                          VECTOR * const currPMV)                                  SearchData * const Data)
2250  {  {
2251  /* Please not that EPZS might not be a good choice for 8x8-block motion search ! */  
2252            int i, t;
2253          const uint32_t iWcount = pParam->mb_width;          MainSearchFunc * MainSearchPtr;
2254          const int32_t iWidth = pParam->width;  
2255          const int32_t iHeight = pParam->height;          Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
2256          const int32_t iEdgedWidth = pParam->edged_width;          Data->predQMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
2257            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2258          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;                                  pParam->width, pParam->height, Data->iFcode, pParam->m_quarterpel);
2259    
2260          int32_t iDiamondSize = 1;          Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16;
2261            Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8;
2262          int32_t min_dx;          Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8;
2263          int32_t max_dx;  
2264          int32_t min_dy;          Data->Ref = pRef->y + (x + Data->iEdgedWidth*y) * 16;
2265          int32_t max_dy;          Data->RefH = pRefH + (x + Data->iEdgedWidth*y) * 16;
2266            Data->RefV = pRefV + (x + Data->iEdgedWidth*y) * 16;
2267          VECTOR newMV;          Data->RefHV = pRefHV + (x + Data->iEdgedWidth*y) * 16;
2268          VECTOR backupMV;          Data->RefCV = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8;
2269            Data->RefCU = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8;
         VECTOR pmv[4];  
         int32_t psad[8];  
   
         const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);  
   
 //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;  
         const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;  
2270    
2271          int32_t bPredEq;          if (!(MotionFlags & PMV_HALFPEL16)) {
2272          int32_t iMinSAD, iSAD = 9999;                  Data->min_dx = EVEN(Data->min_dx);
2273                    Data->max_dx = EVEN(Data->max_dx);
2274          MainSearch8FuncPtr MainSearchPtr;                  Data->min_dy = EVEN(Data->min_dy);
2275                    Data->max_dy = EVEN(Data->max_dy);
2276  /* Get maximum range */          }
2277          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,  
2278                            iFcode);          for(i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;
2279    
2280  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          if (pMB->dquant != NO_CHANGE) inter4v = 0;
2281    
2282          if (!(MotionFlags & PMV_HALFPEL8)) {          if (inter4v || pParam->m_quarterpel || Data->chroma) CheckCandidate = CheckCandidate16;
2283                  min_dx = EVEN(min_dx);          else CheckCandidate = CheckCandidate16no4v;
2284                  max_dx = EVEN(max_dx);  
2285                  min_dy = EVEN(min_dy);          pMB->mvs[0].x = EVEN(pMB->mvs[0].x);
2286                  max_dy = EVEN(max_dy);          pMB->mvs[0].y = EVEN(pMB->mvs[0].y);
2287            if (pMB->mvs[0].x > Data->max_dx) pMB->mvs[0].x = Data->max_dx; // this is in case iFcode changed
2288            if (pMB->mvs[0].x < Data->min_dx) pMB->mvs[0].x = Data->min_dx;
2289            if (pMB->mvs[0].y > Data->max_dy) pMB->mvs[0].y = Data->max_dy;
2290            if (pMB->mvs[0].y < Data->min_dy) pMB->mvs[0].y = Data->min_dy;
2291    
2292            (*CheckCandidate)(pMB->mvs[0].x, pMB->mvs[0].y, 0, &t, Data);
2293    
2294            if (pMB->mode == MODE_INTER4V)
2295                    for (i = 1; i < 4; i++) { // all four vectors will be used as four predictions for 16x16 search
2296                            pMB->mvs[i].x = EVEN(pMB->mvs[i].x);
2297                            pMB->mvs[i].y = EVEN(pMB->mvs[i].y);
2298                            if (!(make_mask(pMB->mvs, i)))
2299                                    (*CheckCandidate)(pMB->mvs[i].x, pMB->mvs[i].y, 0, &t, Data);
2300          }          }
         /* 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);  
   
2301    
2302  /* Step 4: Calculate SAD around the Median prediction.          if (MotionFlags & PMV_USESQUARES16)
2303          MinSAD=SAD                  MainSearchPtr = SquareSearch;
2304          If Motion Vector equal to Previous frame motion vector          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
2305                  and MinSAD<PrevFrmSAD goto Step 10.                  MainSearchPtr = AdvDiamondSearch;
2306          If SAD<=256 goto Step 10.                  else MainSearchPtr = DiamondSearch;
 */  
2307    
2308  // Prepare for main loop          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);
2309    
2310            if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(Data);
2311    
2312          if (!(MotionFlags & PMV_HALFPEL8)) {          for(i = 0; i < 5; i++) {
2313                  currMV->x = EVEN(currMV->x);                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // initialize qpel vectors
2314                  currMV->y = EVEN(currMV->y);                  Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
2315            }
2316    
2317            if((pParam->m_quarterpel) && (MotionFlags & PMV_QUARTERPELREFINE16)) {
2318                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2319                                    pParam->width, pParam->height, Data->iFcode, 0);
2320                    CheckCandidate = CheckCandidate16_qpel;
2321                    QuarterpelRefine(Data);
2322            }
2323    
2324            if (inter4v) {
2325                    SearchData Data8;
2326                    Data8.iFcode = Data->iFcode;
2327                    Data8.lambda8 = Data->lambda8;
2328                    Data8.iEdgedWidth = Data->iEdgedWidth;
2329                    Data8.RefQ = Data->RefQ;
2330                    Data8.qpel = Data->qpel;
2331                    Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
2332                    Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
2333                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
2334                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
2335    
2336                    if (Data->chroma) {
2337                            int sum, dx, dy;
2338    
2339                            if(pParam->m_quarterpel)
2340                                    sum = (pMB->qmvs[0].y/2 + pMB->qmvs[1].y/2 + pMB->qmvs[2].y/2 + pMB->qmvs[3].y/2);
2341                            else sum = pMB->mvs[0].y + pMB->mvs[1].y + pMB->mvs[2].y + pMB->mvs[3].y;
2342                            dy = (sum ? SIGN(sum) *
2343                                      (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2) : 0);
2344    
2345                            if(pParam->m_quarterpel)
2346                                    sum = (pMB->qmvs[0].x/2 + pMB->qmvs[1].x/2 + pMB->qmvs[2].x/2 + pMB->qmvs[3].x/2);
2347                            else sum = pMB->mvs[0].x + pMB->mvs[1].x + pMB->mvs[2].x + pMB->mvs[3].x;
2348                            dx = (sum ? SIGN(sum) *
2349                                      (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2) : 0);
2350                            Data->iMinSAD[1] += ChromaSAD(dx, dy, Data);
2351          }          }
   
         if (currMV->x > max_dx)  
                 currMV->x = max_dx;  
         if (currMV->x < min_dx)  
                 currMV->x = min_dx;  
         if (currMV->y > max_dy)  
                 currMV->y = max_dy;  
         if (currMV->y < min_dy)  
                 currMV->y = min_dy;  
   
 /***************** This is predictor SET A: only median prediction ******************/  
   
   
         iMinSAD =  
                 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);  
   
   
 // thresh1 is fixed to 256  
         if (iMinSAD < 256 / 4) {  
                 if (MotionFlags & PMV_QUICKSTOP8)  
                         goto EPZS8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
2352          }          }
2353    
2354  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/          if (!(inter4v) ||
2355                    (Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] + Data->iMinSAD[3] +
2356                                                            Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {
2357    // INTER MODE
2358                    pMB->mode = MODE_INTER;
2359                    pMB->mvs[0] = pMB->mvs[1]
2360                            = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
2361    
2362  // MV=(0,0) is often a good choice                  pMB->qmvs[0] = pMB->qmvs[1]
2363          CHECK_MV8_ZERO;                          = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
2364    
2365  // previous frame MV                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
2366          CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x, prevMB->mvs[iSubBlock].y);                          pMB->sad8[2] = pMB->sad8[3] =  Data->iMinSAD[0];
2367    
2368  // left neighbour, if allowed                  if(pParam->m_quarterpel) {
2369          if (psad[1] != MV_MAX_ERROR) {                          pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predQMV.x;
2370                  if (!(MotionFlags & PMV_HALFPEL8)) {                          pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predQMV.y;
2371                          pmv[1].x = EVEN(pmv[1].x);                  } else {
2372                          pmv[1].y = EVEN(pmv[1].y);                          pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
2373                  }                          pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
                 CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);  
         }  
 // top neighbour, if allowed  
         if (psad[2] != MV_MAX_ERROR) {  
                 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  
                 if (psad[3] != MV_MAX_ERROR) {  
                         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);  
                 }  
2374          }          }
2375            } else {
2376  /*  // this bias is zero anyway, at the moment!  // INTER4V MODE; all other things are already set in Search8
2377                    pMB->mode = MODE_INTER4V;
2378          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)                  pMB->sad16 = Data->iMinSAD[1] + Data->iMinSAD[2] + Data->iMinSAD[3]
2379                  iMinSAD -= MV8_00_BIAS;                                                  + Data->iMinSAD[4] + IMV16X16 * iQuant;
   
 */  
   
 /* Terminate if MinSAD <= T_2  
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
   
         if (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */  
                 if (MotionFlags & PMV_QUICKSTOP8)  
                         goto EPZS8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
2380          }          }
2381    
 /************ (Diamond Search)  **************/  
   
         backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  
   
         if (!(MotionFlags & PMV_HALFPELDIAMOND8))  
                 iDiamondSize *= 2;  
   
 /* default: use best prediction as starting point for one call of EPZS_MainSearch */  
   
 // there is no EPZS^2 for inter4v at the moment  
   
   if (MotionFlags & PMV_USESQUARES8)  
       MainSearchPtr = Square8_MainSearch;  
   else  
   
         if (MotionFlags & PMV_ADVANCEDDIAMOND8)  
                 MainSearchPtr = AdvDiamond8_MainSearch;  
         else  
                 MainSearchPtr = Diamond8_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, 0);  
   
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
2382          }          }
2383    
2384          if (MotionFlags & PMV_EXTSEARCH8) {  void
2385  /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  MotionEstimationHinted( MBParam * const pParam,
2386                                                    FRAMEINFO * const current,
2387                  if (!(MVequal(pmv[0], backupMV))) {                                                  FRAMEINFO * const reference,
2388                          iSAD =                                                  const IMAGE * const pRefH,
2389                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                                  const IMAGE * const pRefV,
2390                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,                                                  const IMAGE * const pRefHV)
2391                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  {
2392                                                                    iDiamondSize, iFcode, iQuant, 0);          MACROBLOCK *const pMBs = current->mbs;
2393            const IMAGE *const pCurrent = &current->image;
2394            const IMAGE *const pRef = &reference->image;
2395    
2396                          if (iSAD < iMinSAD) {          uint32_t x, y;
2397                                  *currMV = newMV;          uint8_t * qimage;
2398                                  iMinSAD = iSAD;          int32_t temp[5], quant = current->quant;
2399            int32_t iMinSAD[5];
2400            VECTOR currentMV[5], currentQMV[5];
2401            SearchData Data;
2402            Data.iEdgedWidth = pParam->edged_width;
2403            Data.currentMV = currentMV;
2404            Data.currentQMV = currentQMV;
2405            Data.iMinSAD = iMinSAD;
2406            Data.temp = temp;
2407            Data.iFcode = current->fcode;
2408            Data.rounding = pParam->m_rounding_type;
2409            Data.qpel = pParam->m_quarterpel;
2410            Data.chroma = current->global_flags & XVID_ME_COLOUR;
2411    
2412            if((qimage = (uint8_t *) malloc(32 * pParam->edged_width)) == NULL)
2413                    return; // allocate some mem for qpel interpolated blocks
2414                                      // somehow this is dirty since I think we shouldn't use malloc outside
2415                                      // encoder_create() - so please fix me!
2416    
2417            Data.RefQ = qimage;
2418    
2419            if (sadInit) (*sadInit) ();
2420    
2421            for (y = 0; y < pParam->mb_height; y++) {
2422                    for (x = 0; x < pParam->mb_width; x++)  {
2423    
2424                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
2425    
2426    //intra mode is copied from the first pass. At least for the time being
2427                            if  ((pMB->mode == MODE_INTRA) || (pMB->mode == MODE_NOT_CODED) ) continue;
2428    
2429                            if (!(current->global_flags & XVID_LUMIMASKING)) {
2430                                    pMB->dquant = NO_CHANGE;
2431                                    pMB->quant = current->quant; }
2432                            else {
2433                                    if (pMB->dquant != NO_CHANGE) {
2434                                            quant += DQtab[pMB->dquant];
2435                                            if (quant > 31) quant = 31;
2436                                            else if (quant < 1) quant = 1;
2437                          }                          }
2438                                    pMB->quant = quant;
2439                  }                  }
2440    
2441                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                          SearchPhinted(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
2442                          iSAD =                                                          y, current->motion_flags, pMB->quant,
2443                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                                                          pParam, pMBs, current->global_flags & XVID_INTER4V, pMB,
2444                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,                                                          &Data);
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, 0);  
2445    
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
2446                  }                  }
2447          }          }
2448            free(qimage);
 /***************        Choose best MV found     **************/  
   
   EPZS8_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);  
   
   EPZS8_Terminate_without_Refine:  
   
         currPMV->x = currMV->x - center_x;  
         currPMV->y = currMV->y - center_y;  
         return iMinSAD;  
2449  }  }
2450    
2451    static __inline int
2452    MEanalyzeMB (   const uint8_t * const pRef,
2453  int32_t                                  const uint8_t * const pCur,
 PMVfastIntSearch16(const uint8_t * const pRef,  
                                 const uint8_t * const pRefH,  
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const IMAGE * const pCur,  
2454                                  const int x,                                  const int x,
2455                                  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,  
                                 const uint32_t MotionFlags,  
                                 const uint32_t iQuant,  
                                 const uint32_t iFcode,  
2456                                  const MBParam * const pParam,                                  const MBParam * const pParam,
2457                                  const MACROBLOCK * const pMBs,                                  const MACROBLOCK * const pMBs,
2458                                  const MACROBLOCK * const prevMBs,                                  MACROBLOCK * const pMB,
2459                                  VECTOR * const currMV,                                  SearchData * const Data)
                                 VECTOR * const currPMV)  
2460  {  {
         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;  
         const VECTOR zeroMV = { 0, 0 };  
   
         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;  
   
         VECTOR pmv[4];  
         int32_t psad[4];  
   
         MainSearch16FuncPtr MainSearchPtr;  
   
         const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;  
         MACROBLOCK *const pMB = pMBs + x + y * iWcount;  
   
         int32_t threshA, threshB;  
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD;  
2461    
2462            int i = 255, mask;
2463            VECTOR pmv[3];
2464            *(Data->iMinSAD) = MV_MAX_ERROR;
2465    
2466  /* Get maximum range */          //median is only used as prediction. it doesn't have to be real
2467          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,          if (x == 1 && y == 1) Data->predMV.x = Data->predMV.y = 0;
2468                            iFcode);          else
2469                    if (x == 1) //left macroblock does not have any vector now
2470  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */                          Data->predMV = (pMB - pParam->mb_width)->mvs[0]; // top instead of median
2471                    else if (y == 1) // top macroblock don't have it's vector
2472          if ((x == 0) && (y == 0)) {                          Data->predMV = (pMB - 1)->mvs[0]; // left instead of median
2473                  threshA = 512;                          else Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); //else median
2474                  threshB = 1024;  
2475            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2476                  bPredEq = 0;                                  pParam->width, pParam->height, Data->iFcode, pParam->m_quarterpel);
2477                  psad[0] = psad[1] = psad[2] = psad[3] = 0;  
2478                  *currMV = pmv[0] = pmv[1] = pmv[2] = pmv[3] = zeroMV;          Data->Cur = pCur + (x + y * pParam->edged_width) * 16;
2479            Data->Ref = pRef + (x + y * pParam->edged_width) * 16;
2480          } else {  
2481                  threshA = psad[0];          pmv[1].x = EVEN(pMB->mvs[0].x);
2482                  threshB = threshA + 256;          pmv[1].y = EVEN(pMB->mvs[0].y);
2483                  if (threshA < 512)          pmv[2].x = EVEN(Data->predMV.x);
2484                          threshA = 512;          pmv[2].y = EVEN(Data->predMV.y);
2485                  if (threshA > 1024)          pmv[0].x = pmv[0].y = 0;
2486                          threshA = 1024;  
2487                  if (threshB > 1792)          (*CheckCandidate)(0, 0, 255, &i, Data);
2488                          threshB = 1792;  
2489    //early skip for 0,0
2490                  bPredEq = get_ipmvdata(pMBs, iWcount, 0, x, y, 0, pmv, psad);          if (*Data->iMinSAD < MAX_SAD00_FOR_SKIP * 4) {
2491                  *currMV = pmv[0];                       /* current best := prediction */                  pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
2492          }                  pMB->mode = MODE_NOT_CODED;
2493                    return 0;
         iFound = 0;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
   
         if (currMV->x > max_dx) {  
                 currMV->x = EVEN(max_dx);  
         }  
         if (currMV->x < min_dx) {  
                 currMV->x = EVEN(min_dx);  
         }  
         if (currMV->y > max_dy) {  
                 currMV->y = EVEN(max_dy);  
         }  
         if (currMV->y < min_dy) {  
                 currMV->y = EVEN(min_dy);  
2494          }          }
2495    
2496          iMinSAD =          if (!(mask = make_mask(pmv, 1)))
2497                  sad16(cur,                  (*CheckCandidate)(pmv[1].x, pmv[1].y, mask, &i, Data);
2498                            get_iref_mv(pRef, x, y, 16, currMV,          if (!(mask = make_mask(pmv, 2)))
2499                                                   iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);                  (*CheckCandidate)(pmv[2].x, pmv[2].y, mask, &i, Data);
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
2500    
2501          if ((iMinSAD < 256) ||          if (*Data->iMinSAD > MAX_SAD00_FOR_SKIP * 4) // diamond only if needed
2502                  ((MVequal(*currMV, prevMB->i_mvs[0])) &&                  DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, i);
                  ((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;  
                         }  
                 }  
2503    
2504                  if (MotionFlags & PMV_EARLYSTOP16)          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
2505                          goto PMVfastInt16_Terminate_with_Refine;          pMB->mode = MODE_INTER;
2506            return *(Data->iMinSAD);
2507          }          }
2508    
2509    #define INTRA_THRESH    1350
2510    #define INTER_THRESH    900
2511    
 /* 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->i_mvs[0])))  
                 iFound = 2;  
   
 /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.  
    Otherwise select large Diamond Search.  
 */  
   
         if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))  
                 iDiamondSize = 2;               // halfpel units!  
         else  
                 iDiamondSize = 4;               // halfpel units!  
2512    
2513  /*  int
2514     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  MEanalysis(     const IMAGE * const pRef,
2515     Also calculate (0,0) but do not subtract offset.                          FRAMEINFO * const Current,
2516     Let MinSAD be the smallest SAD up to this point.                          MBParam * const pParam,
2517     If MV is (0,0) subtract offset.                          int maxIntra, //maximum number if non-I frames
2518  */                          int intraCount, //number of non-I frames after last I frame; 0 if we force P/B frame
2519                            int bCount) // number if B frames in a row
2520  // (0,0) is often a good choice  {
2521            uint32_t x, y, intra = 0;
2522          if (!MVzero(pmv[0]))          int sSAD = 0;
2523                  CHECK_MV16_ZERO;          MACROBLOCK * const pMBs = Current->mbs;
2524            const IMAGE * const pCurrent = &Current->image;
2525  // previous frame MV is always possible          int IntraThresh = INTRA_THRESH, InterThresh = INTER_THRESH;
2526    
2527          if (!MVzero(prevMB->i_mvs[0]))          VECTOR currentMV;
2528                  if (!MVequal(prevMB->i_mvs[0], pmv[0]))          int32_t iMinSAD;
2529                          CHECK_MV16_CANDIDATE(prevMB->i_mvs[0].x, prevMB->i_mvs[0].y);          SearchData Data;
2530            Data.iEdgedWidth = pParam->edged_width;
2531  // left neighbour, if allowed          Data.currentMV = &currentMV;
2532            Data.iMinSAD = &iMinSAD;
2533          if (!MVzero(pmv[1]))          Data.iFcode = Current->fcode;
2534                  if (!MVequal(pmv[1], prevMB->i_mvs[0]))          CheckCandidate = CheckCandidate16no4vI;
                         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.  
 */  
2535    
2536          if (MotionFlags & PMV_USESQUARES16)          if (intraCount < 10) // we're right after an I frame
2537                  MainSearchPtr = Square16_MainSearch;                  IntraThresh += 4 * (intraCount - 10) * (intraCount - 10);
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
2538          else          else
2539                  MainSearchPtr = Diamond16_MainSearch;                  if ( 5*(maxIntra - intraCount) < maxIntra) // we're close to maximum. 2 sec when max is 10 sec
2540                            IntraThresh -= (IntraThresh * (maxIntra - 5*(maxIntra - intraCount)))/maxIntra;
2541    
         backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  
2542    
2543            InterThresh += 300 * (1 - bCount);
2544            if (InterThresh < 200) InterThresh = 200;
2545    
2546  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          if (sadInit) (*sadInit) ();
         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);  
2547    
2548          if (iSAD < iMinSAD) {          for (y = 1; y < pParam->mb_height-1; y++) {
2549                  *currMV = newMV;                  for (x = 1; x < pParam->mb_width-1; x++) {
2550                  iMinSAD = iSAD;                          int sad, dev;
2551          }                          MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
2552    
2553          if (MotionFlags & PMV_EXTSEARCH16) {                          sad = MEanalyzeMB(pRef->y, pCurrent->y, x, y,
2554  /* extended: search (up to) two more times: orignal prediction and (0,0) */                                                                  pParam, pMBs, pMB, &Data);
2555    
2556                  if (!(MVequal(pmv[0], backupMV))) {                          if (sad > IntraThresh) {
2557                          iSAD =                                  dev = dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,
2558                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                                            pParam->edged_width);
2559                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,                                  if (dev + IntraThresh < sad) {
2560                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,                                          pMB->mode = MODE_INTRA;
2561                                                                    iDiamondSize, iFcode, iQuant, iFound);                                          if (++intra > (pParam->mb_height-2)*(pParam->mb_width-2)/2) return 2;  // I frame
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
2562                  }                  }
   
                 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;  
2563                          }                          }
2564                            sSAD += sad;
2565                  }                  }
2566          }          }
2567            sSAD /= (pParam->mb_height-2)*(pParam->mb_width-2);
2568            if (sSAD > InterThresh ) return 1; //P frame
2569            emms();
2570            return 0; // B frame
2571    
 /*  
    Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  
 */  
   
 PMVfastInt16_Terminate_with_Refine:  
   
         pMB->i_mvs[0] = pMB->i_mvs[1] = pMB->i_mvs[2] = pMB->i_mvs[3] = pMB->i_mv16 = *currMV;  
         pMB->i_sad8[0] = pMB->i_sad8[1] = pMB->i_sad8[2] = pMB->i_sad8[3] = pMB->i_sad16 = iMinSAD;  
   
         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);  
   
         pmv[0] = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          // get _REAL_ prediction (halfpel possible)  
   
 PMVfastInt16_Terminate_without_Refine:  
         currPMV->x = currMV->x - center_x;  
         currPMV->y = currMV->y - center_y;  
         return iMinSAD;  
2572  }  }
2573    
2574    int
2575    FindFcode(      const MBParam * const pParam,
2576  /* ***********************************************************                          const FRAMEINFO * const current)
         bvop motion estimation  
 ***************************************************************/  
   
 void  
 MotionEstimationBVOP(MBParam * const pParam,  
                                          FRAMEINFO * const frame,  
                                          const int32_t time_bp,  
                                          const int32_t time_pp,  
                                          // forward (past) reference  
                                          const MACROBLOCK * const f_mbs,  
                                          const IMAGE * const f_ref,  
                                          const IMAGE * const f_refH,  
                                          const IMAGE * const f_refV,  
                                          const IMAGE * const f_refHV,  
                                          // backward (future) reference  
                                          const MACROBLOCK * const b_mbs,  
                                          const IMAGE * const b_ref,  
                                          const IMAGE * const b_refH,  
                                          const IMAGE * const b_refV,  
                                          const IMAGE * const b_refHV)  
2577  {  {
2578          const int mb_width = pParam->mb_width;          uint32_t x, y;
2579          const int mb_height = pParam->mb_height;          int max = 0, min = 0, i;
         const int edged_width = pParam->edged_width;  
   
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
   
         int i, j, k;  
   
         static const VECTOR zeroMV={0,0};  
   
         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;  
   
         VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/  
         VECTOR f_interpolMV, b_interpolMV;  
         VECTOR pmv_dontcare;  
   
         int min_dx, max_dx, min_dy, max_dy;  
         int f_min_dx, f_max_dx, f_min_dy, f_max_dy;  
         int b_min_dx, b_max_dx, b_min_dy, b_max_dy;  
   
         int f_count=0;  
         int b_count=0;  
         int i_count=0;  
         int d_count=0;  
2580    
2581          const int64_t TRB = (int32_t)time_pp - (int32_t)time_bp;          for (y = 0; y < pParam->mb_height; y++) {
2582      const int64_t TRD = (int32_t)time_pp;                  for (x = 0; x < pParam->mb_width; x++) {
2583    
2584          // fprintf(stderr,"TRB = %lld  TRD = %lld  time_bp =%d time_pp =%d\n\n",TRB,TRD,time_bp,time_pp);                          MACROBLOCK *pMB = &current->mbs[x + y * pParam->mb_width];
2585          // note: i==horizontal, j==vertical                          for(i = 0; i < (pMB->mode == MODE_INTER4V ? 4:1); i++) {
2586          for (j = 0; j < mb_height; j++) {                                  if (pMB->mvs[i].x > max) max = pMB->mvs[i].x;
2587                                    if (pMB->mvs[i].y > max) max = pMB->mvs[i].y;
                 f_predMV = zeroMV;      /* prediction is reset at left boundary */  
                 b_predMV = zeroMV;  
2588    
2589                  for (i = 0; i < mb_width; i++) {                                  if (pMB->mvs[i].x < min) min = pMB->mvs[i].x;
2590                          MACROBLOCK *mb = &frame->mbs[i + j * mb_width];                                  if (pMB->mvs[i].y < min) min = pMB->mvs[i].y;
                         const MACROBLOCK *f_mb = &f_mbs[i + j * mb_width];  
                         const MACROBLOCK *b_mb = &b_mbs[i + j * mb_width];  
   
                         mb->deltamv=zeroMV;  
   
 /* special case, if collocated block is SKIPed: encoding is forward (0,0), cpb=0 without further ado */  
   
 #ifndef _DISABLE_SKIP  
                         if (b_mb->mode == MODE_INTER && b_mb->cbp == 0 &&  
                                 b_mb->mvs[0].x == 0 && b_mb->mvs[0].y == 0) {  
                                 mb->mode = MODE_NOT_CODED;  
                                 mb->mvs[0].x = 0;  
                                 mb->mvs[0].y = 0;  
                                 mb->b_mvs[0].x = 0;  
                                 mb->b_mvs[0].y = 0;  
                                 continue;  
2591                          }                          }
 #endif  
   
                         if (b_mb->mode == MODE_INTER4V)  
                         {  
                                 d_sad16 = 0;  
                         /* same method of scaling as in decoder.c, so we copy from there */  
                     for (k = 0; k < 4; k++) {  
   
                                         mb->directmv[k] = b_mb->mvs[k];  
   
                                         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);  
2592                                  }                                  }
2593                          }                          }
                         else  
                         {  
                                 mb->directmv[3] = mb->directmv[2] = mb->directmv[1] =  
                                         mb->directmv[0] = b_mb->mvs[0];  
2594    
2595                                  mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);          min = -min;
2596                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)          max += 1;
2597                                                                          ? ((TRB - TRD) * mb->directmv[0].x) / TRD          if (min > max) max = min;
2598                                      : mb->mvs[0].x - mb->directmv[0].x);          if (pParam->m_quarterpel) max *= 2;
   
                     mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);  
                 mb->b_mvs[0].y = (int32_t) ((mb->directmv[0].y == 0)  
                                                                         ? ((TRB - TRD) * mb->directmv[0].y) / TRD  
                                     : mb->mvs[0].y - mb->directmv[0].y);  
   
                                 d_sad16 = sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 i, j, 16, &mb->mvs[0], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 i, j, 16, &mb->b_mvs[0], edged_width),  
                                                   edged_width);  
2599    
2600            for (i = 1; (max > 32 << (i - 1)); i++);
2601            return i;
2602              }              }
                     d_sad16 += calc_delta_16(mb->deltamv.x, mb->deltamv.y, 1, frame->quant);  
   
                         // forward search  
                         f_sad16 = SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 &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 */  
                                                 frame->motion_flags,  
                                                 frame->quant, frame->fcode, pParam,  
                                                 f_mbs, f_mbs,  
                                                 &mb->mvs[0], &pmv_dontcare);  
2603    
2604    static void
2605    CheckGMC(int x, int y, const int dir, int * iDirection,
2606                    const MACROBLOCK * const pMBs, uint32_t * bestcount, VECTOR * GMC,
2607                    const MBParam * const pParam)
2608    {
2609            uint32_t mx, my, a, count = 0;
2610    
2611                          // backward search          for (my = 1; my < pParam->mb_height-1; my++)
2612                          b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,                  for (mx = 1; mx < pParam->mb_width-1; mx++) {
2613                                                  &frame->image, i, j,                          VECTOR mv;
2614                                                  mb->b_mvs[0].x, mb->b_mvs[0].y,         /* start point b_directMV */                          const MACROBLOCK *pMB = &pMBs[mx + my * pParam->mb_width];
2615                                                  b_predMV.x, b_predMV.y,                         /* center is b-prediction */                          if (pMB->mode == MODE_INTRA || pMB->mode == MODE_NOT_CODED) continue;
2616                                                  frame->motion_flags,                          mv = pMB->mvs[0];
2617                                                  frame->quant, frame->bcode, pParam,                          a = ABS(mv.x - x) + ABS(mv.y - y);
2618                                                  b_mbs, b_mbs,                          if (a < 6) count += 6 - a;
                                                 &mb->b_mvs[0], &pmv_dontcare);  
   
                         i_sad16 =  
                                 sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 i, j, 16, &mb->mvs[0], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 i, j, 16, &mb->b_mvs[0], edged_width),  
                                                   edged_width);  
                     i_sad16 += calc_delta_16(mb->mvs[0].x-f_predMV.x, mb->mvs[0].y-f_predMV.y,  
                                                                 frame->fcode, frame->quant);  
                     i_sad16 += calc_delta_16(mb->b_mvs[0].x-b_predMV.x, mb->b_mvs[0].y-b_predMV.y,  
                                                                 frame->bcode, frame->quant);  
   
                         get_range(&f_min_dx, &f_max_dx, &f_min_dy, &f_max_dy, i, j, 16, iWidth, iHeight,  
                           frame->fcode);  
                         get_range(&b_min_dx, &b_max_dx, &b_min_dy, &b_max_dy, i, j, 16, iWidth, iHeight,  
                           frame->bcode);  
   
 /* Interpolated MC motion vector search, this is tedious and more complicated because there are  
    two values for everything, always one for backward and one for forward ME. Still, we don't gain  
    much from this search, maybe it should simply be skipped and simply current i_sad16 value used  
    as "optimal". */  
   
                         i_sad16 = Diamond16_InterpolMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i * 16 + j * 16 * edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 mb->mvs[0].x, mb->mvs[0].y,  
                                                 mb->b_mvs[0].x, mb->b_mvs[0].y,  
                                                 i_sad16,  
                                                 &f_interpolMV, &b_interpolMV,  
                                                 f_predMV.x, f_predMV.y, b_predMV.x, b_predMV.y,  
                                                 f_min_dx, f_max_dx, f_min_dy, f_max_dy,  
                                                 b_min_dx, b_max_dx, b_min_dy, b_max_dy,  
                                                 edged_width,  1,  
                                                 frame->fcode, frame->bcode,frame->quant,0);  
   
   
 /*  DIRECT MODE DELTA VECTOR SEARCH.  
     This has to be made more effective, but at the moment I'm happy it's running at all */  
   
 /* range is taken without fcode restriction, just a hack instead of writing down the dimensions, of course */  
   
                         get_range(&min_dx, &max_dx, &min_dy, &max_dy, i, j, 16, iWidth, iHeight, 19);  
   
                         d_sad16 = Diamond16_DirectMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i*16 + j*16*edged_width,  
                                                 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, 1, frame->quant, 0);  
   
   
 //                      i_sad16 = 65535;                /* remove the comment to disable any of the MODEs */  
 //                      f_sad16 = 65535;  
 //                      b_sad16 = 65535;  
 //                      d_sad16 = 65535;  
   
                         if (f_sad16 < b_sad16) {  
                                 best_sad = f_sad16;  
                                 mb->mode = MODE_FORWARD;  
                         } else {  
                                 best_sad = b_sad16;  
                                 mb->mode = MODE_BACKWARD;  
2619                          }                          }
2620    
2621                          if (i_sad16 < best_sad) {          if (count > *bestcount) {
2622                                  best_sad = i_sad16;                  *bestcount = count;
2623                                  mb->mode = MODE_INTERPOLATE;                  *iDirection = dir;
2624                    GMC->x = x; GMC->y = y;
2625            }
2626                          }                          }
2627    
                         if (d_sad16 < best_sad) {  
2628    
2629                                  if (b_mb->mode == MODE_INTER4V)  static VECTOR
2630    GlobalMotionEst(const MACROBLOCK * const pMBs, const MBParam * const pParam, const uint32_t iFcode)
2631                                  {                                  {
2632    
2633                                  /* how to calc vectors is defined in standard. mvs[] and b_mvs[] are only for motion compensation */          uint32_t count, bestcount = 0;
2634                                  /* for the bitstream, the value mb->deltamv is read directly */          int x, y;
2635            VECTOR gmc = {0,0};
2636                              for (k = 0; k < 4; k++) {          int step, min_x, max_x, min_y, max_y;
2637            uint32_t mx, my;
2638                                                  mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);          int iDirection, bDirection;
                             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);  
                                         }  
                                 }  
                                 else  
                                 {  
                                         mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);  
2639    
2640                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)          min_x = min_y = -32<<iFcode;
2641                                                                                  ? ((TRB - TRD) * mb->directmv[0].x) / TRD          max_x = max_y = 32<<iFcode;
                                         : mb->mvs[0].x - mb->directmv[0].x);  
2642    
2643                              mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);  //step1: let's find a rough camera panning
2644            for (step = 32; step >= 2; step /= 2) {
2645                    bestcount = 0;
2646                    for (y = min_y; y <= max_y; y += step)
2647                            for (x = min_x ; x <= max_x; x += step) {
2648                                    count = 0;
2649                                    //for all macroblocks
2650                                    for (my = 1; my < pParam->mb_height-1; my++)
2651                                            for (mx = 1; mx < pParam->mb_width-1; mx++) {
2652                                                    const MACROBLOCK *pMB = &pMBs[mx + my * pParam->mb_width];
2653                                                    VECTOR mv;
2654    
2655                          mb->b_mvs[0].y = (int32_t) ((mb->deltamv.y == 0)                                                  if (pMB->mode == MODE_INTRA || pMB->mode == MODE_NOT_CODED)
2656                                                                                  ? ((TRB - TRD) * mb->directmv[0].y) / TRD                                                          continue;
                                             : mb->mvs[0].y - mb->directmv[0].y);  
2657    
2658                                          mb->mvs[3] = mb->mvs[2] = mb->mvs[1] = mb->mvs[0];                                                  mv = pMB->mvs[0];
2659                                          mb->b_mvs[3] = mb->b_mvs[2] = mb->b_mvs[1] = mb->b_mvs[0];                                                  if ( ABS(mv.x - x) <= step && ABS(mv.y - y) <= step )   /* GMC translation is always halfpel-res */
2660                                                            count++;
2661                                            }
2662                                    if (count >= bestcount) { bestcount = count; gmc.x = x; gmc.y = y; }
2663                  }                  }
2664                    min_x = gmc.x - step;
2665                    max_x = gmc.x + step;
2666                    min_y = gmc.y - step;
2667                    max_y = gmc.y + step;
2668    
                                 best_sad = d_sad16;  
                                 mb->mode = MODE_DIRECT;  
2669                          }                          }
2670    
2671                          switch (mb->mode)          if (bestcount < (pParam->mb_height-2)*(pParam->mb_width-2)/10)
2672                          {                  gmc.x = gmc.y = 0; //no camara pan, no GMC
                                 case MODE_FORWARD:  
                                         f_count++;  
                                         f_predMV = mb->mvs[0];  
                                         break;  
                                 case MODE_BACKWARD:  
                                         b_count++;  
                                         b_predMV = mb->b_mvs[0];  
2673    
2674                                          break;  // step2: let's refine camera panning using gradiend-descent approach.
2675                                  case MODE_INTERPOLATE:  // TODO: more warping points may be evaluated here (like in interpolate mode search - two vectors in one diamond)
2676                                          i_count++;          bestcount = 0;
2677                                          mb->mvs[0] = f_interpolMV;          CheckGMC(gmc.x, gmc.y, 255, &iDirection, pMBs, &bestcount, &gmc, pParam);
2678                                          mb->b_mvs[0] = b_interpolMV;          do {
2679                                          f_predMV = mb->mvs[0];                  x = gmc.x; y = gmc.y;
2680                                          b_predMV = mb->b_mvs[0];                  bDirection = iDirection; iDirection = 0;
2681                                          break;                  if (bDirection & 1) CheckGMC(x - 1, y, 1+4+8, &iDirection, pMBs, &bestcount, &gmc, pParam);
2682                                  case MODE_DIRECT:                  if (bDirection & 2) CheckGMC(x + 1, y, 2+4+8, &iDirection, pMBs, &bestcount, &gmc, pParam);
2683                                          d_count++;                  if (bDirection & 4) CheckGMC(x, y - 1, 1+2+4, &iDirection, pMBs, &bestcount, &gmc, pParam);
2684                                          break;                  if (bDirection & 8) CheckGMC(x, y + 1, 1+2+8, &iDirection, pMBs, &bestcount, &gmc, pParam);
                                 default:  
                                         break;  
                         }  
2685    
2686                  }          } while (iDirection);
         }  
2687    
2688  #ifdef _DEBUG_BFRAME_STAT          if (pParam->m_quarterpel) {
2689          fprintf(stderr,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d\n",                  gmc.x *= 2;
2690                                  f_count,b_count,i_count,d_count);                  gmc.y *= 2;     /* we store the halfpel value as pseudo-qpel to make comparison easier */
2691  #endif          }
2692    
2693            return gmc;
2694  }  }

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

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