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

Legend:
Removed from v.348  
changed lines
  Added in v.768

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