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

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

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

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

Legend:
Removed from v.300  
changed lines
  Added in v.702

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