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

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

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