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

Legend:
Removed from v.344  
changed lines
  Added in v.698

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