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

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

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