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

Legend:
Removed from v.347  
changed lines
  Added in v.628

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