[cvs] / xvidcore / src / motion / motion_est.c Repository:
ViewVC logotype

Diff of /xvidcore/src/motion/motion_est.c

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

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

Legend:
Removed from v.1.44  
changed lines
  Added in v.1.44.2.31

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