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

Legend:
Removed from v.370  
changed lines
  Added in v.771

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