[svn] / trunk / xvidcore / src / motion / motion_est.c Repository:
ViewVC logotype

Diff of /trunk/xvidcore/src/motion/motion_est.c

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

revision 351, Wed Jul 31 10:08:58 2002 UTC revision 1072, Thu Jun 19 10:06:40 2003 UTC
# Line 28  Line 28 
28   *   *
29   *************************************************************************/   *************************************************************************/
30    
 /**************************************************************************  
  *  
  *  Modifications:  
  *  
  *      01.05.2002      updated MotionEstimationBVOP  
  *      25.04.2002 partial prevMB conversion  
  *  22.04.2002 remove some compile warning by chenm001 <chenm001@163.com>  
  *  14.04.2002 added MotionEstimationBVOP()  
  *  02.04.2002 add EPZS(^2) as ME algorithm, use PMV_USESQUARES to choose between  
  *             EPZS and EPZS^2  
  *  08.02.2002 split up PMVfast into three routines: PMVFast, PMVFast_MainLoop  
  *             PMVFast_Refine to support multiple searches with different start points  
  *  07.01.2002 uv-block-based interpolation  
  *  06.01.2002 INTER/INTRA-decision is now done before any SEARCH8 (speedup)  
  *             changed INTER_BIAS to 150 (as suggested by suxen_drol)  
  *             removed halfpel refinement step in PMVfastSearch8 + quality=5  
  *             added new quality mode = 6 which performs halfpel refinement  
  *             filesize difference between quality 5 and 6 is smaller than 1%  
  *             (Isibaar)  
  *  31.12.2001 PMVfastSearch16 and PMVfastSearch8 (gruel)  
  *  30.12.2001 get_range/MotionSearchX simplified; blue/green bug fix  
  *  22.12.2001 commented best_point==99 check  
  *  19.12.2001 modified get_range (purple bug fix)  
  *  15.12.2001 moved pmv displacement from mbprediction  
  *  02.12.2001 motion estimation/compensation split (Isibaar)  
  *  16.11.2001 rewrote/tweaked search algorithms; pross@cs.rmit.edu.au  
  *  10.11.2001 support for sad16/sad8 functions  
  *  28.08.2001 reactivated MODE_INTER4V for EXT_MODE  
  *  24.08.2001 removed MODE_INTER4V_Q, disabled MODE_INTER4V for EXT_MODE  
  *  22.08.2001 added MODE_INTER4V_Q  
  *  20.08.2001 added pragma to get rid of internal compiler error with VC6  
  *             idea by Cyril. Thanks.  
  *  
  *  Michael Militzer <isibaar@videocoding.de>  
  *  
  **************************************************************************/  
   
31  #include <assert.h>  #include <assert.h>
32  #include <stdio.h>  #include <stdio.h>
33  #include <stdlib.h>  #include <stdlib.h>
34    #include <string.h>     // memcpy
35    #include <math.h>       // lrint
36    
37  #include "../encoder.h"  #include "../encoder.h"
38  #include "../utils/mbfunctions.h"  #include "../utils/mbfunctions.h"
39  #include "../prediction/mbprediction.h"  #include "../prediction/mbprediction.h"
40  #include "../global.h"  #include "../global.h"
41  #include "../utils/timer.h"  #include "../utils/timer.h"
42    #include "../image/interpolate8x8.h"
43    #include "motion_est.h"
44  #include "motion.h"  #include "motion.h"
45  #include "sad.h"  #include "sad.h"
46    #include "../utils/emms.h"
47    #include "../dct/fdct.h"
48    
49    /*****************************************************************************
50     * Modified rounding tables -- declared in motion.h
51  static int32_t lambda_vec16[32] =       /* rounded values for lambda param for weight of motion bits as in modified H.26L */   * Original tables see ISO spec tables 7-6 -> 7-9
52  { 0, (int) (1.00235 + 0.5), (int) (1.15582 + 0.5), (int) (1.31976 + 0.5),   ****************************************************************************/
53                  (int) (1.49591 + 0.5), (int) (1.68601 + 0.5),  
54          (int) (1.89187 + 0.5), (int) (2.11542 + 0.5), (int) (2.35878 + 0.5),  const uint32_t roundtab[16] =
55                  (int) (2.62429 + 0.5), (int) (2.91455 + 0.5),  {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2 };
56          (int) (3.23253 + 0.5), (int) (3.58158 + 0.5), (int) (3.96555 + 0.5),  
57                  (int) (4.38887 + 0.5), (int) (4.85673 + 0.5),  /* K = 4 */
58          (int) (5.37519 + 0.5), (int) (5.95144 + 0.5), (int) (6.59408 + 0.5),  const uint32_t roundtab_76[16] =
59                  (int) (7.31349 + 0.5), (int) (8.12242 + 0.5),  { 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1 };
60          (int) (9.03669 + 0.5), (int) (10.0763 + 0.5), (int) (11.2669 + 0.5),  
61                  (int) (12.6426 + 0.5), (int) (14.2493 + 0.5),  /* K = 2 */
62          (int) (16.1512 + 0.5), (int) (18.442 + 0.5), (int) (21.2656 + 0.5),  const uint32_t roundtab_78[8] =
63                  (int) (24.8580 + 0.5), (int) (29.6436 + 0.5),  { 0, 0, 1, 1, 0, 0, 0, 1  };
64          (int) (36.4949 + 0.5)  
65  };  /* K = 1 */
66    const uint32_t roundtab_79[4] =
67  static int32_t *lambda_vec8 = lambda_vec16;     /* same table for INTER and INTER4V for now */  { 0, 1, 0, 0 };
68    
69    #define INITIAL_SKIP_THRESH     (10)
70    #define FINAL_SKIP_THRESH       (50)
71  // mv.length table  #define MAX_SAD00_FOR_SKIP      (20)
72  static const uint32_t mvtab[33] = {  #define MAX_CHROMA_SAD_FOR_SKIP (22)
73          1, 2, 3, 4, 6, 7, 7, 7,  
74          9, 9, 9, 10, 10, 10, 10, 10,  #define CHECK_CANDIDATE(X,Y,D) { \
75          10, 10, 10, 10, 10, 10, 10, 10,  CheckCandidate((X),(Y), (D), &iDirection, data ); }
76          10, 11, 11, 11, 11, 11, 11, 12, 12  
77  };  /*****************************************************************************
78     * Code
79     ****************************************************************************/
80    
81  static __inline uint32_t  static __inline uint32_t
82  mv_bits(int32_t component,  d_mv_bits(int x, int y, const VECTOR pred, const uint32_t iFcode, const int qpel, const int rrv)
                 const uint32_t iFcode)  
83  {  {
84          if (component == 0)          int bits;
85                  return 1;          const int q = (1 << (iFcode - 1)) - 1;
   
         if (component < 0)  
                 component = -component;  
   
         if (iFcode == 1) {  
                 if (component > 32)  
                         component = 32;  
86    
87                  return mvtab[component] + 1;          x <<= qpel;
88            y <<= qpel;
89            if (rrv) { x = RRV_MV_SCALEDOWN(x); y = RRV_MV_SCALEDOWN(y); }
90    
91            x -= pred.x;
92            bits = (x != 0 ? iFcode:0);
93            x = abs(x);
94            x += q;
95            x >>= (iFcode - 1);
96            bits += mvtab[x];
97    
98            y -= pred.y;
99            bits += (y != 0 ? iFcode:0);
100            y = abs(y);
101            y += q;
102            y >>= (iFcode - 1);
103            bits += mvtab[y];
104    
105            return bits;
106    }
107    
108    static int32_t ChromaSAD2(const int fx, const int fy, const int bx, const int by,
109                                                            const SearchData * const data)
110    {
111            int sad;
112            const uint32_t stride = data->iEdgedWidth/2;
113            uint8_t * f_refu = data->RefQ,
114                    * f_refv = data->RefQ + 8,
115                    * b_refu = data->RefQ + 16,
116                    * b_refv = data->RefQ + 24;
117            int offset = (fx>>1) + (fy>>1)*stride;
118    
119            switch (((fx & 1) << 1) | (fy & 1))     {
120                    case 0:
121                            f_refu = (uint8_t*)data->RefP[4] + offset;
122                            f_refv = (uint8_t*)data->RefP[5] + offset;
123                            break;
124                    case 1:
125                            interpolate8x8_halfpel_v(f_refu, data->RefP[4] + offset, stride, data->rounding);
126                            interpolate8x8_halfpel_v(f_refv, data->RefP[5] + offset, stride, data->rounding);
127                            break;
128                    case 2:
129                            interpolate8x8_halfpel_h(f_refu, data->RefP[4] + offset, stride, data->rounding);
130                            interpolate8x8_halfpel_h(f_refv, data->RefP[5] + offset, stride, data->rounding);
131                            break;
132                    default:
133                            interpolate8x8_halfpel_hv(f_refu, data->RefP[4] + offset, stride, data->rounding);
134                            interpolate8x8_halfpel_hv(f_refv, data->RefP[5] + offset, stride, data->rounding);
135                            break;
136          }          }
137    
138          component += (1 << (iFcode - 1)) - 1;          offset = (bx>>1) + (by>>1)*stride;
139          component >>= (iFcode - 1);          switch (((bx & 1) << 1) | (by & 1))     {
140                    case 0:
141          if (component > 32)                          b_refu = (uint8_t*)data->b_RefP[4] + offset;
142                  component = 32;                          b_refv = (uint8_t*)data->b_RefP[5] + offset;
143                            break;
144          return mvtab[component] + 1 + iFcode - 1;                  case 1:
145                            interpolate8x8_halfpel_v(b_refu, data->b_RefP[4] + offset, stride, data->rounding);
146                            interpolate8x8_halfpel_v(b_refv, data->b_RefP[5] + offset, stride, data->rounding);
147                            break;
148                    case 2:
149                            interpolate8x8_halfpel_h(b_refu, data->b_RefP[4] + offset, stride, data->rounding);
150                            interpolate8x8_halfpel_h(b_refv, data->b_RefP[5] + offset, stride, data->rounding);
151                            break;
152                    default:
153                            interpolate8x8_halfpel_hv(b_refu, data->b_RefP[4] + offset, stride, data->rounding);
154                            interpolate8x8_halfpel_hv(b_refv, data->b_RefP[5] + offset, stride, data->rounding);
155                            break;
156  }  }
157    
158            sad = sad8bi(data->CurU, b_refu, f_refu, stride);
159            sad += sad8bi(data->CurV, b_refv, f_refv, stride);
160    
161  static __inline uint32_t          return sad;
 calc_delta_16(const int32_t dx,  
                           const int32_t dy,  
                           const uint32_t iFcode,  
                           const uint32_t iQuant)  
 {  
         return NEIGH_TEND_16X16 * lambda_vec16[iQuant] * (mv_bits(dx, iFcode) +  
                                                                                                           mv_bits(dy, iFcode));  
 }  
   
 static __inline uint32_t  
 calc_delta_8(const int32_t dx,  
                          const int32_t dy,  
                          const uint32_t iFcode,  
                          const uint32_t iQuant)  
 {  
         return NEIGH_TEND_8X8 * lambda_vec8[iQuant] * (mv_bits(dx, iFcode) +  
                                                                                                    mv_bits(dy, iFcode));  
162  }  }
163    
164  bool  static int32_t
165  MotionEstimation(MBParam * const pParam,  ChromaSAD(const int dx, const int dy, 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)  
166  {  {
167          const uint32_t iWcount = pParam->mb_width;          int sad;
168          const uint32_t iHcount = pParam->mb_height;          const uint32_t stride = data->iEdgedWidth/2;
169          MACROBLOCK *const pMBs = current->mbs;          int offset = (dx>>1) + (dy>>1)*stride;
         MACROBLOCK *const prevMBs = reference->mbs;  
         const IMAGE *const pCurrent = &current->image;  
         const IMAGE *const pRef = &reference->image;  
   
         static const VECTOR zeroMV = { 0, 0 };  
         VECTOR predMV;  
   
         int32_t x, y;  
         int32_t iIntra = 0;  
         VECTOR pmv;  
   
         if (sadInit)  
                 (*sadInit) ();  
   
         for (y = 0; y < iHcount; y++)   {  
                 for (x = 0; x < iWcount; x ++)  {  
   
                         MACROBLOCK *const pMB = &pMBs[x + y * iWcount];  
   
                         predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);  
   
                         pMB->sad16 =  
                                 SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,  
                                                  x, y, predMV.x, predMV.y, predMV.x, predMV.y,  
                                                  current->motion_flags, current->quant,  
                                                  current->fcode, pParam, pMBs, prevMBs, &pMB->mv16,  
                                                  &pMB->pmvs[0]);  
170    
171                          if (0 < (pMB->sad16 - MV16_INTER_BIAS)) {          if (dx == data->temp[5] && dy == data->temp[6]) return data->temp[7]; //it has been checked recently
172                                  int32_t deviation;          data->temp[5] = dx; data->temp[6] = dy; // backup
   
                                 deviation =  
                                         dev16(pCurrent->y + x * 16 + y * 16 * pParam->edged_width,  
                                                   pParam->edged_width);  
   
                                 if (deviation < (pMB->sad16 - MV16_INTER_BIAS)) {  
                                         pMB->mode = MODE_INTRA;  
                                         pMB->mv16 = pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =  
                                                 pMB->mvs[3] = zeroMV;  
                                         pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =  
                                                 pMB->sad8[3] = 0;  
173    
174                                          iIntra++;          switch (((dx & 1) << 1) | (dy & 1))     {
175                                          if (iIntra >= iLimit)                  case 0:
176                                                  return 1;                          sad = sad8(data->CurU, data->RefP[4] + offset, stride);
177                            sad += sad8(data->CurV, data->RefP[5] + offset, stride);
178                                          continue;                          break;
179                                  }                  case 1:
180                          }                          sad = sad8bi(data->CurU, data->RefP[4] + offset, data->RefP[4] + offset + stride, stride);
181                            sad += sad8bi(data->CurV, data->RefP[5] + offset, data->RefP[5] + offset + stride, stride);
182                          pmv = pMB->pmvs[0];                          break;
183                          if (current->global_flags & XVID_INTER4V)                  case 2:
184                                  if ((!(current->global_flags & XVID_LUMIMASKING) ||                          sad = sad8bi(data->CurU, data->RefP[4] + offset, data->RefP[4] + offset + 1, stride);
185                                           pMB->dquant == NO_CHANGE)) {                          sad += sad8bi(data->CurV, data->RefP[5] + offset, data->RefP[5] + offset + 1, stride);
186                                          int32_t sad8 = IMV16X16 * current->quant;                          break;
187                    default:
188                                          if (sad8 < pMB->sad16) {                          interpolate8x8_halfpel_hv(data->RefQ, data->RefP[4] + offset, stride, data->rounding);
189                                                  sad8 += pMB->sad8[0] =                          sad = sad8(data->CurU, data->RefQ, stride);
                                                         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  
                                          */  
190    
191                                          if (sad8 < pMB->sad16) {                          interpolate8x8_halfpel_hv(data->RefQ, data->RefP[5] + offset, stride, data->rounding);
192                                                  pMB->mode = MODE_INTER4V;                          sad += sad8(data->CurV, data->RefQ, stride);
193                                                  pMB->sad8[0] *= 4;                          break;
                                                 pMB->sad8[1] *= 4;  
                                                 pMB->sad8[2] *= 4;  
                                                 pMB->sad8[3] *= 4;  
                                                 continue;  
194                                          }                                          }
195            data->temp[7] = sad; //backup, part 2
196            return sad;
197                                  }                                  }
198    
199                          pMB->mode = MODE_INTER;  static __inline const uint8_t *
200                          pMB->pmvs[0] = pmv;     /* pMB->pmvs[1] = pMB->pmvs[2] = pMB->pmvs[3]  are not needed for INTER */  GetReferenceB(const int x, const int y, const uint32_t dir, const SearchData * const data)
201                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mv16;  {
202                          pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] =  //      dir : 0 = forward, 1 = backward
203                                  pMB->sad16;          const uint8_t *const *const direction = ( dir == 0 ? data->RefP : data->b_RefP );
204                          }          const int picture = ((x&1)<<1) | (y&1);
205            const int offset = (x>>1) + (y>>1)*data->iEdgedWidth;
206            return direction[picture] + offset;
207                          }                          }
208    
209          return 0;  // this is a simpler copy of GetReferenceB, but as it's __inline anyway, we can keep the two separate
210    static __inline const uint8_t *
211    GetReference(const int x, const int y, const SearchData * const data)
212    {
213            const int picture = ((x&1)<<1) | (y&1);
214            const int offset = (x>>1) + (y>>1)*data->iEdgedWidth;
215            return data->RefP[picture] + offset;
216  }  }
217    
218    static uint8_t *
219  #define CHECK_MV16_ZERO {\  Interpolate8x8qpel(const int x, const int y, const uint32_t block, const uint32_t dir, const SearchData * const data)
   if ( (0 <= max_dx) && (0 >= min_dx) \  
     && (0 <= max_dy) && (0 >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \  
     iSAD += calc_delta_16(-center_x, -center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=0; currMV->y=0; }  }     \  
 }  
   
 #define NOCHECK_MV16_CANDIDATE(X,Y) { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \  
 }  
   
 #define CHECK_MV16_CANDIDATE(X,Y) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_CANDIDATE_DIR(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \  
 }  
   
 #define CHECK_MV16_CANDIDATE_FOUND(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
 }  
   
   
 #define CHECK_MV8_ZERO {\  
   iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, 0, 0 , iEdgedWidth), iEdgedWidth); \  
   iSAD += calc_delta_8(-center_x, -center_y, (uint8_t)iFcode, iQuant);\  
   if (iSAD < iMinSAD) \  
   { iMinSAD=iSAD; currMV->x=0; currMV->y=0; } \  
 }  
   
 #define NOCHECK_MV8_CANDIDATE(X,Y) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \  
 }  
   
 #define CHECK_MV8_CANDIDATE(X,Y) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV8_CANDIDATE_DIR(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \  
 }  
   
 #define CHECK_MV8_CANDIDATE_FOUND(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
 }  
   
 /* too slow and not fully functional at the moment */  
 /*  
 int32_t ZeroSearch16(  
                                         const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const IMAGE * const pCur,  
                                         const int x, const int y,  
                                         const uint32_t MotionFlags,  
                                         const uint32_t iQuant,  
                                         const uint32_t iFcode,  
                                         MBParam * const pParam,  
                                         const MACROBLOCK * const pMBs,  
                                         const MACROBLOCK * const prevMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
220  {  {
221          const int32_t iEdgedWidth = pParam->edged_width;  // create or find a qpel-precision reference picture; return pointer to it
222          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;          uint8_t * Reference = data->RefQ + 16*dir;
223          int32_t iSAD;          const uint32_t iEdgedWidth = data->iEdgedWidth;
224          VECTOR pred;          const uint32_t rounding = data->rounding;
225            const int halfpel_x = x/2;
226            const int halfpel_y = y/2;
227            const uint8_t *ref1, *ref2, *ref3, *ref4;
228    
229          pred = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
230            ref1 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
231            switch( ((x&1)<<1) + (y&1) ) {
232            case 3: // x and y in qpel resolution - the "corners" (top left/right and
233                            // bottom left/right) during qpel refinement
234                    ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
235                    ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
236                    ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);
237                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
238                    ref3 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
239                    ref4 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
240                    interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
241                    break;
242    
243          iSAD = sad16( cur,          case 1: // x halfpel, y qpel - top or bottom during qpel refinement
244                  get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth),                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
245                  iEdgedWidth, MV_MAX_ERROR);                  ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
246          if (iSAD <= iQuant * 96)                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
247                  iSAD -= MV16_00_BIAS;                  break;
248    
249          currMV->x = 0;          case 2: // x qpel, y halfpel - left or right during qpel refinement
250          currMV->y = 0;                  ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
251          currPMV->x = -pred.x;                  ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
252          currPMV->y = -pred.y;                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
253                    break;
254    
255          return iSAD;          default: // pure halfpel position
256                    return (uint8_t *) ref1;
257    
258  }  }
259  */          return Reference;
   
 int32_t  
 Diamond16_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)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iDirectionBackup;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
   
         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);  
                 }  
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
         }  
         return iMinSAD;  
260  }  }
261    
262  int32_t  static uint8_t *
263  Square16_MainSearch(const uint8_t * const pRef,  Interpolate16x16qpel(const int x, const int y, const uint32_t dir, const SearchData * const data)
264                                          const uint8_t * const pRefH,  {
265                                          const uint8_t * const pRefV,  // create or find a qpel-precision reference picture; return pointer to it
266                                          const uint8_t * const pRefHV,          uint8_t * Reference = data->RefQ + 16*dir;
267                                          const uint8_t * const cur,          const uint32_t iEdgedWidth = data->iEdgedWidth;
268                                          const int x,          const uint32_t rounding = data->rounding;
269                                          const int y,          const int halfpel_x = x/2;
270                                     const int start_x,          const int halfpel_y = y/2;
271                                     const int start_y,          const uint8_t *ref1, *ref2, *ref3, *ref4;
                                    int iMinSAD,  
                                    VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a square search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* It's one search with full square pattern, and new parts for all following diamonds */  
   
 /*   new direction are extra, so 1-4 is normal diamond  
       537  
       1*2  
       648  
 */  
   
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
   
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 5);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 6);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 7);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 8);  
   
   
         if (iDirection) {  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;  
   
                         switch (iDirection) {  
                         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;  
272    
273                          case 3:          ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
274                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,          switch( ((x&1)<<1) + (y&1) ) {
275                                                                                   4);          case 3: // x and y in qpel resolution - the "corners" (top left/right and
276                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                          // bottom left/right) during qpel refinement
277                                                                                   backupMV.y - iDiamondSize, 7);                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
278                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                  ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
279                                                                                   backupMV.y + iDiamondSize, 8);                  ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);
280                    interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
281                    interpolate8x8_avg4(Reference+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, rounding);
282                    interpolate8x8_avg4(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, rounding);
283                    interpolate8x8_avg4(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, rounding);
284                                  break;                                  break;
285    
286                          case 4:          case 1: // x halfpel, y qpel - top or bottom during qpel refinement
287                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
288                                                                                   3);                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
289                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
290                                                                                   backupMV.y - iDiamondSize, 5);                  interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
291                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 break;  
   
                         case 5:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
   
                         case 6:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
   
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
   
292                                  break;                                  break;
293    
294                          case 7:          case 2: // x qpel, y halfpel - left or right during qpel refinement
295                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
296                                                                                     backupMV.y, 1);                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
297                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                  interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
298                                                                                   4);                  interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
299                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
                                                                                  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);  
300                                  break;                                  break;
301    
302                          case 8:          default: // pure halfpel position
303                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,                  return (uint8_t *) ref1;
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         default:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
   
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
304                          }                          }
305            return Reference;
306                  }                  }
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
         }  
         return iMinSAD;  
 }  
   
   
 int32_t  
 Full16_MainSearch(const uint8_t * const pRef,  
                                   const uint8_t * const pRefH,  
                                   const uint8_t * const pRefV,  
                                   const uint8_t * const pRefHV,  
                                   const uint8_t * const cur,  
                                   const int x,  
                                   const int y,  
                                    const int start_x,  
                                    const int start_y,  
                                    int iMinSAD,  
                                    VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                   const int32_t min_dx,  
                                   const int32_t max_dx,  
                                   const int32_t min_dy,  
                                   const int32_t max_dy,  
                                   const int32_t iEdgedWidth,  
                                   const int32_t iDiamondSize,  
                                   const int32_t iFcode,  
                                   const int32_t iQuant,  
                                   int iFound)  
 {  
         int32_t iSAD;  
         int32_t dx, dy;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV16_CANDIDATE(dx, dy);  
307    
308          return iMinSAD;  /* CHECK_CANDIATE FUNCTIONS START */
 }  
309    
310  int32_t  static void
311  AdvDiamond16_MainSearch(const uint8_t * const pRef,  CheckCandidate16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                                                 const uint8_t * const pRefH,  
                                                 const uint8_t * const pRefV,  
                                                 const uint8_t * const pRefHV,  
                                                 const uint8_t * const cur,  
                                                 const int x,  
                                                 const int y,  
                                            int start_x,  
                                            int start_y,  
                                            int iMinSAD,  
                                            VECTOR * const currMV,  
                                            const int center_x,  
                                            const int center_y,  
                                                 const int32_t min_dx,  
                                                 const int32_t max_dx,  
                                                 const int32_t min_dy,  
                                                 const int32_t max_dy,  
                                                 const int32_t iEdgedWidth,  
                                                 const int32_t iDiamondSize,  
                                                 const int32_t iFcode,  
                                                 const int32_t iQuant,  
                                                 int iDirection)  
312  {  {
313            int xc, yc;
314            const uint8_t * Reference;
315            VECTOR * current;
316            int32_t sad; uint32_t t;
317    
318          int32_t iSAD;          if ( (x > data->max_dx) || (x < data->min_dx)
319                    || (y > data->max_dy) || (y < data->min_dy) ) return;
 /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */  
320    
321          if (iDirection) {          if (!data->qpel_precision) {
322                  CHECK_MV16_CANDIDATE(start_x - iDiamondSize, start_y);                  Reference = GetReference(x, y, data);
323                  CHECK_MV16_CANDIDATE(start_x + iDiamondSize, start_y);                  current = data->currentMV;
324                  CHECK_MV16_CANDIDATE(start_x, start_y - iDiamondSize);                  xc = x; yc = y;
325                  CHECK_MV16_CANDIDATE(start_x, start_y + iDiamondSize);          } else { // x and y are in 1/4 precision
326          } else {                  Reference = Interpolate16x16qpel(x, y, 0, data);
327                  int bDirection = 1 + 2 + 4 + 8;                  xc = x/2; yc = y/2; //for chroma sad
328                    current = data->currentQMV;
329                  do {          }
                         iDirection = 0;  
                         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);  
   
                         if (bDirection & 2)  
                                 CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
330    
331                          if (bDirection & 4)          sad = sad16v(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
332                                  CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);          t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
333    
334                          if (bDirection & 8)          sad += (data->lambda16 * t * sad)>>10;
335                                  CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;
336    
337                          /* now we're doing diagonal checks near our candidate */          if (data->chroma) sad += ChromaSAD(     (xc >> 1) + roundtab_79[xc & 0x3],
338                                                                                    (yc >> 1) + roundtab_79[yc & 0x3], data);
339    
340                          if (iDirection)         //checking if anything found          if (sad < data->iMinSAD[0]) {
341                          {                  data->iMinSAD[0] = sad;
342                                  bDirection = iDirection;                  current[0].x = x; current[0].y = y;
343                                  iDirection = 0;                  *dir = Direction;
                                 start_x = currMV->x;  
                                 start_y = currMV->y;  
                                 if (bDirection & 3)     //our candidate is left or right  
                                 {  
                                         CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);  
                                 } else                  // what remains here is up or down  
                                 {  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
344                                  }                                  }
345    
346                                  if (iDirection) {          if (data->temp[1] < data->iMinSAD[1]) {
347                                          bDirection += iDirection;                  data->iMinSAD[1] = data->temp[1]; current[1].x = x; current[1].y = y; }
348                                          start_x = currMV->x;          if (data->temp[2] < data->iMinSAD[2]) {
349                                          start_y = currMV->y;                  data->iMinSAD[2] = data->temp[2]; current[2].x = x; current[2].y = y; }
350            if (data->temp[3] < data->iMinSAD[3]) {
351                    data->iMinSAD[3] = data->temp[3]; current[3].x = x; current[3].y = y; }
352            if (data->temp[4] < data->iMinSAD[4]) {
353                    data->iMinSAD[4] = data->temp[4]; current[4].x = x; current[4].y = y; }
354                                  }                                  }
                         } else                          //about to quit, eh? not so fast....  
                         {  
                                 switch (bDirection) {  
                                 case 2:  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1:  
355    
356                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  static void
357                                                                                           start_y - iDiamondSize, 1 + 4);  CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 2 + 4:  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 4:  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         break;  
                                 case 8:  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 1 + 4:  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         break;  
                                 case 2 + 8:  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1 + 8:  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         break;  
                                 default:                //1+2+4+8 == we didn't find anything at all  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 }  
                                 if (!iDirection)  
                                         break;          //ok, the end. really  
                                 else {  
                                         bDirection = iDirection;  
                                         start_x = currMV->x;  
                                         start_y = currMV->y;  
                                 }  
                         }  
                 }  
                 while (1);                              //forever  
         }  
         return iMinSAD;  
 }  
   
 #define CHECK_MV16_F_INTERPOL(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); } } \  
 }  
   
 #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,  
   
                                          const int x,  
                                          const int y,  
   
                                    const int f_start_x,  
                                    const int f_start_y,  
                                    const int b_start_x,  
                                    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,  
   
                                         const int x,  
                                         const int y,  
   
                                         const int TRB,  
                                         const int TRD,  
   
                                     const int start_x,  
                                     const int start_y,  
   
                                     int iMinSAD,  
                                     VECTOR * const currMV,  
                                         const VECTOR * const directmv,  
   
                                     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 iQuant,  
                                         int iFound)  
358  {  {
359  /* Do a diamond search around given starting point, return SAD of best */          int32_t sad; uint32_t t;
360            const uint8_t * Reference;
361          int32_t iSAD;          VECTOR * current;
   
         VECTOR backupMV;  
362    
363          currMV->x = start_x;          if ( (x > data->max_dx) || (x < data->min_dx)
364          currMV->y = start_y;                  || (y > data->max_dy) || (y < data->min_dy) ) return;
365    
366  /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */          if (!data->qpel_precision) {
367                    Reference = GetReference(x, y, data);
368          do                  current = data->currentMV;
369          {          } else { // x and y are in 1/4 precision
370                  iFound = 1;                  Reference = Interpolate8x8qpel(x, y, 0, 0, data);
371                    current = data->currentQMV;
372                  backupMV = *currMV;          }
373    
374                  CHECK_MV16_DIRECT_FOUND(backupMV.x - iDiamondSize, backupMV.y);          sad = sad8(data->Cur, Reference, data->iEdgedWidth);
375                  CHECK_MV16_DIRECT_FOUND(backupMV.x + iDiamondSize, backupMV.y);          t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
                 CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y - iDiamondSize);  
                 CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y + iDiamondSize);  
376    
377          } while (!iFound);          sad += (data->lambda8 * t * (sad+NEIGH_8X8_BIAS))>>10;
378    
379          return iMinSAD;          if (sad < *(data->iMinSAD)) {
380                    *(data->iMinSAD) = sad;
381                    current->x = x; current->y = y;
382                    *dir = Direction;
383            }
384  }  }
385    
386    static void
387  int32_t  CheckCandidate32(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
 AdvDiamond8_MainSearch(const uint8_t * const pRef,  
                                            const uint8_t * const pRefH,  
                                            const uint8_t * const pRefV,  
                                            const uint8_t * const pRefHV,  
                                            const uint8_t * const cur,  
                                            const int x,  
                                            const int y,  
                                            int start_x,  
                                            int start_y,  
                                            int iMinSAD,  
                                            VECTOR * const currMV,  
                                            const int center_x,  
                                            const int center_y,  
                                            const int32_t min_dx,  
                                            const int32_t max_dx,  
                                            const int32_t min_dy,  
                                            const int32_t max_dy,  
                                            const int32_t iEdgedWidth,  
                                            const int32_t iDiamondSize,  
                                            const int32_t iFcode,  
                                            const int32_t iQuant,  
                                            int iDirection)  
388  {  {
389            uint32_t t;
390            const uint8_t * Reference;
391    
392          int32_t iSAD;          if ( (!(x&1) && x !=0) || (!(y&1) && y !=0) || //non-zero even value
393                    (x > data->max_dx) || (x < data->min_dx)
394  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */                  || (y > data->max_dy) || (y < data->min_dy) ) return;
   
         if (iDirection) {  
                 CHECK_MV8_CANDIDATE(start_x - iDiamondSize, start_y);  
                 CHECK_MV8_CANDIDATE(start_x + iDiamondSize, start_y);  
                 CHECK_MV8_CANDIDATE(start_x, start_y - iDiamondSize);  
                 CHECK_MV8_CANDIDATE(start_x, start_y + iDiamondSize);  
         } else {  
                 int bDirection = 1 + 2 + 4 + 8;  
   
                 do {  
                         iDirection = 0;  
                         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_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
395    
396                          if (bDirection & 2)          Reference = GetReference(x, y, data);
397                                  CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);          t = d_mv_bits(x, y, data->predMV, data->iFcode, 0, 1);
398    
399                          if (bDirection & 4)          data->temp[0] = sad32v_c(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
                                 CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);  
400    
401                          if (bDirection & 8)          data->temp[0] += (data->lambda16 * t * data->temp[0]) >> 10;
402                                  CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;
403    
404                          /* now we're doing diagonal checks near our candidate */          if (data->temp[0] < data->iMinSAD[0]) {
405                    data->iMinSAD[0] = data->temp[0];
406                    data->currentMV[0].x = x; data->currentMV[0].y = y;
407                    *dir = Direction; }
408    
409                          if (iDirection)         //checking if anything found          if (data->temp[1] < data->iMinSAD[1]) {
410                          {                  data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
411                                  bDirection = iDirection;          if (data->temp[2] < data->iMinSAD[2]) {
412                                  iDirection = 0;                  data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
413                                  start_x = currMV->x;          if (data->temp[3] < data->iMinSAD[3]) {
414                                  start_y = currMV->y;                  data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
415                                  if (bDirection & 3)     //our candidate is left or right          if (data->temp[4] < data->iMinSAD[4]) {
416                                  {                  data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
                                         CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);  
                                 } else                  // what remains here is up or down  
                                 {  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
417                                  }                                  }
418    
419                                  if (iDirection) {  static void
420                                          bDirection += iDirection;  CheckCandidate16no4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                                         start_x = currMV->x;  
                                         start_y = currMV->y;  
                                 }  
                         } else                          //about to quit, eh? not so fast....  
421                          {                          {
422                                  switch (bDirection) {          int32_t sad, xc, yc;
423                                  case 2:          const uint8_t * Reference;
424                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,          uint32_t t;
425                                                                                          start_y - iDiamondSize, 2 + 4);          VECTOR * current;
                                         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;  
 }  
426    
427            if ( (x > data->max_dx) || ( x < data->min_dx)
428                    || (y > data->max_dy) || (y < data->min_dy) ) return;
429    
430  int32_t          if (data->rrv && (!(x&1) && x !=0) | (!(y&1) && y !=0) ) return; //non-zero even value
 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);  
431    
432          return iMinSAD;          if (data->qpel_precision) { // x and y are in 1/4 precision
433                    Reference = Interpolate16x16qpel(x, y, 0, data);
434                    current = data->currentQMV;
435                    xc = x/2; yc = y/2;
436            } else {
437                    Reference = GetReference(x, y, data);
438                    current = data->currentMV;
439                    xc = x; yc = y;
440  }  }
441            t = d_mv_bits(x, y, data->predMV, data->iFcode,
442                                            data->qpel^data->qpel_precision, data->rrv);
443    
444  Halfpel8_RefineFuncPtr Halfpel8_Refine;          sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
445            sad += (data->lambda16 * t * sad)>>10;
446    
447  int32_t          if (data->chroma) sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
448  Halfpel16_Refine(const uint8_t * const pRef,                                                                                  (yc >> 1) + roundtab_79[yc & 0x3], 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,  
                                  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) */  
449    
450          int32_t iSAD;          if (sad < *(data->iMinSAD)) {
451          VECTOR backupMV = *currMV;                  *(data->iMinSAD) = sad;
452                    current->x = x; current->y = y;
453          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y - 1);                  *dir = Direction;
454          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;  
455  }  }
456    
457  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)  static void
458    CheckCandidate32I(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
   
   
 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)  
459  {  {
460          const uint32_t iWcount = pParam->mb_width;  // maximum speed - for P/B/I decision
461          const int32_t iWidth = pParam->width;          int32_t sad;
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
   
         const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;  
462    
463          int32_t iDiamondSize;          if ( (x > data->max_dx) || (x < data->min_dx)
464                    || (y > data->max_dy) || (y < data->min_dy) ) return;
465    
466          int32_t min_dx;          sad = sad32v_c(data->Cur, data->RefP[0] + (x>>1) + (y>>1)*(data->iEdgedWidth),
467          int32_t max_dx;                                          data->iEdgedWidth, data->temp+1);
         int32_t min_dy;  
         int32_t max_dy;  
468    
469          int32_t iFound;          if (sad < *(data->iMinSAD)) {
470                    *(data->iMinSAD) = sad;
471          VECTOR newMV;                  data->currentMV[0].x = x; data->currentMV[0].y = y;
472          VECTOR backupMV;                        /* just for PMVFAST */                  *dir = Direction;
473            }
474          VECTOR pmv[4];          if (data->temp[1] < data->iMinSAD[1]) {
475          int32_t psad[4];                  data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
476            if (data->temp[2] < data->iMinSAD[2]) {
477          MainSearch16FuncPtr MainSearchPtr;                  data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
478            if (data->temp[3] < data->iMinSAD[3]) {
479          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;                  data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
480            if (data->temp[4] < data->iMinSAD[4]) {
481          int32_t threshA, threshB;                  data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
         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 */  
482    
         if (!(MotionFlags & PMV_HALFPEL16)) {  
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
483          }          }
484    
485          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  static void
486          //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)
487          bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);  {
488            int32_t sad, xb, yb, xcf, ycf, xcb, ycb;
489            uint32_t t;
490            const uint8_t *ReferenceF, *ReferenceB;
491            VECTOR *current;
492    
493            if ((xf > data->max_dx) || (xf < data->min_dx) ||
494                    (yf > data->max_dy) || (yf < data->min_dy))
495                    return;
496    
497          if ((x == 0) && (y == 0)) {          if (!data->qpel_precision) {
498                  threshA = 512;                  ReferenceF = GetReference(xf, yf, data);
499                  threshB = 1024;                  xb = data->currentMV[1].x; yb = data->currentMV[1].y;
500                    ReferenceB = GetReferenceB(xb, yb, 1, data);
501                    current = data->currentMV;
502                    xcf = xf; ycf = yf;
503                    xcb = xb; ycb = yb;
504          } else {          } else {
505                  threshA = psad[0];                  ReferenceF = Interpolate16x16qpel(xf, yf, 0, data);
506                  threshB = threshA + 256;                  xb = data->currentQMV[1].x; yb = data->currentQMV[1].y;
507                  if (threshA < 512)                  current = data->currentQMV;
508                          threshA = 512;                  ReferenceB = Interpolate16x16qpel(xb, yb, 1, data);
509                  if (threshA > 1024)                  xcf = xf/2; ycf = yf/2;
510                          threshA = 1024;                  xcb = xb/2; ycb = yb/2;
                 if (threshB > 1792)  
                         threshB = 1792;  
511          }          }
512    
513          iFound = 0;          t = d_mv_bits(xf, yf, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0)
514                            + d_mv_bits(xb, yb, data->bpredMV, data->iFcode, data->qpel^data->qpel_precision, 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.  
 */  
515    
516          currMV->x = start_x;          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
517          currMV->y = start_y;          sad += (data->lambda16 * t * sad)>>10;
518    
519          if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */          if (data->chroma) sad += ChromaSAD2((xcf >> 1) + roundtab_79[xcf & 0x3],
520                  currMV->x = EVEN(currMV->x);                                                                                  (ycf >> 1) + roundtab_79[ycf & 0x3],
521                  currMV->y = EVEN(currMV->y);                                                                                  (xcb >> 1) + roundtab_79[xcb & 0x3],
522          }                                                                                  (ycb >> 1) + roundtab_79[ycb & 0x3], data);
523    
524          if (currMV->x > max_dx) {          if (sad < *(data->iMinSAD)) {
525                  currMV->x = max_dx;                  *(data->iMinSAD) = sad;
526          }                  current->x = xf; current->y = yf;
527          if (currMV->x < min_dx) {                  *dir = Direction;
                 currMV->x = min_dx;  
528          }          }
         if (currMV->y > max_dy) {  
                 currMV->y = max_dy;  
529          }          }
         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);  
530    
531          if ((iMinSAD < 256) ||  static void
532                  ((MVequal(*currMV, prevMB->mvs[0])) &&  CheckCandidateDirect(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
533                  {                  {
534                          if (!MVzero(*currMV)) {          int32_t sad = 0, xcf = 0, ycf = 0, xcb = 0, ycb = 0;
535                                  iMinSAD += MV16_00_BIAS;          uint32_t k;
536                                  CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures          const uint8_t *ReferenceF;
537                                  iMinSAD -= MV16_00_BIAS;          const uint8_t *ReferenceB;
538                          }          VECTOR mvs, b_mvs;
                 }  
539    
540                  if (MotionFlags & PMV_QUICKSTOP16)          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
541                          goto PMVfast16_Terminate_without_Refine;  
542                  if (MotionFlags & PMV_EARLYSTOP16)          for (k = 0; k < 4; k++) {
543                          goto PMVfast16_Terminate_with_Refine;                  mvs.x = data->directmvF[k].x + x;
544                    b_mvs.x = ((x == 0) ?
545                            data->directmvB[k].x
546                            : mvs.x - data->referencemv[k].x);
547    
548                    mvs.y = data->directmvF[k].y + y;
549                    b_mvs.y = ((y == 0) ?
550                            data->directmvB[k].y
551                            : mvs.y - data->referencemv[k].y);
552    
553                    if ((mvs.x > data->max_dx)   || (mvs.x < data->min_dx)   ||
554                            (mvs.y > data->max_dy)   || (mvs.y < data->min_dy)   ||
555                            (b_mvs.x > data->max_dx) || (b_mvs.x < data->min_dx) ||
556                            (b_mvs.y > data->max_dy) || (b_mvs.y < data->min_dy) )
557                            return;
558    
559                    if (data->qpel) {
560                            xcf += mvs.x/2; ycf += mvs.y/2;
561                            xcb += b_mvs.x/2; ycb += b_mvs.y/2;
562                    } else {
563                            xcf += mvs.x; ycf += mvs.y;
564                            xcb += b_mvs.x; ycb += b_mvs.y;
565                            mvs.x *= 2; mvs.y *= 2; //we move to qpel precision anyway
566                            b_mvs.x *= 2; b_mvs.y *= 2;
567          }          }
568    
569                    ReferenceF = Interpolate8x8qpel(mvs.x, mvs.y, k, 0, data);
570                    ReferenceB = Interpolate8x8qpel(b_mvs.x, b_mvs.y, k, 1, data);
571    
572  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion                  sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
573     vector of the median.                                                  ReferenceF, ReferenceB, data->iEdgedWidth);
574     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2                  if (sad > *(data->iMinSAD)) return;
575  */          }
576    
577          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[0])))          sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;
                 iFound = 2;  
578    
579  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          if (data->chroma) sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],
580     Otherwise select large Diamond Search.                                                                                  (ycf >> 3) + roundtab_76[ycf & 0xf],
581  */                                                                                  (xcb >> 3) + roundtab_76[xcb & 0xf],
582                                                                                    (ycb >> 3) + roundtab_76[ycb & 0xf], data);
583    
584          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))          if (sad < *(data->iMinSAD)) {
585                  iDiamondSize = 1;               // halfpel!                  *(data->iMinSAD) = sad;
586          else                  data->currentMV->x = x; data->currentMV->y = y;
587                  iDiamondSize = 2;               // halfpel!                  *dir = Direction;
588            }
589    }
590    
591          if (!(MotionFlags & PMV_HALFPELDIAMOND16))  static void
592                  iDiamondSize *= 2;  CheckCandidateDirectno4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
593    {
594            int32_t sad, xcf, ycf, xcb, ycb;
595            const uint8_t *ReferenceF;
596            const uint8_t *ReferenceB;
597            VECTOR mvs, b_mvs;
598    
599  /*          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
    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.  
 */  
600    
601  // (0,0) is always possible          mvs.x = data->directmvF[0].x + x;
602            b_mvs.x = ((x == 0) ?
603                    data->directmvB[0].x
604                    : mvs.x - data->referencemv[0].x);
605    
606          if (!MVzero(pmv[0]))          mvs.y = data->directmvF[0].y + y;
607                  CHECK_MV16_ZERO;          b_mvs.y = ((y == 0) ?
608                    data->directmvB[0].y
609                    : mvs.y - data->referencemv[0].y);
610    
611  // previous frame MV is always possible          if ( (mvs.x > data->max_dx) || (mvs.x < data->min_dx)
612                    || (mvs.y > data->max_dy) || (mvs.y < data->min_dy)
613                    || (b_mvs.x > data->max_dx) || (b_mvs.x < data->min_dx)
614                    || (b_mvs.y > data->max_dy) || (b_mvs.y < data->min_dy) ) return;
615    
616          if (!MVzero(prevMB->mvs[0]))          if (data->qpel) {
617                  if (!MVequal(prevMB->mvs[0], pmv[0]))                  xcf = 4*(mvs.x/2); ycf = 4*(mvs.y/2);
618                          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);                  xcb = 4*(b_mvs.x/2); ycb = 4*(b_mvs.y/2);
619                    ReferenceF = Interpolate16x16qpel(mvs.x, mvs.y, 0, data);
620                    ReferenceB = Interpolate16x16qpel(b_mvs.x, b_mvs.y, 1, data);
621            } else {
622                    xcf = 4*mvs.x; ycf = 4*mvs.y;
623                    xcb = 4*b_mvs.x; ycb = 4*b_mvs.y;
624                    ReferenceF = GetReference(mvs.x, mvs.y, data);
625                    ReferenceB = GetReferenceB(b_mvs.x, b_mvs.y, 1, data);
626            }
627    
628  // left neighbour, if allowed          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
629            sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;
630    
631          if (!MVzero(pmv[1]))          if (data->chroma) sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],
632                  if (!MVequal(pmv[1], prevMB->mvs[0]))                                                                                  (ycf >> 3) + roundtab_76[ycf & 0xf],
633                          if (!MVequal(pmv[1], pmv[0])) {                                                                                  (xcb >> 3) + roundtab_76[xcb & 0xf],
634                                  if (!(MotionFlags & PMV_HALFPEL16)) {                                                                                  (ycb >> 3) + roundtab_76[ycb & 0xf], data);
                                         pmv[1].x = EVEN(pmv[1].x);  
                                         pmv[1].y = EVEN(pmv[1].y);  
                                 }  
635    
636                                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);          if (sad < *(data->iMinSAD)) {
637                    *(data->iMinSAD) = sad;
638                    data->currentMV->x = x; data->currentMV->y = y;
639                    *dir = Direction;
640                          }                          }
 // 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);  
641                                          }                                          }
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
642    
 // 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);  
                                                                         }  
                                 }  
643    
644          if ((MVzero(*currMV)) &&  static void
645                  (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  CheckCandidateBits16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
646                  iMinSAD -= MV16_00_BIAS;  {
647    
648            int16_t *in = data->dctSpace, *coeff = data->dctSpace + 64;
649            int32_t bits = 0;
650            VECTOR * current;
651            const uint8_t * ptr;
652            int i, cbp = 0, t, xc, yc;
653    
654  /* Step 6: If MinSAD <= thresa goto Step 10.          if ( (x > data->max_dx) || (x < data->min_dx)
655     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.                  || (y > data->max_dy) || (y < data->min_dy) ) return;
 */  
656    
657          if ((iMinSAD <= threshA) ||          if (!data->qpel_precision) {
658                  (MVequal(*currMV, prevMB->mvs[0]) &&                  ptr = GetReference(x, y, data);
659                   ((int32_t) iMinSAD < prevMB->sad16))) {                  current = data->currentMV;
660                  if (MotionFlags & PMV_QUICKSTOP16)                  xc = x; yc = y;
661                          goto PMVfast16_Terminate_without_Refine;          } else { // x and y are in 1/4 precision
662                  if (MotionFlags & PMV_EARLYSTOP16)                  ptr = Interpolate16x16qpel(x, y, 0, data);
663                          goto PMVfast16_Terminate_with_Refine;                  current = data->currentQMV;
664                    xc = x/2; yc = y/2;
665          }          }
666    
667            for(i = 0; i < 4; i++) {
668                    int s = 8*((i&1) + (i>>1)*data->iEdgedWidth);
669                    transfer_8to16subro(in, data->Cur + s, ptr + s, data->iEdgedWidth);
670                    bits += data->temp[i] = Block_CalcBits(coeff, in, data->iQuant, data->quant_type, &cbp, i);
671            }
672    
673  /************ (Diamond Search)  **************/          bits += t = BITS_MULT*d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
 /*  
    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.  
 */  
674    
675          if (MotionFlags & PMV_USESQUARES16)          if (data->temp[0] + t < data->iMinSAD[1]) {
676                  MainSearchPtr = Square16_MainSearch;                  data->iMinSAD[1] = data->temp[0] + t; current[1].x = x; current[1].y = y; }
677          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)          if (data->temp[1] < data->iMinSAD[2]) {
678                  MainSearchPtr = AdvDiamond16_MainSearch;                  data->iMinSAD[2] = data->temp[1]; current[2].x = x; current[2].y = y; }
679          else          if (data->temp[2] < data->iMinSAD[3]) {
680                  MainSearchPtr = Diamond16_MainSearch;                  data->iMinSAD[3] = data->temp[2]; current[3].x = x; current[3].y = y; }
681            if (data->temp[3] < data->iMinSAD[4]) {
682                    data->iMinSAD[4] = data->temp[3]; current[4].x = x; current[4].y = y; }
683    
         backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  
684    
685            bits += BITS_MULT*xvid_cbpy_tab[15-(cbp>>2)].len;
686    
687  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          if (bits >= data->iMinSAD[0]) return;
         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;  
         }  
688    
689          if (MotionFlags & PMV_EXTSEARCH16) {          //chroma
690  /* extended: search (up to) two more times: orignal prediction and (0,0) */          xc = (xc >> 1) + roundtab_79[xc & 0x3];
691            yc = (yc >> 1) + roundtab_79[yc & 0x3];
692    
693                  if (!(MVequal(pmv[0], backupMV))) {          //chroma U
694                          iSAD =          ptr = interpolate8x8_switch2(data->RefQ + 64, data->RefP[4], 0, 0, xc, yc,  data->iEdgedWidth/2, data->rounding);
695                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,          transfer_8to16subro(in, ptr, data->CurU, data->iEdgedWidth/2);
696                                                                    center_x, center_y, iMinSAD, &newMV, center_x, center_y,          bits += Block_CalcBits(coeff, in, data->iQuant, data->quant_type, &cbp, 4);
697                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,          if (bits >= data->iMinSAD[0]) return;
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
698    
699                          if (iSAD < iMinSAD) {          //chroma V
700                                  *currMV = newMV;          ptr = interpolate8x8_switch2(data->RefQ + 64, data->RefP[5], 0, 0, xc, yc,  data->iEdgedWidth/2, data->rounding);
701                                  iMinSAD = iSAD;          transfer_8to16subro(in, ptr, data->CurV, data->iEdgedWidth/2);
702                          }          bits += Block_CalcBits(coeff, in, data->iQuant, data->quant_type, &cbp, 5);
                 }  
703    
704                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTER & 7) | ((cbp & 3) << 3)].len;
                         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);  
705    
706                          if (iSAD < iMinSAD) {          if (bits < data->iMinSAD[0]) {
707                                  *currMV = newMV;                  data->iMinSAD[0] = bits;
708                                  iMinSAD = iSAD;                  current[0].x = x; current[0].y = y;
709                    *dir = Direction;
710                          }                          }
                 }  
         }  
   
 /*  
    Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  
 */  
711    
   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;  
712  }  }
713    
714    static void
715    CheckCandidateBits8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
716    {
717    
718            int16_t *in = data->dctSpace, *coeff = data->dctSpace + 64;
719            int32_t bits;
720            VECTOR * current;
721            const uint8_t * ptr;
722            int cbp = 0;
723    
724            if ( (x > data->max_dx) || (x < data->min_dx)
725                    || (y > data->max_dy) || (y < data->min_dy) ) return;
726    
727            if (!data->qpel_precision) {
728                    ptr = GetReference(x, y, data);
729                    current = data->currentMV;
730            } else { // x and y are in 1/4 precision
731                    ptr = Interpolate8x8qpel(x, y, 0, 0, data);
732                    current = data->currentQMV;
733            }
734    
735            transfer_8to16subro(in, data->Cur, ptr, data->iEdgedWidth);
736            bits = Block_CalcBits(coeff, in, data->iQuant, data->quant_type, &cbp, 5);
737            bits += BITS_MULT*d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
738    
739  int32_t          if (bits < data->iMinSAD[0]) {
740  Diamond8_MainSearch(const uint8_t * const pRef,                  data->temp[0] = cbp;
741                                          const uint8_t * const pRefH,                  data->iMinSAD[0] = bits;
742                                          const uint8_t * const pRefV,                  current[0].x = x; current[0].y = y;
743                                          const uint8_t * const pRefHV,                  *dir = Direction;
                                         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;  
744          }          }
         return iMinSAD;  
745  }  }
746    
747    /* CHECK_CANDIATE FUNCTIONS END */
748    
749    /* MAINSEARCH FUNCTIONS START */
750    
751    static void
752    AdvDiamondSearch(int x, int y, const SearchData * const data, int bDirection)
753    {
754    
755  int32_t  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
 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  
 */  
756    
757          CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);          int iDirection;
         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);  
758    
759            for(;;) { //forever
760                    iDirection = 0;
761                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
762                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
763                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
764                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
765    
766          if (iDirection) {                  /* now we're doing diagonal checks near our candidate */
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;  
767    
768                          switch (iDirection) {                  if (iDirection) {               //if anything found
769                          case 1:                          bDirection = iDirection;
770                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          iDirection = 0;
771                                                                                     backupMV.y, 1);                          x = data->currentMV->x; y = data->currentMV->y;
772                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          if (bDirection & 3) {   //our candidate is left or right
773                                                                                   backupMV.y - iDiamondSize, 5);                                  CHECK_CANDIDATE(x, y + iDiamondSize, 8);
774                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                                  CHECK_CANDIDATE(x, y - iDiamondSize, 4);
775                                                                                   backupMV.y - iDiamondSize, 7);                          } else {                        // what remains here is up or down
776                                  break;                                  CHECK_CANDIDATE(x + iDiamondSize, y, 2);
777                                    CHECK_CANDIDATE(x - iDiamondSize, y, 1);
778                            }
779    
780                            if (iDirection) {
781                                    bDirection += iDirection;
782                                    x = data->currentMV->x; y = data->currentMV->y;
783                            }
784                    } else {                                //about to quit, eh? not so fast....
785                            switch (bDirection) {
786                          case 2:                          case 2:
787                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
788                                                                                   2);                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
789                                  break;                                  break;
790                            case 1:
791                          case 3:                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
792                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                                                                  4);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
793                                  break;                                  break;
794                            case 2 + 4:
795                          case 4:                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
796                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
797                                                                                   3);                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                 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);  
   
798                                  break;                                  break;
799                            case 4:
800                          case 7:                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
801                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
                                                                                    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);  
802                                  break;                                  break;
   
803                          case 8:                          case 8:
804                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
805                                                                                   2);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                 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);  
806                                  break;                                  break;
807                          default:                          case 1 + 4:
808                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
809                                                                                   1);                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
810                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
811                                                                                   2);                                  break;
812                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,                          case 2 + 8:
813                                                                                   3);                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
814                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
815                                                                                   4);                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
816                                    break;
817                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          case 1 + 8:
818                                                                                   backupMV.y - iDiamondSize, 5);                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
819                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
820                                                                                   backupMV.y + iDiamondSize, 6);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
821                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                                  break;
822                                                                                   backupMV.y - iDiamondSize, 7);                          default:                //1+2+4+8 == we didn't find anything at all
823                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
824                                                                                   backupMV.y + iDiamondSize, 8);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
825                                    CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
826                                    CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
827                                  break;                                  break;
828                          }                          }
829                            if (!iDirection) break;         //ok, the end. really
830                            bDirection = iDirection;
831                            x = data->currentMV->x; y = data->currentMV->y;
832                  }                  }
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
833          }          }
         return iMinSAD;  
834  }  }
835    
836    static void
837    SquareSearch(int x, int y, const SearchData * const data, int bDirection)
838    {
839            int iDirection;
840    
841            do {
842                    iDirection = 0;
843                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);
844                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);
845                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);
846                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128);
847                    if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64);
848                    if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128);
849                    if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128);
850                    if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128);
851    
852                    bDirection = iDirection;
853                    x = data->currentMV->x; y = data->currentMV->y;
854  int32_t          } while (iDirection);
 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;  
855  }  }
856    
857    static void
858  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)  DiamondSearch(int x, int y, const SearchData * const data, int bDirection)
   
 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)  
859  {  {
         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;  
860    
861          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
862    
863          int32_t iDiamondSize;          int iDirection;
864    
865          int32_t min_dx;          do {
866          int32_t max_dx;                  iDirection = 0;
867          int32_t min_dy;                  if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
868          int32_t max_dy;                  if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
869                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
870                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
871    
872          VECTOR pmv[4];                  /* now we're doing diagonal checks near our candidate */
         int32_t psad[4];  
         VECTOR newMV;  
         VECTOR backupMV;  
         VECTOR startMV;  
873    
874  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;                  if (iDirection) {               //checking if anything found
875          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;                          bDirection = iDirection;
876                            iDirection = 0;
877                            x = data->currentMV->x; y = data->currentMV->y;
878                            if (bDirection & 3) {   //our candidate is left or right
879                                    CHECK_CANDIDATE(x, y + iDiamondSize, 8);
880                                    CHECK_CANDIDATE(x, y - iDiamondSize, 4);
881                            } else {                        // what remains here is up or down
882                                    CHECK_CANDIDATE(x + iDiamondSize, y, 2);
883                                    CHECK_CANDIDATE(x - iDiamondSize, y, 1);
884                            }
885                            bDirection += iDirection;
886                            x = data->currentMV->x; y = data->currentMV->y;
887                    }
888            }
889            while (iDirection);
890    }
891    
892           int32_t threshA, threshB;  /* MAINSEARCH FUNCTIONS END */
         int32_t iFound, bPredEq;  
         int32_t iMinSAD, iSAD;  
893    
894          int32_t iSubBlock = (y & 1) + (y & 1) + (x & 1);  static void
895    SubpelRefine(const SearchData * const data)
896    {
897    /* Do a half-pel or q-pel refinement */
898            const VECTOR centerMV = data->qpel_precision ? *data->currentQMV : *data->currentMV;
899            int iDirection; //only needed because macro expects it
900    
901          MainSearch8FuncPtr MainSearchPtr;          CHECK_CANDIDATE(centerMV.x, centerMV.y - 1, 0);
902            CHECK_CANDIDATE(centerMV.x + 1, centerMV.y - 1, 0);
903            CHECK_CANDIDATE(centerMV.x + 1, centerMV.y, 0);
904            CHECK_CANDIDATE(centerMV.x + 1, centerMV.y + 1, 0);
905            CHECK_CANDIDATE(centerMV.x, centerMV.y + 1, 0);
906            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y + 1, 0);
907            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y, 0);
908            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y - 1, 0);
909    }
910    
911          /* Init variables */  static __inline int
912          startMV.x = start_x;  SkipDecisionP(const IMAGE * current, const IMAGE * reference,
913          startMV.y = start_y;                                  const int x, const int y,
914                                    const uint32_t stride, const uint32_t iQuant, int rrv)
915    
916          /* Get maximum range */  {
917          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,          int offset = (x + y*stride)*8;
918                            iFcode);          if(!rrv) {
919                    uint32_t sadC = sad8(current->u + offset,
920                                                    reference->u + offset, stride);
921                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
922                    sadC += sad8(current->v + offset,
923                                                    reference->v + offset, stride);
924                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
925                    return 1;
926    
927          if (!(MotionFlags & PMV_HALFPELDIAMOND8)) {          } else {
928                  min_dx = EVEN(min_dx);                  uint32_t sadC = sad16(current->u + 2*offset,
929                  max_dx = EVEN(max_dx);                                                  reference->u + 2*offset, stride, 256*4096);
930                  min_dy = EVEN(min_dy);                  if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
931                  max_dy = EVEN(max_dy);                  sadC += sad16(current->v + 2*offset,
932                                                    reference->v + 2*offset, stride, 256*4096);
933                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
934                    return 1;
935            }
936          }          }
937    
938          /* because we might use IF (dx>max_dx) THEN dx=max_dx; */  static __inline void
939          //bPredEq = get_pmvdata(pMBs, (x >> 1), (y >> 1), iWcount, iSubBlock, pmv, psad);  SkipMacroblockP(MACROBLOCK *pMB, const int32_t sad)
940          bPredEq = get_pmvdata2(pMBs, iWcount, 0, (x >> 1), (y >> 1), iSubBlock, pmv, psad);  {
941            pMB->mode = MODE_NOT_CODED;
942          if ((x == 0) && (y == 0)) {          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = zeroMV;
943                  threshA = 512 / 4;          pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] = pMB->qmvs[3] = zeroMV;
944                  threshB = 1024 / 4;          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
945    }
946    
947    static __inline void
948    ModeDecision(SearchData * const Data,
949                            MACROBLOCK * const pMB,
950                            const MACROBLOCK * const pMBs,
951                            const int x, const int y,
952                            const MBParam * const pParam,
953                            const uint32_t MotionFlags,
954                            const uint32_t GlobalFlags,
955                            const IMAGE * const pCurrent,
956                            const IMAGE * const pRef)
957    {
958            int mode = MODE_INTER;
959            int inter4v = (GlobalFlags & XVID_INTER4V) && (pMB->dquant == NO_CHANGE);
960            const uint32_t iQuant = pMB->quant;
961    
962            const int skip_possible = (!(GlobalFlags & XVID_GMC)) && (pMB->dquant == NO_CHANGE);
963    
964            if (!(GlobalFlags & XVID_MODEDECISION_BITS)) { //normal, fast, SAD-based mode decision
965                    int sad;
966                    int InterBias = MV16_INTER_BIAS;
967                    if (inter4v == 0 || Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
968                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant) {
969                            mode = MODE_INTER;
970                            sad = Data->iMinSAD[0];
971          } else {          } else {
972                  threshA = psad[0] / 4;  /* good estimate? */                          mode = MODE_INTER4V;
973                  threshB = threshA + 256 / 4;                          sad = Data->iMinSAD[1] + Data->iMinSAD[2] +
974                  if (threshA < 512 / 4)                                                  Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant;
975                          threshA = 512 / 4;                          Data->iMinSAD[0] = sad;
976                  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.  
 */  
   
977    
978  // Prepare for main loop                  /* final skip decision, a.k.a. "the vector you found, really that good?" */
979                    if (skip_possible && (pMB->sad16 < (int)iQuant * MAX_SAD00_FOR_SKIP))
980                            if ( (100*sad)/(pMB->sad16+1) > FINAL_SKIP_THRESH)
981                                    if (Data->chroma || SkipDecisionP(pCurrent, pRef, x, y, Data->iEdgedWidth/2, iQuant, Data->rrv)) {
982                                            mode = MODE_NOT_CODED;
983                                            sad = 0;
984                                    }
985    
986    if (MotionFlags & PMV_USESQUARES8)                  /* intra decision */
       MainSearchPtr = Square8_MainSearch;  
   else  
987    
988          if (MotionFlags & PMV_ADVANCEDDIAMOND8)                  if (iQuant > 8) InterBias += 100 * (iQuant - 8); // to make high quants work
989                  MainSearchPtr = AdvDiamond8_MainSearch;                  if (y != 0)
990          else                          if ((pMB - pParam->mb_width)->mode == MODE_INTRA ) InterBias -= 80;
991                  MainSearchPtr = Diamond8_MainSearch;                  if (x != 0)
992                            if ((pMB - 1)->mode == MODE_INTRA ) InterBias -= 80;
993    
994                    if (Data->chroma) InterBias += 50; // dev8(chroma) ???
995                    if (Data->rrv) InterBias *= 4;
996    
997          *currMV = startMV;                  if (InterBias < pMB->sad16) {
998                            int32_t deviation;
999                            if (!Data->rrv) deviation = dev16(Data->Cur, Data->iEdgedWidth);
1000                            else deviation = dev16(Data->Cur, Data->iEdgedWidth) +
1001                                    dev16(Data->Cur+16, Data->iEdgedWidth) +
1002                                    dev16(Data->Cur + 16*Data->iEdgedWidth, Data->iEdgedWidth) +
1003                                    dev16(Data->Cur+16+16*Data->iEdgedWidth, Data->iEdgedWidth);
1004    
1005          iMinSAD =                          if (deviation < (sad - InterBias)) mode = MODE_INTRA;
1006                  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  
 */  
1007    
1008          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[iSubBlock])))          } else { // BITS
                 iFound = 2;  
1009    
1010  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.                  int bits, intra, i;
1011     Otherwise select large Diamond Search.                  VECTOR backup[5], *v;
1012  */                  Data->iQuant = iQuant;
1013    
1014          if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))                  v = Data->qpel ? Data->currentQMV : Data->currentMV;
1015                  iDiamondSize = 1;               // 1 halfpel!                  for (i = 0; i < 5; i++) {
1016          else                          Data->iMinSAD[i] = 256*4096;
1017                  iDiamondSize = 2;               // 2 halfpel = 1 full pixel!                          backup[i] = v[i];
1018                    }
1019    
1020          if (!(MotionFlags & PMV_HALFPELDIAMOND8))                  bits = CountMBBitsInter(Data, pMBs, x, y, pParam, MotionFlags);
1021                  iDiamondSize *= 2;                  if (bits == 0)
1022                            mode = MODE_INTER; // quick stop
1023                    else {
1024                            if (inter4v) {
1025                                    int bits_inter4v = CountMBBitsInter4v(Data, pMB, pMBs, x, y, pParam, MotionFlags, backup);
1026                                    if (bits_inter4v < bits) { Data->iMinSAD[0] = bits = bits_inter4v; mode = MODE_INTER4V; }
1027                            }
1028    
1029                            intra = CountMBBitsIntra(Data);
1030    
1031  /*                          if (intra < bits) { *Data->iMinSAD = bits = intra; mode = MODE_INTRA; }
1032     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.                  }
1033     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.  
 */  
1034    
1035  // the median prediction might be even better than mv16          if (Data->rrv) {
1036                            Data->currentMV[0].x = RRV_MV_SCALEDOWN(Data->currentMV[0].x);
1037                            Data->currentMV[0].y = RRV_MV_SCALEDOWN(Data->currentMV[0].y);
1038            }
1039    
1040          if (!MVequal(pmv[0], startMV))          if (mode == MODE_INTER) {
1041                  CHECK_MV8_CANDIDATE(center_x, center_y);                  pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
1042                    pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = Data->iMinSAD[0];
1043    
1044  // (0,0) if needed                  if(Data->qpel) {
1045          if (!MVzero(pmv[0]))                          pMB->qmvs[0] = pMB->qmvs[1]
1046                  if (!MVzero(startMV))                                  = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1047                          CHECK_MV8_ZERO;                          pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1048                            pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;
1049  // previous frame MV if needed                  } else {
1050          if (!MVzero(prevMB->mvs[iSubBlock]))                          pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1051                  if (!MVequal(prevMB->mvs[iSubBlock], startMV))                          pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
1052                          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;  
1053    
1054            } else if (mode == MODE_INTER4V)
1055                    pMB->sad16 = Data->iMinSAD[0];
1056            else // INTRA, NOT_CODED
1057                    SkipMacroblockP(pMB, 0);
1058    
1059  /* Step 6: If MinSAD <= thresa goto Step 10.          pMB->mode = mode;
1060     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  }
 */  
1061    
1062          if ((iMinSAD <= threshA) ||  bool
1063                  (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&  MotionEstimation(MBParam * const pParam,
1064                   ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {                                  FRAMEINFO * const current,
1065                  if (MotionFlags & PMV_QUICKSTOP16)                                  FRAMEINFO * const reference,
1066                          goto PMVfast8_Terminate_without_Refine;                                  const IMAGE * const pRefH,
1067                  if (MotionFlags & PMV_EARLYSTOP16)                                  const IMAGE * const pRefV,
1068                          goto PMVfast8_Terminate_with_Refine;                                  const IMAGE * const pRefHV,
1069          }                                  const uint32_t iLimit)
1070    {
1071  /************ (Diamond Search)  **************/          MACROBLOCK *const pMBs = current->mbs;
1072  /*          const IMAGE *const pCurrent = &current->image;
1073     Step 7: Perform Diamond search, with either the small or large diamond.          const IMAGE *const pRef = &reference->image;
    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.  
 */  
1074    
1075          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          uint32_t mb_width = pParam->mb_width;
1076            uint32_t mb_height = pParam->mb_height;
1077            const uint32_t iEdgedWidth = pParam->edged_width;
1078            const uint32_t MotionFlags = MakeGoodMotionFlags(current->motion_flags, current->global_flags);
1079    
1080            uint32_t x, y;
1081            uint32_t iIntra = 0;
1082            int32_t quant = current->quant, sad00;
1083            int skip_thresh = INITIAL_SKIP_THRESH *
1084                    (current->global_flags & XVID_REDUCED ? 4:1) *
1085                    (current->global_flags & XVID_MODEDECISION_BITS ? 2:1);
1086    
1087            // some pre-initialized thingies for SearchP
1088            int32_t temp[8];
1089            VECTOR currentMV[5];
1090            VECTOR currentQMV[5];
1091            int32_t iMinSAD[5];
1092            DECLARE_ALIGNED_MATRIX(dct_space, 2, 64, int16_t, CACHE_LINE);
1093            SearchData Data;
1094            memset(&Data, 0, sizeof(SearchData));
1095            Data.iEdgedWidth = iEdgedWidth;
1096            Data.currentMV = currentMV;
1097            Data.currentQMV = currentQMV;
1098            Data.iMinSAD = iMinSAD;
1099            Data.temp = temp;
1100            Data.iFcode = current->fcode;
1101            Data.rounding = pParam->m_rounding_type;
1102            Data.qpel = pParam->m_quarterpel;
1103            Data.chroma = MotionFlags & PMV_CHROMA16;
1104            Data.rrv = current->global_flags & XVID_REDUCED;
1105            Data.dctSpace = dct_space;
1106            Data.quant_type = pParam->m_quant_type;
1107    
1108            if ((current->global_flags & XVID_REDUCED)) {
1109                    mb_width = (pParam->width + 31) / 32;
1110                    mb_height = (pParam->height + 31) / 32;
1111                    Data.qpel = 0;
1112            }
1113    
1114            Data.RefQ = pRefV->u; // a good place, also used in MC (for similar purpose)
1115            if (sadInit) (*sadInit) ();
1116    
1117            for (y = 0; y < mb_height; y++) {
1118                    for (x = 0; x < mb_width; x++)  {
1119                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1120    
1121                            if (!Data.rrv) pMB->sad16 =
1122                                    sad16v(pCurrent->y + (x + y * iEdgedWidth) * 16,
1123                                                            pRef->y + (x + y * iEdgedWidth) * 16,
1124                                                            pParam->edged_width, pMB->sad8 );
1125    
1126                            else pMB->sad16 =
1127                                    sad32v_c(pCurrent->y + (x + y * iEdgedWidth) * 32,
1128                                                            pRef->y + (x + y * iEdgedWidth) * 32,
1129                                                            pParam->edged_width, pMB->sad8 );
1130    
1131                            if (Data.chroma) {
1132                                    Data.temp[7] = sad8(pCurrent->u + x*8 + y*(iEdgedWidth/2)*8,
1133                                                                            pRef->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2)
1134                                                                    + sad8(pCurrent->v + (x + y*(iEdgedWidth/2))*8,
1135                                                                            pRef->v + (x + y*(iEdgedWidth/2))*8, iEdgedWidth/2);
1136                                    pMB->sad16 += Data.temp[7];
1137                            }
1138    
1139  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                          sad00 = pMB->sad16;
         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);  
1140    
1141          if (iSAD < iMinSAD) {                          if (!(current->global_flags & XVID_LUMIMASKING))
1142                  *currMV = newMV;                                  pMB->dquant = NO_CHANGE;
1143                  iMinSAD = iSAD;                          else {
1144                                    if (pMB->dquant != NO_CHANGE) {
1145                                            quant += DQtab[pMB->dquant];
1146                                            if (quant > 31) quant = 31;
1147                                            else if (quant < 1) quant = 1;
1148                                    }
1149                            }
1150                            pMB->quant = quant;
1151    
1152    //initial skip decision
1153    /* no early skip for GMC (global vector = skip vector is unknown!)  */
1154                            if (!(current->global_flags & XVID_GMC))        { /* no fast SKIP for S(GMC)-VOPs */
1155                                    if (pMB->dquant == NO_CHANGE && sad00 < quant * skip_thresh)
1156                                            if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, iEdgedWidth/2, pMB->quant, Data.rrv)) {
1157                                                    SkipMacroblockP(pMB, sad00);
1158                                                    continue;
1159                                            }
1160          }          }
1161    
1162          if (MotionFlags & PMV_EXTSEARCH8) {                          SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1163  /* extended: search (up to) two more times: orignal prediction and (0,0) */                                                  y, MotionFlags, current->global_flags,
1164                                                    &Data, pParam, pMBs, reference->mbs, pMB);
1165    
1166                  if (!(MVequal(pmv[0], backupMV))) {                          ModeDecision(&Data, pMB, pMBs, x, y, pParam,
1167                          iSAD =                                                          MotionFlags, current->global_flags,
1168                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                                          pCurrent, pRef);
1169                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,  
1170                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,                          if (pMB->mode == MODE_INTRA)
1171                                                                    iDiamondSize, iFcode, iQuant, iFound);                                  if (++iIntra > iLimit) return 1;
1172                    }
1173            }
1174    
1175                          if (iSAD < iMinSAD) {          if (current->global_flags & XVID_GMC )  /* GMC only for S(GMC)-VOPs */
1176                                  *currMV = newMV;          {
1177                                  iMinSAD = iSAD;                  current->warp = GlobalMotionEst( pMBs, pParam, current, reference, pRefH, pRefV, pRefHV);
1178                          }                          }
1179            return 0;
1180                  }                  }
1181    
                 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);  
1182    
1183                          if (iSAD < iMinSAD) {  static __inline int
1184                                  *currMV = newMV;  make_mask(const VECTOR * const pmv, const int i)
1185                                  iMinSAD = iSAD;  {
1186            int mask = 255, j;
1187            for (j = 0; j < i; j++) {
1188                    if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already
1189                    if (pmv[i].x == pmv[j].x) {
1190                            if (pmv[i].y == pmv[j].y + iDiamondSize) mask &= ~4;
1191                            else if (pmv[i].y == pmv[j].y - iDiamondSize) mask &= ~8;
1192                    } else
1193                            if (pmv[i].y == pmv[j].y) {
1194                                    if (pmv[i].x == pmv[j].x + iDiamondSize) mask &= ~1;
1195                                    else if (pmv[i].x == pmv[j].x - iDiamondSize) mask &= ~2;
1196                          }                          }
1197                  }                  }
1198            return mask;
1199          }          }
1200    
1201  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.  static __inline void
1202     By performing an optional local half-pixel search, we can refine this result even further.  PreparePredictionsP(VECTOR * const pmv, int x, int y, int iWcount,
1203  */                          int iHcount, const MACROBLOCK * const prevMB, int rrv)
1204    {
1205    
1206    //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself
1207            if (rrv) { iWcount /= 2; iHcount /= 2; }
1208    
1209            if ( (y != 0) && (x < (iWcount-1)) ) {          // [5] top-right neighbour
1210                    pmv[5].x = EVEN(pmv[3].x);
1211                    pmv[5].y = EVEN(pmv[3].y);
1212            } else pmv[5].x = pmv[5].y = 0;
1213    
1214    PMVfast8_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
1215          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step          else pmv[3].x = pmv[3].y = 0;
                 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);  
1216    
1217            if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }// [4] top neighbour
1218            else pmv[4].x = pmv[4].y = 0;
1219    
1220    PMVfast8_Terminate_without_Refine:          // [1] median prediction
1221          currPMV->x = currMV->x - center_x;          pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
         currPMV->y = currMV->y - center_y;  
1222    
1223          return iMinSAD;          pmv[0].x = pmv[0].y = 0; // [0] is zero; not used in the loop (checked before) but needed here for make_mask
1224    
1225            pmv[2].x = EVEN(prevMB->mvs[0].x); // [2] is last frame
1226            pmv[2].y = EVEN(prevMB->mvs[0].y);
1227    
1228            if ((x < iWcount-1) && (y < iHcount-1)) {
1229                    pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); //[6] right-down neighbour in last frame
1230                    pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
1231            } else pmv[6].x = pmv[6].y = 0;
1232    
1233            if (rrv) {
1234                    int i;
1235                    for (i = 0; i < 7; i++) {
1236                            pmv[i].x = RRV_MV_SCALEUP(pmv[i].x);
1237                            pmv[i].y = RRV_MV_SCALEUP(pmv[i].y);
1238                    }
1239            }
1240  }  }
1241    
1242  int32_t  static void
1243  EPZSSearch16(const uint8_t * const pRef,  SearchP(const IMAGE * const pRef,
1244                           const uint8_t * const pRefH,                           const uint8_t * const pRefH,
1245                           const uint8_t * const pRefV,                           const uint8_t * const pRefV,
1246                           const uint8_t * const pRefHV,                           const uint8_t * const pRefHV,
1247                           const IMAGE * const pCur,                           const IMAGE * const pCur,
1248                           const int x,                           const int x,
1249                           const int y,                           const int y,
                         const int start_x,  
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
1250                           const uint32_t MotionFlags,                           const uint32_t MotionFlags,
1251                           const uint32_t iQuant,                  const uint32_t GlobalFlags,
1252                           const uint32_t iFcode,                  SearchData * const Data,
1253                           const MBParam * const pParam,                           const MBParam * const pParam,
1254                           const MACROBLOCK * const pMBs,                           const MACROBLOCK * const pMBs,
1255                           const MACROBLOCK * const prevMBs,                           const MACROBLOCK * const prevMBs,
1256                           VECTOR * const currMV,                  MACROBLOCK * const pMB)
                          VECTOR * const currPMV)  
1257  {  {
         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;  
1258    
1259          int32_t min_dx;          int i, iDirection = 255, mask, threshA;
1260          int32_t max_dx;          VECTOR pmv[7];
1261          int32_t min_dy;          int inter4v = (GlobalFlags & XVID_INTER4V) && (pMB->dquant == NO_CHANGE);
1262          int32_t max_dy;  
1263            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1264          VECTOR newMV;                                  pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
1265          VECTOR backupMV;  
1266            get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);
1267          VECTOR pmv[4];  
1268          int32_t psad[8];          Data->temp[5] = Data->temp[6] = 0; // chroma-sad cache
1269            i = Data->rrv ? 2 : 1;
1270          static MACROBLOCK *oldMBs = NULL;          Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16*i;
1271            Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1272            Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1273    
1274            Data->RefP[0] = pRef->y + (x + Data->iEdgedWidth*y) * 16*i;
1275            Data->RefP[2] = pRefH + (x + Data->iEdgedWidth*y) * 16*i;
1276            Data->RefP[1] = pRefV + (x + Data->iEdgedWidth*y) * 16*i;
1277            Data->RefP[3] = pRefHV + (x + Data->iEdgedWidth*y) * 16*i;
1278            Data->RefP[4] = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1279            Data->RefP[5] = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1280    
1281            Data->lambda16 = lambda_vec16[pMB->quant];
1282            Data->lambda8 = lambda_vec8[pMB->quant];
1283            Data->qpel_precision = 0;
1284    
1285            memset(Data->currentMV, 0, 5*sizeof(VECTOR));
1286    
1287            if (Data->qpel) Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1288            else Data->predMV = pmv[0];
1289    
1290            i = d_mv_bits(0, 0, Data->predMV, Data->iFcode, 0, 0);
1291            Data->iMinSAD[0] = pMB->sad16 + ((Data->lambda16 * i * pMB->sad16)>>10);
1292            Data->iMinSAD[1] = pMB->sad8[0] + ((Data->lambda8 * i * (pMB->sad8[0]+NEIGH_8X8_BIAS)) >> 10);
1293            Data->iMinSAD[2] = pMB->sad8[1];
1294            Data->iMinSAD[3] = pMB->sad8[2];
1295            Data->iMinSAD[4] = pMB->sad8[3];
1296    
1297            if ((!(GlobalFlags & XVID_MODEDECISION_BITS)) && (x | y)) {
1298                    threshA = Data->temp[0]; // that's where we keep this SAD atm
1299                    if (threshA < 512) threshA = 512;
1300                    else if (threshA > 1024) threshA = 1024;
1301            } else
1302                    threshA = 512;
1303    
1304  //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
1305          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;                                          prevMBs + x + y * pParam->mb_width, Data->rrv);
         MACROBLOCK *oldMB = NULL;  
1306    
1307           int32_t thresh2;          if (!Data->rrv) {
1308          int32_t bPredEq;                  if (inter4v | Data->chroma) CheckCandidate = CheckCandidate16;
1309          int32_t iMinSAD, iSAD = 9999;                          else CheckCandidate = CheckCandidate16no4v; //for extra speed
1310            } else CheckCandidate = CheckCandidate32;
1311    
1312    /* main loop. checking all predictions (but first, which is 0,0 and has been checked in MotionEstimation())*/
1313    
1314            for (i = 1; i < 7; i++) {
1315                    if (!(mask = make_mask(pmv, i)) ) continue;
1316                    CheckCandidate(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1317                    if (Data->iMinSAD[0] <= threshA) break;
1318            }
1319    
1320            if ((Data->iMinSAD[0] <= threshA) ||
1321                            (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
1322                            (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16)))
1323                    inter4v = 0;
1324            else {
1325    
1326          MainSearch16FuncPtr MainSearchPtr;                  MainSearchFunc * MainSearchPtr;
1327                    if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1328                    else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1329                            else MainSearchPtr = DiamondSearch;
1330    
1331                    MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
1332    
1333    /* extended search, diamond starting in 0,0 and in prediction.
1334            note that this search is/might be done in halfpel positions,
1335            which makes it more different than the diamond above */
1336    
1337          if (oldMBs == NULL) {                  if (MotionFlags & PMV_EXTSEARCH16) {
1338                  oldMBs = (MACROBLOCK *) calloc(iWcount * iHcount, sizeof(MACROBLOCK));                          int32_t bSAD;
1339  //      fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));                          VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
1340                            if (Data->rrv) {
1341                                    startMV.x = RRV_MV_SCALEUP(startMV.x);
1342                                    startMV.y = RRV_MV_SCALEUP(startMV.y);
1343          }          }
1344          oldMB = oldMBs + x + y * iWcount;                          if (!(MVequal(startMV, backupMV))) {
1345                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1346    
1347  /* Get maximum range */                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1348          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1349                            iFcode);                                  if (bSAD < Data->iMinSAD[0]) {
1350                                            Data->currentMV[0] = backupMV;
1351          if (!(MotionFlags & PMV_HALFPEL16)) {                                          Data->iMinSAD[0] = bSAD; }
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
1352          }          }
         /* 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  
1353    
1354          currMV->x = start_x;                          backupMV = Data->currentMV[0];
1355          currMV->y = start_y;                          startMV.x = startMV.y = 1;
1356                            if (!(MVequal(startMV, backupMV))) {
1357                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1358    
1359          if (!(MotionFlags & PMV_HALFPEL16)) {                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1360                  currMV->x = EVEN(currMV->x);                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1361                  currMV->y = EVEN(currMV->y);                                  if (bSAD < Data->iMinSAD[0]) {
1362          }                                          Data->currentMV[0] = backupMV;
1363                                            Data->iMinSAD[0] = bSAD; }
1364          if (currMV->x > max_dx)                          }
1365                  currMV->x = max_dx;                  }
1366          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);  
1367    
1368  // set threshhold based on Min of Prediction and SAD of collocated block          if (MotionFlags & PMV_HALFPELREFINE16)
1369  // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want                  SubpelRefine(Data);
1370    
1371          if ((x == 0) && (y == 0)) {          for(i = 0; i < 5; i++) {
1372                  thresh2 = 512;                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // initialize qpel vectors
1373          } else {                  Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
1374  /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */          }
1375    
1376                  thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;          if (Data->qpel) {
1377                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1378                                    pParam->width, pParam->height, Data->iFcode, 1, 0);
1379                    Data->qpel_precision = 1;
1380                    if (MotionFlags & PMV_QUARTERPELREFINE16)
1381                            SubpelRefine(Data);
1382          }          }
1383    
1384  // MV=(0,0) is often a good choice          if (Data->iMinSAD[0] < (int32_t)pMB->quant * 30)
1385                    inter4v = 0;
1386    
1387          CHECK_MV16_ZERO;          if (inter4v) {
1388                    SearchData Data8;
1389                    memcpy(&Data8, Data, sizeof(SearchData)); //quick copy of common data
1390    
1391                    Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
1392                    Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
1393                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
1394                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
1395    
1396  // left neighbour, if allowed                  if ((Data->chroma) && (!(GlobalFlags & XVID_MODEDECISION_BITS))) {
1397          if (x != 0) {                          // chroma is only used for comparsion to INTER. if the comparsion will be done in BITS domain, it will not be used
1398                  if (!(MotionFlags & PMV_HALFPEL16)) {                          int sumx = 0, sumy = 0;
1399                          pmv[1].x = EVEN(pmv[1].x);  
1400                          pmv[1].y = EVEN(pmv[1].y);                          if (Data->qpel)
1401                  }                                  for (i = 1; i < 5; i++) {
1402                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);                                          sumx += Data->currentQMV[i].x/2;
1403                                            sumy += Data->currentQMV[i].y/2;
1404          }          }
1405  // top neighbour, if allowed                          else
1406          if (y != 0) {                                  for (i = 1; i < 5; i++) {
1407                  if (!(MotionFlags & PMV_HALFPEL16)) {                                          sumx += Data->currentMV[i].x;
1408                          pmv[2].x = EVEN(pmv[2].x);                                          sumy += Data->currentMV[i].y;
                         pmv[2].y = EVEN(pmv[2].y);  
1409                  }                  }
                 CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
1410    
1411  // top right neighbour, if allowed                          Data->iMinSAD[1] += ChromaSAD(  (sumx >> 3) + roundtab_76[sumx & 0xf],
1412                  if ((uint32_t) x != (iWcount - 1)) {                                                                                          (sumy >> 3) + roundtab_76[sumy & 0xf], Data);
                         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);  
1413                  }                  }
1414            } else Data->iMinSAD[1] = 4096*256;
1415          }          }
1416    
1417  /* Terminate if MinSAD <= T_2  static void
1418     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  Search8(const SearchData * const OldData,
1419  */                  const int x, const int y,
1420                    const uint32_t MotionFlags,
1421          if ((iMinSAD <= thresh2)                  const MBParam * const pParam,
1422                  || (MVequal(*currMV, prevMB->mvs[0]) &&                  MACROBLOCK * const pMB,
1423                          ((int32_t) iMinSAD <= prevMB->sad16))) {                  const MACROBLOCK * const pMBs,
1424                  if (MotionFlags & PMV_QUICKSTOP16)                  const int block,
1425                          goto EPZS16_Terminate_without_Refine;                  SearchData * const Data)
1426                  if (MotionFlags & PMV_EARLYSTOP16)  {
1427                          goto EPZS16_Terminate_with_Refine;          int i = 0;
1428            Data->iMinSAD = OldData->iMinSAD + 1 + block;
1429            Data->currentMV = OldData->currentMV + 1 + block;
1430            Data->currentQMV = OldData->currentQMV + 1 + block;
1431    
1432            if(Data->qpel) {
1433                    Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1434                    if (block != 0) i = d_mv_bits(  Data->currentQMV->x, Data->currentQMV->y,
1435                                                                                    Data->predMV, Data->iFcode, 0, 0);
1436            } else {
1437                    Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1438                    if (block != 0) i = d_mv_bits(  Data->currentMV->x, Data->currentMV->y,
1439                                                                                    Data->predMV, Data->iFcode, 0, Data->rrv);
1440          }          }
1441    
1442  /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/          *(Data->iMinSAD) += (Data->lambda8 * i * (*Data->iMinSAD + NEIGH_8X8_BIAS))>>10;
1443    
1444          backupMV = prevMB->mvs[0];      // collocated MV          if (MotionFlags & (PMV_EXTSEARCH8|PMV_HALFPELREFINE8|PMV_QUARTERPELREFINE8)) {
         backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x);     // acceleration X  
         backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y);     // acceleration Y  
1445    
1446          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y);                  if (Data->rrv) i = 16; else i = 8;
1447    
1448  // left neighbour                  Data->RefP[0] = OldData->RefP[0] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1449          if (x != 0)                  Data->RefP[1] = OldData->RefP[1] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1450                  CHECK_MV16_CANDIDATE((prevMB - 1)->mvs[0].x, (prevMB - 1)->mvs[0].y);                  Data->RefP[2] = OldData->RefP[2] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1451                    Data->RefP[3] = OldData->RefP[3] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1452    
1453  // top neighbour                  Data->Cur = OldData->Cur + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1454          if (y != 0)                  Data->qpel_precision = 0;
                 CHECK_MV16_CANDIDATE((prevMB - iWcount)->mvs[0].x,  
                                                          (prevMB - iWcount)->mvs[0].y);  
1455    
1456  // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1457                                            pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
1458    
1459          if ((uint32_t) x != iWcount - 1)                  if (!Data->rrv) CheckCandidate = CheckCandidate8;
1460                  CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);                  else CheckCandidate = CheckCandidate16no4v;
1461    
1462  // bottom neighbour, dito                  if (MotionFlags & PMV_EXTSEARCH8 && (!(MotionFlags & EXTSEARCH_BITS))) {
1463          if ((uint32_t) y != iHcount - 1)                          int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
                 CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,  
                                                          (prevMB + iWcount)->mvs[0].y);  
1464    
1465  /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */                          MainSearchFunc *MainSearchPtr;
1466          if (iMinSAD <= thresh2) {                          if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
1467                  if (MotionFlags & PMV_QUICKSTOP16)                                  else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1468                          goto EPZS16_Terminate_without_Refine;                                          else MainSearchPtr = DiamondSearch;
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
         }  
1469    
1470  /************ (if Diamond Search)  **************/                          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, 255);
1471    
1472          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                          if(*(Data->iMinSAD) < temp_sad) {
1473                                            Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1474                                            Data->currentQMV->y = 2 * Data->currentMV->y;
1475                            }
1476                    }
1477    
1478          if (MotionFlags & PMV_USESQUARES16)                  if (MotionFlags & PMV_HALFPELREFINE8) {
1479                  MainSearchPtr = Square16_MainSearch;                          int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
         else  
          if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
1480    
1481  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                          SubpelRefine(Data); // perform halfpel refine of current best vector
1482    
1483          iSAD =                          if(*(Data->iMinSAD) < temp_sad) { // we have found a better match
1484                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,                                  Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1485                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,                                  Data->currentQMV->y = 2 * Data->currentMV->y;
1486                                                    min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);                          }
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
1487          }          }
1488    
1489                    if (Data->qpel && MotionFlags & PMV_QUARTERPELREFINE8) {
1490                                    Data->qpel_precision = 1;
1491                                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1492                                            pParam->width, pParam->height, Data->iFcode, 1, 0);
1493                                    SubpelRefine(Data);
1494                    }
1495            }
1496    
1497          if (MotionFlags & PMV_EXTSEARCH16) {          if (Data->rrv) {
1498  /* extended mode: search (up to) two more times: orignal prediction and (0,0) */                          Data->currentMV->x = RRV_MV_SCALEDOWN(Data->currentMV->x);
1499                            Data->currentMV->y = RRV_MV_SCALEDOWN(Data->currentMV->y);
1500            }
1501    
1502                  if (!(MVequal(pmv[0], backupMV))) {          if(Data->qpel) {
1503                          iSAD =                  pMB->pmvs[block].x = Data->currentQMV->x - Data->predMV.x;
1504                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                  pMB->pmvs[block].y = Data->currentQMV->y - Data->predMV.y;
1505                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,                  pMB->qmvs[block] = *Data->currentQMV;
1506                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,          } else {
1507                                                                    2, iFcode, iQuant, 0);                  pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1508                    pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
1509                  }                  }
1510    
1511                  if (iSAD < iMinSAD) {          pMB->mvs[block] = *Data->currentMV;
1512                          *currMV = newMV;          pMB->sad8[block] = 4 * *Data->iMinSAD;
                         iMinSAD = iSAD;  
1513                  }                  }
1514    
1515                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {  /* motion estimation for B-frames */
                         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, 2, iFcode, iQuant, 0);  
1516    
1517                          if (iSAD < iMinSAD) {  static __inline VECTOR
1518                                  *currMV = newMV;  ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1519                                  iMinSAD = iSAD;  {
1520                          }  /* the stupidiest function ever */
1521                  }          return (mode == MODE_FORWARD ? pMB->mvs[0] : pMB->b_mvs[0]);
1522          }          }
1523    
1524  /***************        Choose best MV found     **************/  static void __inline
1525    PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
1526                                                            const uint32_t iWcount,
1527                                                            const MACROBLOCK * const pMB,
1528                                                            const uint32_t mode_curr)
1529    {
1530    
1531            // [0] is prediction
1532            pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
1533    
1534    EPZS16_Terminate_with_Refine:          pmv[1].x = pmv[1].y = 0; // [1] is zero
         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);  
1535    
1536    EPZS16_Terminate_without_Refine:          pmv[2] = ChoosePred(pMB, mode_curr);
1537            pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
1538    
1539          *oldMB = *prevMB;          if ((y != 0)&&(x != (int)(iWcount+1))) {                        // [3] top-right neighbour
1540                    pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
1541                    pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
1542            } else pmv[3].x = pmv[3].y = 0;
1543    
1544            if (y != 0) {
1545                    pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
1546                    pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
1547            } else pmv[4].x = pmv[4].y = 0;
1548    
1549            if (x != 0) {
1550                    pmv[5] = ChoosePred(pMB-1, mode_curr);
1551                    pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1552            } else pmv[5].x = pmv[5].y = 0;
1553    
1554          currPMV->x = currMV->x - center_x;          if (x != 0 && y != 0) {
1555          currPMV->y = currMV->y - center_y;                  pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
1556          return iMinSAD;                  pmv[6].x = EVEN(pmv[6].x); pmv[6].y = EVEN(pmv[6].y);
1557            } else pmv[6].x = pmv[6].y = 0;
1558  }  }
1559    
1560    
1561  int32_t  /* search backward or forward */
1562  EPZSSearch8(const uint8_t * const pRef,  static void
1563    SearchBF(       const IMAGE * const pRef,
1564                          const uint8_t * const pRefH,                          const uint8_t * const pRefH,
1565                          const uint8_t * const pRefV,                          const uint8_t * const pRefV,
1566                          const uint8_t * const pRefHV,                          const uint8_t * const pRefHV,
1567                          const IMAGE * const pCur,                          const IMAGE * const pCur,
1568                          const int x,                          const int x, const int y,
                         const int y,  
                         const int start_x,  
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
1569                          const uint32_t MotionFlags,                          const uint32_t MotionFlags,
                         const uint32_t iQuant,  
1570                          const uint32_t iFcode,                          const uint32_t iFcode,
1571                          const MBParam * const pParam,                          const MBParam * const pParam,
1572                          const MACROBLOCK * const pMBs,                          MACROBLOCK * const pMB,
1573                          const MACROBLOCK * const prevMBs,                          const VECTOR * const predMV,
1574                          VECTOR * const currMV,                          int32_t * const best_sad,
1575                          VECTOR * const currPMV)                          const int32_t mode_current,
1576                            SearchData * const Data)
1577  {  {
 /* 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;  
   
         int32_t iDiamondSize = 1;  
1578    
1579          int32_t min_dx;          int i, iDirection = 255, mask;
1580          int32_t max_dx;          VECTOR pmv[7];
1581          int32_t min_dy;          MainSearchFunc *MainSearchPtr;
1582          int32_t max_dy;          *Data->iMinSAD = MV_MAX_ERROR;
1583            Data->iFcode = iFcode;
1584            Data->qpel_precision = 0;
1585            Data->temp[5] = Data->temp[6] = Data->temp[7] = 256*4096; // reset chroma-sad cache
1586    
1587          VECTOR newMV;          Data->RefP[0] = pRef->y + (x + Data->iEdgedWidth*y) * 16;
1588          VECTOR backupMV;          Data->RefP[2] = pRefH + (x + Data->iEdgedWidth*y) * 16;
1589            Data->RefP[1] = pRefV + (x + Data->iEdgedWidth*y) * 16;
1590            Data->RefP[3] = pRefHV + (x + Data->iEdgedWidth*y) * 16;
1591            Data->RefP[4] = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8;
1592            Data->RefP[5] = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8;
1593    
1594          VECTOR pmv[4];          Data->predMV = *predMV;
         int32_t psad[8];  
1595    
1596          const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1597                                    pParam->width, pParam->height, iFcode - Data->qpel, 0, 0);
1598    
1599  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          pmv[0] = Data->predMV;
1600          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;          if (Data->qpel) { pmv[0].x /= 2; pmv[0].y /= 2; }
1601    
1602          int32_t bPredEq;          PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);
         int32_t iMinSAD, iSAD = 9999;  
1603    
1604          MainSearch8FuncPtr MainSearchPtr;          Data->currentMV->x = Data->currentMV->y = 0;
1605            CheckCandidate = CheckCandidate16no4v;
1606    
1607  /* Get maximum range */  // main loop. checking all predictions
1608          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,          for (i = 0; i < 7; i++) {
1609                            iFcode);                  if (!(mask = make_mask(pmv, i)) ) continue;
1610                    CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
 /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  
   
         if (!(MotionFlags & PMV_HALFPEL8)) {  
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
1611          }          }
         /* 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);  
1612    
1613            if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1614            else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1615                    else MainSearchPtr = DiamondSearch;
1616    
1617  /* Step 4: Calculate SAD around the Median prediction.          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
         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  
1618    
1619            SubpelRefine(Data);
1620    
1621          if (!(MotionFlags & PMV_HALFPEL8)) {          if (Data->qpel && *Data->iMinSAD < *best_sad + 300) {
1622                  currMV->x = EVEN(currMV->x);                  Data->currentQMV->x = 2*Data->currentMV->x;
1623                  currMV->y = EVEN(currMV->y);                  Data->currentQMV->y = 2*Data->currentMV->y;
1624                    Data->qpel_precision = 1;
1625                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1626                                            pParam->width, pParam->height, iFcode, 1, 0);
1627                    SubpelRefine(Data);
1628          }          }
1629    
1630          if (currMV->x > max_dx)  // three bits are needed to code backward mode. four for forward
                 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;  
1631    
1632  /***************** This is predictor SET A: only median prediction ******************/          if (mode_current == MODE_FORWARD) *Data->iMinSAD += 4 * Data->lambda16;
1633            else *Data->iMinSAD += 3 * Data->lambda16;
1634    
1635            if (*Data->iMinSAD < *best_sad) {
1636                    *best_sad = *Data->iMinSAD;
1637                    pMB->mode = mode_current;
1638                    if (Data->qpel) {
1639                            pMB->pmvs[0].x = Data->currentQMV->x - predMV->x;
1640                            pMB->pmvs[0].y = Data->currentQMV->y - predMV->y;
1641                            if (mode_current == MODE_FORWARD)
1642                                    pMB->qmvs[0] = *Data->currentQMV;
1643                            else
1644                                    pMB->b_qmvs[0] = *Data->currentQMV;
1645                    } else {
1646                            pMB->pmvs[0].x = Data->currentMV->x - predMV->x;
1647                            pMB->pmvs[0].y = Data->currentMV->y - predMV->y;
1648                    }
1649                    if (mode_current == MODE_FORWARD) pMB->mvs[0] = *Data->currentMV;
1650                    else pMB->b_mvs[0] = *Data->currentMV;
1651            }
1652    
1653          iMinSAD =          if (mode_current == MODE_FORWARD) *(Data->currentMV+2) = *Data->currentMV;
1654                  sad8(cur,          else *(Data->currentMV+1) = *Data->currentMV; //we store currmv for interpolate search
1655                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  }
1656                                                  iEdgedWidth), iEdgedWidth);  
1657          iMinSAD +=  static void
1658                  calc_delta_8(currMV->x - center_x, currMV->y - center_y,  SkipDecisionB(const IMAGE * const pCur,
1659                                           (uint8_t) iFcode, iQuant);                                  const IMAGE * const f_Ref,
1660                                    const IMAGE * const b_Ref,
1661                                    MACROBLOCK * const pMB,
1662                                    const uint32_t x, const uint32_t y,
1663                                    const SearchData * const Data)
1664    {
1665            int dx = 0, dy = 0, b_dx = 0, b_dy = 0;
1666            int32_t sum;
1667            const int div = 1 + Data->qpel;
1668            int k;
1669            const uint32_t stride = Data->iEdgedWidth/2;
1670    //this is not full chroma compensation, only it's fullpel approximation. should work though
1671    
1672            for (k = 0; k < 4; k++) {
1673                    dy += Data->directmvF[k].y / div;
1674                    dx += Data->directmvF[k].x / div;
1675                    b_dy += Data->directmvB[k].y / div;
1676                    b_dx += Data->directmvB[k].x / div;
1677            }
1678    
1679            dy = (dy >> 3) + roundtab_76[dy & 0xf];
1680            dx = (dx >> 3) + roundtab_76[dx & 0xf];
1681            b_dy = (b_dy >> 3) + roundtab_76[b_dy & 0xf];
1682            b_dx = (b_dx >> 3) + roundtab_76[b_dx & 0xf];
1683    
1684            sum = sad8bi(pCur->u + 8 * x + 8 * y * stride,
1685                                            f_Ref->u + (y*8 + dy/2) * stride + x*8 + dx/2,
1686                                            b_Ref->u + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1687                                            stride);
1688    
1689            if (sum >= 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) return; //no skip
1690    
1691            sum += sad8bi(pCur->v + 8*x + 8 * y * stride,
1692                                            f_Ref->v + (y*8 + dy/2) * stride + x*8 + dx/2,
1693                                            b_Ref->v + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1694                                            stride);
1695    
1696  // thresh1 is fixed to 256          if (sum < 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) {
1697          if (iMinSAD < 256 / 4) {                  pMB->mode = MODE_DIRECT_NONE_MV; //skipped
1698                  if (MotionFlags & PMV_QUICKSTOP8)                  for (k = 0; k < 4; k++) {
1699                          goto EPZS8_Terminate_without_Refine;                          pMB->qmvs[k] = pMB->mvs[k];
1700                  if (MotionFlags & PMV_EARLYSTOP8)                          pMB->b_qmvs[k] = pMB->b_mvs[k];
1701                          goto EPZS8_Terminate_with_Refine;                  }
1702            }
1703          }          }
1704    
1705  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/  static __inline uint32_t
1706    SearchDirect(const IMAGE * const f_Ref,
1707                                    const uint8_t * const f_RefH,
1708                                    const uint8_t * const f_RefV,
1709                                    const uint8_t * const f_RefHV,
1710                                    const IMAGE * const b_Ref,
1711                                    const uint8_t * const b_RefH,
1712                                    const uint8_t * const b_RefV,
1713                                    const uint8_t * const b_RefHV,
1714                                    const IMAGE * const pCur,
1715                                    const int x, const int y,
1716                                    const uint32_t MotionFlags,
1717                                    const int32_t TRB, const int32_t TRD,
1718                                    const MBParam * const pParam,
1719                                    MACROBLOCK * const pMB,
1720                                    const MACROBLOCK * const b_mb,
1721                                    int32_t * const best_sad,
1722                                    SearchData * const Data)
1723    
1724    {
1725            int32_t skip_sad;
1726            int k = (x + Data->iEdgedWidth*y) * 16;
1727            MainSearchFunc *MainSearchPtr;
1728    
1729            *Data->iMinSAD = 256*4096;
1730            Data->RefP[0] = f_Ref->y + k;
1731            Data->RefP[2] = f_RefH + k;
1732            Data->RefP[1] = f_RefV + k;
1733            Data->RefP[3] = f_RefHV + k;
1734            Data->b_RefP[0] = b_Ref->y + k;
1735            Data->b_RefP[2] = b_RefH + k;
1736            Data->b_RefP[1] = b_RefV + k;
1737            Data->b_RefP[3] = b_RefHV + k;
1738            Data->RefP[4] = f_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1739            Data->RefP[5] = f_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1740            Data->b_RefP[4] = b_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1741            Data->b_RefP[5] = b_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1742    
1743            k = Data->qpel ? 4 : 2;
1744            Data->max_dx = k * (pParam->width - x * 16);
1745            Data->max_dy = k * (pParam->height - y * 16);
1746            Data->min_dx = -k * (16 + x * 16);
1747            Data->min_dy = -k * (16 + y * 16);
1748    
1749            Data->referencemv = Data->qpel ? b_mb->qmvs : b_mb->mvs;
1750            Data->qpel_precision = 0;
1751    
1752  // MV=(0,0) is often a good choice          for (k = 0; k < 4; k++) {
1753          CHECK_MV8_ZERO;                  pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);
1754                    pMB->b_mvs[k].x = Data->directmvB[k].x = ((TRB - TRD) * Data->referencemv[k].x) / TRD;
1755                    pMB->mvs[k].y = Data->directmvF[k].y = ((TRB * Data->referencemv[k].y) / TRD);
1756                    pMB->b_mvs[k].y = Data->directmvB[k].y = ((TRB - TRD) * Data->referencemv[k].y) / TRD;
1757    
1758  // previous frame MV                  if ( (pMB->b_mvs[k].x > Data->max_dx) | (pMB->b_mvs[k].x < Data->min_dx)
1759          CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x, prevMB->mvs[iSubBlock].y);                          | (pMB->b_mvs[k].y > Data->max_dy) | (pMB->b_mvs[k].y < Data->min_dy) ) {
1760    
1761  // left neighbour, if allowed                          *best_sad = 256*4096; // in that case, we won't use direct mode
1762          if (psad[1] != MV_MAX_ERROR) {                          pMB->mode = MODE_DIRECT; // just to make sure it doesn't say "MODE_DIRECT_NONE_MV"
1763                  if (!(MotionFlags & PMV_HALFPEL8)) {                          pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;
1764                          pmv[1].x = EVEN(pmv[1].x);                          return 256*4096;
                         pmv[1].y = EVEN(pmv[1].y);  
1765                  }                  }
1766                  CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);                  if (b_mb->mode != MODE_INTER4V) {
1767                            pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mvs[0];
1768                            pMB->b_mvs[1] = pMB->b_mvs[2] = pMB->b_mvs[3] = pMB->b_mvs[0];
1769                            Data->directmvF[1] = Data->directmvF[2] = Data->directmvF[3] = Data->directmvF[0];
1770                            Data->directmvB[1] = Data->directmvB[2] = Data->directmvB[3] = Data->directmvB[0];
1771                            break;
1772          }          }
 // 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);  
1773                  }                  }
                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
1774    
1775  // top right neighbour, if allowed          CheckCandidate = b_mb->mode == MODE_INTER4V ? CheckCandidateDirect : CheckCandidateDirectno4v;
1776                  if (psad[3] != MV_MAX_ERROR) {  
1777                          if (!(MotionFlags & PMV_HALFPEL8)) {          CheckCandidate(0, 0, 255, &k, Data);
1778                                  pmv[3].x = EVEN(pmv[3].x);  
1779                                  pmv[3].y = EVEN(pmv[3].y);  // initial (fast) skip decision
1780                          }          if (*Data->iMinSAD < pMB->quant * INITIAL_SKIP_THRESH * (Data->chroma?3:2)) {
1781                          CHECK_MV8_CANDIDATE(pmv[3].x, pmv[3].y);                  //possible skip
1782                    if (Data->chroma) {
1783                            pMB->mode = MODE_DIRECT_NONE_MV;
1784                            return *Data->iMinSAD; // skip.
1785                    } else {
1786                            SkipDecisionB(pCur, f_Ref, b_Ref, pMB, x, y, Data);
1787                            if (pMB->mode == MODE_DIRECT_NONE_MV) return *Data->iMinSAD; // skip.
1788                  }                  }
1789          }          }
1790    
1791  /*  // this bias is zero anyway, at the moment!          *Data->iMinSAD += Data->lambda16;
1792            skip_sad = *Data->iMinSAD;
1793    
1794          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)  //      DIRECT MODE DELTA VECTOR SEARCH.
1795                  iMinSAD -= MV8_00_BIAS;  //      This has to be made more effective, but at the moment I'm happy it's running at all
1796    
1797  */          if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1798                    else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1799                            else MainSearchPtr = DiamondSearch;
1800    
1801  /* Terminate if MinSAD <= T_2          MainSearchPtr(0, 0, Data, 255);
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
1802    
1803          if (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */          SubpelRefine(Data);
                 if (MotionFlags & PMV_QUICKSTOP8)  
                         goto EPZS8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
         }  
1804    
1805  /************ (Diamond Search)  **************/          *best_sad = *Data->iMinSAD;
1806    
1807          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          if (Data->qpel || b_mb->mode == MODE_INTER4V) pMB->mode = MODE_DIRECT;
1808            else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation
1809    
1810          if (!(MotionFlags & PMV_HALFPELDIAMOND8))          pMB->pmvs[3] = *Data->currentMV;
1811                  iDiamondSize *= 2;  
1812            for (k = 0; k < 4; k++) {
1813                    pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
1814                    pMB->b_mvs[k].x = (     (Data->currentMV->x == 0)
1815                                                            ? Data->directmvB[k].x
1816                                                            :pMB->mvs[k].x - Data->referencemv[k].x);
1817                    pMB->mvs[k].y = (Data->directmvF[k].y + Data->currentMV->y);
1818                    pMB->b_mvs[k].y = ((Data->currentMV->y == 0)
1819                                                            ? Data->directmvB[k].y
1820                                                            : pMB->mvs[k].y - Data->referencemv[k].y);
1821                    if (Data->qpel) {
1822                            pMB->qmvs[k].x = pMB->mvs[k].x; pMB->mvs[k].x /= 2;
1823                            pMB->b_qmvs[k].x = pMB->b_mvs[k].x; pMB->b_mvs[k].x /= 2;
1824                            pMB->qmvs[k].y = pMB->mvs[k].y; pMB->mvs[k].y /= 2;
1825                            pMB->b_qmvs[k].y = pMB->b_mvs[k].y; pMB->b_mvs[k].y /= 2;
1826                    }
1827    
1828                    if (b_mb->mode != MODE_INTER4V) {
1829                            pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1830                            pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1831                            pMB->qmvs[3] = pMB->qmvs[2] = pMB->qmvs[1] = pMB->qmvs[0];
1832                            pMB->b_qmvs[3] = pMB->b_qmvs[2] = pMB->b_qmvs[1] = pMB->b_qmvs[0];
1833                            break;
1834                    }
1835            }
1836            return skip_sad;
1837    }
1838    
1839    static void
1840    SearchInterpolate(const IMAGE * const f_Ref,
1841                                    const uint8_t * const f_RefH,
1842                                    const uint8_t * const f_RefV,
1843                                    const uint8_t * const f_RefHV,
1844                                    const IMAGE * const b_Ref,
1845                                    const uint8_t * const b_RefH,
1846                                    const uint8_t * const b_RefV,
1847                                    const uint8_t * const b_RefHV,
1848                                    const IMAGE * const pCur,
1849                                    const int x, const int y,
1850                                    const uint32_t fcode,
1851                                    const uint32_t bcode,
1852                                    const uint32_t MotionFlags,
1853                                    const MBParam * const pParam,
1854                                    const VECTOR * const f_predMV,
1855                                    const VECTOR * const b_predMV,
1856                                    MACROBLOCK * const pMB,
1857                                    int32_t * const best_sad,
1858                                    SearchData * const fData)
1859    
1860  /* default: use best prediction as starting point for one call of EPZS_MainSearch */  {
1861    
1862  // there is no EPZS^2 for inter4v at the moment          int iDirection, i, j;
1863            SearchData bData;
1864    
1865            fData->qpel_precision = 0;
1866            memcpy(&bData, fData, sizeof(SearchData)); //quick copy of common data
1867            *fData->iMinSAD = 4096*256;
1868            bData.currentMV++; bData.currentQMV++;
1869            fData->iFcode = bData.bFcode = fcode; fData->bFcode = bData.iFcode = bcode;
1870    
1871            i = (x + y * fData->iEdgedWidth) * 16;
1872    
1873            bData.b_RefP[0] = fData->RefP[0] = f_Ref->y + i;
1874            bData.b_RefP[2] = fData->RefP[2] = f_RefH + i;
1875            bData.b_RefP[1] = fData->RefP[1] = f_RefV + i;
1876            bData.b_RefP[3] = fData->RefP[3] = f_RefHV + i;
1877            bData.RefP[0] = fData->b_RefP[0] = b_Ref->y + i;
1878            bData.RefP[2] = fData->b_RefP[2] = b_RefH + i;
1879            bData.RefP[1] = fData->b_RefP[1] = b_RefV + i;
1880            bData.RefP[3] = fData->b_RefP[3] = b_RefHV + i;
1881            bData.b_RefP[4] = fData->RefP[4] = f_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
1882            bData.b_RefP[5] = fData->RefP[5] = f_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
1883            bData.RefP[4] = fData->b_RefP[4] = b_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
1884            bData.RefP[5] = fData->b_RefP[5] = b_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
1885    
1886            bData.bpredMV = fData->predMV = *f_predMV;
1887            fData->bpredMV = bData.predMV = *b_predMV;
1888            fData->currentMV[0] = fData->currentMV[2];
1889    
1890            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);
1891            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);
1892    
1893            if (fData->currentMV[0].x > fData->max_dx) fData->currentMV[0].x = fData->max_dx;
1894            if (fData->currentMV[0].x < fData->min_dx) fData->currentMV[0].x = fData->min_dx;
1895            if (fData->currentMV[0].y > fData->max_dy) fData->currentMV[0].y = fData->max_dy;
1896            if (fData->currentMV[0].y < fData->min_dy) fData->currentMV[0].y = fData->min_dy;
1897    
1898            if (fData->currentMV[1].x > bData.max_dx) fData->currentMV[1].x = bData.max_dx;
1899            if (fData->currentMV[1].x < bData.min_dx) fData->currentMV[1].x = bData.min_dx;
1900            if (fData->currentMV[1].y > bData.max_dy) fData->currentMV[1].y = bData.max_dy;
1901            if (fData->currentMV[1].y < bData.min_dy) fData->currentMV[1].y = bData.min_dy;
1902    
1903    if (MotionFlags & PMV_USESQUARES8)          CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, 255, &iDirection, fData);
       MainSearchPtr = Square8_MainSearch;  
   else  
1904    
1905          if (MotionFlags & PMV_ADVANCEDDIAMOND8)  //diamond
1906                  MainSearchPtr = AdvDiamond8_MainSearch;          do {
1907          else                  iDirection = 255;
1908                  MainSearchPtr = Diamond8_MainSearch;                  // forward MV moves
1909                    i = fData->currentMV[0].x; j = fData->currentMV[0].y;
1910    
1911                    CheckCandidateInt(i + 1, j, 0, &iDirection, fData);
1912                    CheckCandidateInt(i, j + 1, 0, &iDirection, fData);
1913                    CheckCandidateInt(i - 1, j, 0, &iDirection, fData);
1914                    CheckCandidateInt(i, j - 1, 0, &iDirection, fData);
1915    
1916                    // backward MV moves
1917                    i = fData->currentMV[1].x; j = fData->currentMV[1].y;
1918                    fData->currentMV[2] = fData->currentMV[0];
1919                    CheckCandidateInt(i + 1, j, 0, &iDirection, &bData);
1920                    CheckCandidateInt(i, j + 1, 0, &iDirection, &bData);
1921                    CheckCandidateInt(i - 1, j, 0, &iDirection, &bData);
1922                    CheckCandidateInt(i, j - 1, 0, &iDirection, &bData);
1923    
1924            } while (!(iDirection));
1925    
1926    //qpel refinement
1927            if (fData->qpel) {
1928                    if (*fData->iMinSAD > *best_sad + 500) return;
1929                    CheckCandidate = CheckCandidateInt;
1930                    fData->qpel_precision = bData.qpel_precision = 1;
1931                    get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode, 1, 0);
1932                    get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode, 1, 0);
1933                    fData->currentQMV[2].x = fData->currentQMV[0].x = 2 * fData->currentMV[0].x;
1934                    fData->currentQMV[2].y = fData->currentQMV[0].y = 2 * fData->currentMV[0].y;
1935                    fData->currentQMV[1].x = 2 * fData->currentMV[1].x;
1936                    fData->currentQMV[1].y = 2 * fData->currentMV[1].y;
1937                    SubpelRefine(fData);
1938                    if (*fData->iMinSAD > *best_sad + 300) return;
1939                    fData->currentQMV[2] = fData->currentQMV[0];
1940                    SubpelRefine(&bData);
1941            }
1942    
1943            *fData->iMinSAD += (2+3) * fData->lambda16; // two bits are needed to code interpolate mode.
1944    
1945            if (*fData->iMinSAD < *best_sad) {
1946                    *best_sad = *fData->iMinSAD;
1947                    pMB->mvs[0] = fData->currentMV[0];
1948                    pMB->b_mvs[0] = fData->currentMV[1];
1949                    pMB->mode = MODE_INTERPOLATE;
1950                    if (fData->qpel) {
1951                            pMB->qmvs[0] = fData->currentQMV[0];
1952                            pMB->b_qmvs[0] = fData->currentQMV[1];
1953                            pMB->pmvs[1].x = pMB->qmvs[0].x - f_predMV->x;
1954                            pMB->pmvs[1].y = pMB->qmvs[0].y - f_predMV->y;
1955                            pMB->pmvs[0].x = pMB->b_qmvs[0].x - b_predMV->x;
1956                            pMB->pmvs[0].y = pMB->b_qmvs[0].y - b_predMV->y;
1957                    } else {
1958                            pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;
1959                            pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;
1960                            pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;
1961                            pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;
1962                    }
1963            }
1964    }
1965    
1966          iSAD =  void
1967                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  MotionEstimationBVOP(MBParam * const pParam,
1968                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,                                          FRAMEINFO * const frame,
1969                                                    min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,                                          const int32_t time_bp,
1970                                                    iQuant, 0);                                          const int32_t time_pp,
1971                                            // forward (past) reference
1972                                            const MACROBLOCK * const f_mbs,
1973                                            const IMAGE * const f_ref,
1974                                            const IMAGE * const f_refH,
1975                                            const IMAGE * const f_refV,
1976                                            const IMAGE * const f_refHV,
1977                                            // backward (future) reference
1978                                            const FRAMEINFO * const b_reference,
1979                                            const IMAGE * const b_ref,
1980                                            const IMAGE * const b_refH,
1981                                            const IMAGE * const b_refV,
1982                                            const IMAGE * const b_refHV)
1983    {
1984            uint32_t i, j;
1985            int32_t best_sad;
1986            uint32_t skip_sad;
1987            int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;
1988            const MACROBLOCK * const b_mbs = b_reference->mbs;
1989    
1990            VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
1991    
1992          if (iSAD < iMinSAD) {          const int32_t TRB = time_pp - time_bp;
1993                  *currMV = newMV;          const int32_t TRD = time_pp;
                 iMinSAD = iSAD;  
         }  
1994    
1995          if (MotionFlags & PMV_EXTSEARCH8) {  // some pre-inintialized data for the rest of the search
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
1996    
1997                  if (!(MVequal(pmv[0], backupMV))) {          SearchData Data;
1998                          iSAD =          int32_t iMinSAD;
1999                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,          VECTOR currentMV[3];
2000                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,          VECTOR currentQMV[3];
2001                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,          int32_t temp[8];
2002                                                                    iDiamondSize, iFcode, iQuant, 0);          memset(&Data, 0, sizeof(SearchData));
2003            Data.iEdgedWidth = pParam->edged_width;
2004            Data.currentMV = currentMV; Data.currentQMV = currentQMV;
2005            Data.iMinSAD = &iMinSAD;
2006            Data.lambda16 = lambda_vec16[frame->quant];
2007            Data.qpel = pParam->m_quarterpel;
2008            Data.rounding = 0;
2009            Data.chroma = frame->motion_flags & PMV_CHROMA8;
2010            Data.temp = temp;
2011    
2012                          if (iSAD < iMinSAD) {          Data.RefQ = f_refV->u; // a good place, also used in MC (for similar purpose)
2013                                  *currMV = newMV;          // note: i==horizontal, j==vertical
2014                                  iMinSAD = iSAD;          for (j = 0; j < pParam->mb_height; j++) {
                         }  
                 }  
2015    
2016                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                  f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
                         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, 0);  
2017    
2018                          if (iSAD < iMinSAD) {                  for (i = 0; i < pParam->mb_width; i++) {
2019                                  *currMV = newMV;                          MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
2020                                  iMinSAD = iSAD;                          const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
2021                          }  
2022                  }  /* special case, if collocated block is SKIPed in P-VOP: encoding is forward (0,0), cpb=0 without further ado */
2023                            if (b_reference->coding_type != S_VOP)
2024                                    if (b_mb->mode == MODE_NOT_CODED) {
2025                                            pMB->mode = MODE_NOT_CODED;
2026                                            continue;
2027          }          }
2028    
2029  /***************        Choose best MV found     **************/                          Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
2030                            Data.CurU = frame->image.u + (j * Data.iEdgedWidth/2 + i) * 8;
2031    EPZS8_Terminate_with_Refine:                          Data.CurV = frame->image.v + (j * Data.iEdgedWidth/2 + i) * 8;
2032          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step                          pMB->quant = frame->quant;
2033                  iMinSAD =  
2034                          Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  /* direct search comes first, because it (1) checks for SKIP-mode
2035                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,          and (2) sets very good predictions for forward and backward search */
2036                                                          iFcode, iQuant, iEdgedWidth);                          skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2037                                                                            b_ref, b_refH->y, b_refV->y, b_refHV->y,
2038                                                                            &frame->image,
2039                                                                            i, j,
2040                                                                            frame->motion_flags,
2041                                                                            TRB, TRD,
2042                                                                            pParam,
2043                                                                            pMB, b_mb,
2044                                                                            &best_sad,
2045                                                                            &Data);
2046    
2047    EPZS8_Terminate_without_Refine:                          if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
2048    
2049          currPMV->x = currMV->x - center_x;                          // forward search
2050          currPMV->y = currMV->y - center_y;                          SearchBF(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2051          return iMinSAD;                                                  &frame->image, i, j,
2052  }                                                  frame->motion_flags,
2053                                                    frame->fcode, pParam,
2054                                                    pMB, &f_predMV, &best_sad,
2055                                                    MODE_FORWARD, &Data);
2056    
2057                            // backward search
2058                            SearchBF(b_ref, b_refH->y, b_refV->y, b_refHV->y,
2059                                                    &frame->image, i, j,
2060                                                    frame->motion_flags,
2061                                                    frame->bcode, pParam,
2062                                                    pMB, &b_predMV, &best_sad,
2063                                                    MODE_BACKWARD, &Data);
2064    
2065                            // interpolate search comes last, because it uses data from forward and backward as prediction
2066                            SearchInterpolate(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2067                                                    b_ref, b_refH->y, b_refV->y, b_refHV->y,
2068                                                    &frame->image,
2069                                                    i, j,
2070                                                    frame->fcode, frame->bcode,
2071                                                    frame->motion_flags,
2072                                                    pParam,
2073                                                    &f_predMV, &b_predMV,
2074                                                    pMB, &best_sad,
2075                                                    &Data);
2076    
2077    // final skip decision
2078                            if ( (skip_sad < frame->quant * MAX_SAD00_FOR_SKIP * 2)
2079                                            && ((100*best_sad)/(skip_sad+1) > FINAL_SKIP_THRESH) )
2080                                    SkipDecisionB(&frame->image, f_ref, b_ref, pMB, i, j, &Data);
2081    
2082                            switch (pMB->mode) {
2083                                    case MODE_FORWARD:
2084                                            f_count++;
2085                                            f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2086                                            break;
2087                                    case MODE_BACKWARD:
2088                                            b_count++;
2089                                            b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2090                                            break;
2091                                    case MODE_INTERPOLATE:
2092                                            i_count++;
2093                                            f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2094                                            b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2095                                            break;
2096                                    case MODE_DIRECT:
2097                                    case MODE_DIRECT_NO4V:
2098                                            d_count++;
2099                                    default:
2100                                            break;
2101                            }
2102                    }
2103            }
2104    }
2105    
2106  int32_t  static __inline void
2107  PMVfastIntSearch16(const uint8_t * const pRef,  MEanalyzeMB (   const uint8_t * const pRef,
2108                                  const uint8_t * const pRefH,                                  const uint8_t * const pCur,
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const IMAGE * const pCur,  
2109                                  const int x,                                  const int x,
2110                                  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,  
                                 const uint32_t MotionFlags,  
                                 const uint32_t iQuant,  
                                 const uint32_t iFcode,  
2111                                  const MBParam * const pParam,                                  const MBParam * const pParam,
2112                                  const MACROBLOCK * const pMBs,                                  MACROBLOCK * const pMBs,
2113                                  const MACROBLOCK * const prevMBs,                                  SearchData * const Data)
                                 VECTOR * const currMV,  
                                 VECTOR * const currPMV)  
2114  {  {
         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;  
2115    
2116          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          int i, mask;
2117          const VECTOR zeroMV = { 0, 0 };          VECTOR pmv[3];
2118            MACROBLOCK * const pMB = &pMBs[x + y * pParam->mb_width];
2119    
2120          int32_t iDiamondSize;          for (i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;
2121    
2122          int32_t min_dx;          //median is only used as prediction. it doesn't have to be real
2123          int32_t max_dx;          if (x == 1 && y == 1) Data->predMV.x = Data->predMV.y = 0;
2124          int32_t min_dy;          else
2125          int32_t max_dy;                  if (x == 1) //left macroblock does not have any vector now
2126                            Data->predMV = (pMB - pParam->mb_width)->mvs[0]; // top instead of median
2127                    else if (y == 1) // top macroblock doesn't have it's vector
2128                            Data->predMV = (pMB - 1)->mvs[0]; // left instead of median
2129                            else Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); //else median
2130    
2131          int32_t iFound;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2132                                    pParam->width, pParam->height, Data->iFcode - pParam->m_quarterpel, 0, 0);
2133    
2134          VECTOR newMV;          Data->Cur = pCur + (x + y * pParam->edged_width) * 16;
2135          VECTOR backupMV;          Data->RefP[0] = pRef + (x + y * pParam->edged_width) * 16;
2136    
2137          VECTOR pmv[4];          pmv[1].x = EVEN(pMB->mvs[0].x);
2138          int32_t psad[4];          pmv[1].y = EVEN(pMB->mvs[0].y);
2139            pmv[2].x = EVEN(Data->predMV.x);
2140            pmv[2].y = EVEN(Data->predMV.y);
2141            pmv[0].x = pmv[0].y = 0;
2142    
2143          MainSearch16FuncPtr MainSearchPtr;          CheckCandidate32I(0, 0, 255, &i, Data);
2144    
2145          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;          if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP) {
         MACROBLOCK *const pMB = pMBs + x + y * iWcount;  
2146    
2147          int32_t threshA, threshB;                  if (!(mask = make_mask(pmv, 1)))
2148          int32_t bPredEq;                          CheckCandidate32I(pmv[1].x, pmv[1].y, mask, &i, Data);
2149          int32_t iMinSAD, iSAD;                  if (!(mask = make_mask(pmv, 2)))
2150                            CheckCandidate32I(pmv[2].x, pmv[2].y, mask, &i, Data);
2151    
2152                    if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP) // diamond only if needed
2153                            DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, i);
2154            }
2155    
2156  /* Get maximum range */          for (i = 0; i < 4; i++) {
2157          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,                  MACROBLOCK * MB = &pMBs[x + (i&1) + (y+(i>>1)) * pParam->mb_width];
2158                            iFcode);                  MB->mvs[0] = MB->mvs[1] = MB->mvs[2] = MB->mvs[3] = Data->currentMV[i];
2159                    MB->mode = MODE_INTER;
2160                    MB->sad16 = Data->iMinSAD[i+1];
2161            }
2162    }
2163    
2164  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  #define INTRA_THRESH    1700
2165    #define INTER_THRESH    1200
2166    
2167          if ((x == 0) && (y == 0)) {  int
2168                  threshA = 512;  MEanalysis(     const IMAGE * const pRef,
2169                  threshB = 1024;                          const FRAMEINFO * const Current,
2170                            const MBParam * const pParam,
2171                            const int maxIntra, //maximum number if non-I frames
2172                            const int intraCount, //number of non-I frames after last I frame; 0 if we force P/B frame
2173                            const int bCount,  // number of B frames in a row
2174                            const int b_thresh)
2175    {
2176            uint32_t x, y, intra = 0;
2177            int sSAD = 0;
2178            MACROBLOCK * const pMBs = Current->mbs;
2179            const IMAGE * const pCurrent = &Current->image;
2180            int IntraThresh = INTRA_THRESH, InterThresh = INTER_THRESH + 10*b_thresh;
2181            int s = 0, blocks = 0;
2182    
2183            int32_t iMinSAD[5], temp[5];
2184            VECTOR currentMV[5];
2185            SearchData Data;
2186            Data.iEdgedWidth = pParam->edged_width;
2187            Data.currentMV = currentMV;
2188            Data.iMinSAD = iMinSAD;
2189            Data.iFcode = Current->fcode;
2190            Data.temp = temp;
2191            CheckCandidate = CheckCandidate32I;
2192    
2193            if (intraCount != 0) {
2194                    if (intraCount < 10) // we're right after an I frame
2195                            IntraThresh += 15* (intraCount - 10) * (intraCount - 10);
2196                    else
2197                            if ( 5*(maxIntra - intraCount) < maxIntra) // we're close to maximum. 2 sec when max is 10 sec
2198                                    IntraThresh -= (IntraThresh * (maxIntra - 8*(maxIntra - intraCount)))/maxIntra;
2199            }
2200    
2201                  bPredEq = 0;          InterThresh -= (350 - 8*b_thresh) * bCount;
2202                  psad[0] = psad[1] = psad[2] = psad[3] = 0;          if (InterThresh < 300 + 5*b_thresh) InterThresh = 300 + 5*b_thresh;
                 *currMV = pmv[0] = pmv[1] = pmv[2] = pmv[3] = zeroMV;  
2203    
2204          } else {          if (sadInit) (*sadInit) ();
                 threshA = psad[0];  
                 threshB = threshA + 256;  
                 if (threshA < 512)  
                         threshA = 512;  
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
   
                 bPredEq = get_ipmvdata(pMBs, iWcount, 0, x, y, 0, pmv, psad);  
                 *currMV = pmv[0];                       /* current best := prediction */  
         }  
   
         iFound = 0;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
2205    
2206          if (currMV->x > max_dx) {          for (y = 1; y < pParam->mb_height-1; y += 2) {
2207                  currMV->x = EVEN(max_dx);                  for (x = 1; x < pParam->mb_width-1; x += 2) {
2208          }                          int i;
2209          if (currMV->x < min_dx) {                          blocks += 4;
2210                  currMV->x = EVEN(min_dx);  
2211                            if (bCount == 0) pMBs[x + y * pParam->mb_width].mvs[0] = zeroMV;
2212                            else { //extrapolation of the vector found for last frame
2213                                    pMBs[x + y * pParam->mb_width].mvs[0].x =
2214                                            (pMBs[x + y * pParam->mb_width].mvs[0].x * (bCount+1) ) / bCount;
2215                                    pMBs[x + y * pParam->mb_width].mvs[0].y =
2216                                            (pMBs[x + y * pParam->mb_width].mvs[0].y * (bCount+1) ) / bCount;
2217          }          }
2218          if (currMV->y > max_dy) {  
2219                  currMV->y = EVEN(max_dy);                          MEanalyzeMB(pRef->y, pCurrent->y, x, y, pParam, pMBs, &Data);
2220    
2221                            for (i = 0; i < 4; i++) {
2222                                    int dev;
2223                                    MACROBLOCK *pMB = &pMBs[x+(i&1) + (y+(i>>1)) * pParam->mb_width];
2224                                    if (pMB->sad16 > IntraThresh) {
2225                                            dev = dev16(pCurrent->y + (x + (i&1) + (y + (i>>1)) * pParam->edged_width) * 16,
2226                                                                            pParam->edged_width);
2227                                            if (dev + IntraThresh < pMB->sad16) {
2228                                                    pMB->mode = MODE_INTRA;
2229                                                    if (++intra > ((pParam->mb_height-2)*(pParam->mb_width-2))/2) return I_VOP;
2230          }          }
         if (currMV->y < min_dy) {  
                 currMV->y = EVEN(min_dy);  
2231          }          }
2232                                    if (pMB->mvs[0].x == 0 && pMB->mvs[0].y == 0) s++;
2233    
2234          iMinSAD =                                  sSAD += pMB->sad16;
2235                  sad16(cur,                          }
                           get_iref_mv(pRef, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256) ||  
                 ((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;  
2236                          }                          }
2237                  }                  }
2238    
2239                  if (MotionFlags & PMV_EARLYSTOP16)          sSAD /= blocks;
2240                          goto PMVfastInt16_Terminate_with_Refine;  
2241            if (b_thresh < 20) {
2242                    s = (10*s) / blocks;
2243                    if (s > 4) sSAD += (s - 2) * (40 - 2*b_thresh); //static block - looks bad when in bframe...
2244          }          }
2245    
2246            if (sSAD > InterThresh ) return P_VOP;
2247            emms();
2248            return B_VOP;
2249    }
2250    
 /* 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  
 */  
2251    
2252          if ((bPredEq) && (MVequal(pmv[0], prevMB->i_mvs[0])))  static WARPPOINTS
2253                  iFound = 2;  GlobalMotionEst(const MACROBLOCK * const pMBs,
2254                                    const MBParam * const pParam,
2255                                    const FRAMEINFO * const current,
2256                                    const FRAMEINFO * const reference,
2257                                    const IMAGE * const pRefH,
2258                                    const IMAGE * const pRefV,
2259                                    const IMAGE * const pRefHV      )
2260    {
2261    
2262  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          const int deltax=8;             // upper bound for difference between a MV and it's neighbour MVs
2263     Otherwise select large Diamond Search.          const int deltay=8;
2264  */          const int grad=512;             // lower bound for deviation in MB
2265    
2266          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))          WARPPOINTS gmc;
                 iDiamondSize = 2;               // halfpel units!  
         else  
                 iDiamondSize = 4;               // halfpel units!  
2267    
2268  /*          uint32_t mx, my;
    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.  
 */  
2269    
2270  // (0,0) is often a good choice          int MBh = pParam->mb_height;
2271            int MBw = pParam->mb_width;
2272    
2273          if (!MVzero(pmv[0]))          int *MBmask= calloc(MBh*MBw,sizeof(int));
2274                  CHECK_MV16_ZERO;          double DtimesF[4] = { 0.,0., 0., 0. };
2275            double sol[4] = { 0., 0., 0., 0. };
2276            double a,b,c,n,denom;
2277            double meanx,meany;
2278            int num,oldnum;
2279    
2280  // previous frame MV is always possible          if (!MBmask) {  fprintf(stderr,"Mem error\n");
2281                                            gmc.duv[0].x= gmc.duv[0].y =
2282                                                    gmc.duv[1].x= gmc.duv[1].y =
2283                                                    gmc.duv[2].x= gmc.duv[2].y = 0;
2284                                            return gmc; }
2285    
2286          if (!MVzero(prevMB->i_mvs[0]))  // filter mask of all blocks
                 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;  
2287    
2288            for (my = 1; my < (uint32_t)MBh-1; my++)
2289            for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2290            {
2291                    const int mbnum = mx + my * MBw;
2292                    const MACROBLOCK *pMB = &pMBs[mbnum];
2293                    const VECTOR mv = pMB->mvs[0];
2294    
2295  /* Step 6: If MinSAD <= thresa goto Step 10.                  if (pMB->mode == MODE_INTRA || pMB->mode == MODE_NOT_CODED)
2296     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.                          continue;
 */  
2297    
2298          if ((iMinSAD <= threshA) ||                  if ( ( (abs(mv.x -   (pMB-1)->mvs[0].x) < deltax) && (abs(mv.y -   (pMB-1)->mvs[0].y) < deltay) )
2299                  (MVequal(*currMV, prevMB->i_mvs[0]) &&                  &&   ( (abs(mv.x -   (pMB+1)->mvs[0].x) < deltax) && (abs(mv.y -   (pMB+1)->mvs[0].y) < deltay) )
2300                   ((int32_t) iMinSAD < prevMB->i_sad16))) {                  &&   ( (abs(mv.x - (pMB-MBw)->mvs[0].x) < deltax) && (abs(mv.y - (pMB-MBw)->mvs[0].y) < deltay) )
2301                    &&   ( (abs(mv.x - (pMB+MBw)->mvs[0].x) < deltax) && (abs(mv.y - (pMB+MBw)->mvs[0].y) < deltay) ) )
2302                  if (MotionFlags & PMV_EARLYSTOP16)                          MBmask[mbnum]=1;
                         goto PMVfastInt16_Terminate_with_Refine;  
2303          }          }
2304    
2305            for (my = 1; my < (uint32_t)MBh-1; my++)
2306            for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2307            {
2308                    const uint8_t *const pCur = current->image.y + 16*my*pParam->edged_width + 16*mx;
2309    
2310                    const int mbnum = mx + my * MBw;
2311                    if (!MBmask[mbnum])
2312                            continue;
2313    
2314  /************ (Diamond Search)  **************/                  if (sad16 ( pCur, pCur+1 , pParam->edged_width, 65536) <= (uint32_t)grad )
2315  /*                          MBmask[mbnum] = 0;
2316     Step 7: Perform Diamond search, with either the small or large diamond.                  if (sad16 ( pCur, pCur+pParam->edged_width, pParam->edged_width, 65536) <= (uint32_t)grad )
2317     If Found=2 only examine one Diamond pattern, and afterwards goto step 10                          MBmask[mbnum] = 0;
    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.  
 */  
2318    
2319          if (MotionFlags & PMV_USESQUARES16)          }
                 MainSearchPtr = Square16_MainSearch;  
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
2320    
2321          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          emms();
2322    
2323            do {            /* until convergence */
2324    
2325  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          a = b = c = n = 0;
2326          iSAD =          DtimesF[0] = DtimesF[1] = DtimesF[2] = DtimesF[3] = 0.;
2327                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,          for (my = 0; my < (uint32_t)MBh; my++)
2328                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,                  for (mx = 0; mx < (uint32_t)MBw; mx++)
2329                                                    min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,                  {
2330                                                    iQuant, iFound);                          const int mbnum = mx + my * MBw;
2331                            const MACROBLOCK *pMB = &pMBs[mbnum];
2332                            const VECTOR mv = pMB->mvs[0];
2333    
2334          if (iSAD < iMinSAD) {                          if (!MBmask[mbnum])
2335                  *currMV = newMV;                                  continue;
                 iMinSAD = iSAD;  
         }  
2336    
2337          if (MotionFlags & PMV_EXTSEARCH16) {                          n++;
2338  /* extended: search (up to) two more times: orignal prediction and (0,0) */                          a += 16*mx+8;
2339                            b += 16*my+8;
2340                            c += (16*mx+8)*(16*mx+8)+(16*my+8)*(16*my+8);
2341    
2342                            DtimesF[0] += (double)mv.x;
2343                            DtimesF[1] += (double)mv.x*(16*mx+8) + (double)mv.y*(16*my+8);
2344                            DtimesF[2] += (double)mv.x*(16*my+8) - (double)mv.y*(16*mx+8);
2345                            DtimesF[3] += (double)mv.y;
2346                    }
2347    
2348            denom = a*a+b*b-c*n;
2349    
2350    /* Solve the system:    sol = (D'*E*D)^{-1} D'*E*F   */
2351    /* D'*E*F has been calculated in the same loop as matrix */
2352    
2353            sol[0] = -c*DtimesF[0] + a*DtimesF[1] + b*DtimesF[2];
2354            sol[1] =  a*DtimesF[0] - n*DtimesF[1]                           + b*DtimesF[3];
2355            sol[2] =  b*DtimesF[0]                          - n*DtimesF[2] - a*DtimesF[3];
2356            sol[3] =                                 b*DtimesF[1] - a*DtimesF[2] - c*DtimesF[3];
2357    
2358            sol[0] /= denom;
2359            sol[1] /= denom;
2360            sol[2] /= denom;
2361            sol[3] /= denom;
2362    
2363            meanx = meany = 0.;
2364            oldnum = 0;
2365            for (my = 0; my < (uint32_t)MBh; my++)
2366                    for (mx = 0; mx < (uint32_t)MBw; mx++)
2367                    {
2368                            const int mbnum = mx + my * MBw;
2369                            const MACROBLOCK *pMB = &pMBs[mbnum];
2370                            const VECTOR mv = pMB->mvs[0];
2371    
2372                  if (!(MVequal(pmv[0], backupMV))) {                          if (!MBmask[mbnum])
2373                          iSAD =                                  continue;
                                 (*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);  
2374    
2375                          if (iSAD < iMinSAD) {                          oldnum++;
2376                                  *currMV = newMV;                          meanx += fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - mv.x );
2377                                  iMinSAD = iSAD;                          meany += fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - mv.y );
                         }  
2378                  }                  }
2379    
2380                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          if (4*meanx > oldnum)   /* better fit than 0.25 is useless */
2381                          iSAD =                  meanx /= oldnum;
2382                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,          else
2383                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,                  meanx = 0.25;
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
2384    
2385                          if (iSAD < iMinSAD) {          if (4*meany > oldnum)
2386                                  *currMV = newMV;                  meany /= oldnum;
2387                                  iMinSAD = iSAD;          else
2388                          }                  meany = 0.25;
                 }  
         }  
2389    
2390  /*  /*      fprintf(stderr,"sol = (%8.5f, %8.5f, %8.5f, %8.5f)\n",sol[0],sol[1],sol[2],sol[3]);
2391     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.          fprintf(stderr,"meanx = %8.5f  meany = %8.5f   %d\n",meanx,meany, oldnum);
2392  */  */
2393            num = 0;
2394            for (my = 0; my < (uint32_t)MBh; my++)
2395                    for (mx = 0; mx < (uint32_t)MBw; mx++)
2396                    {
2397                            const int mbnum = mx + my * MBw;
2398                            const MACROBLOCK *pMB = &pMBs[mbnum];
2399                            const VECTOR mv = pMB->mvs[0];
2400    
2401                            if (!MBmask[mbnum])
2402                                    continue;
2403    
2404                            if  ( ( fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - mv.x ) > meanx )
2405                                    || ( fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - mv.y ) > meany ) )
2406                                    MBmask[mbnum]=0;
2407                            else
2408                                    num++;
2409                    }
2410    
2411  PMVfastInt16_Terminate_with_Refine:          } while ( (oldnum != num) && (num>=4) );
2412    
2413          pMB->i_mvs[0] = pMB->i_mvs[1] = pMB->i_mvs[2] = pMB->i_mvs[3] = pMB->i_mv16 = *currMV;          if (num < 4)
2414          pMB->i_sad8[0] = pMB->i_sad8[1] = pMB->i_sad8[2] = pMB->i_sad8[3] = pMB->i_sad16 = iMinSAD;          {
2415                    gmc.duv[0].x= gmc.duv[0].y= gmc.duv[1].x= gmc.duv[1].y= gmc.duv[2].x= gmc.duv[2].y=0;
2416            } else {
2417    
2418          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step                  gmc.duv[0].x=(int)(sol[0]+0.5);
2419                  iMinSAD =                  gmc.duv[0].y=(int)(sol[3]+0.5);
                         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);  
2420    
2421          pmv[0] = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          // get _REAL_ prediction (halfpel possible)                  gmc.duv[1].x=(int)(sol[1]*pParam->width+0.5);
2422                    gmc.duv[1].y=(int)(-sol[2]*pParam->width+0.5);
2423    
2424  PMVfastInt16_Terminate_without_Refine:                  gmc.duv[2].x=0;
2425          currPMV->x = currMV->x - center_x;                  gmc.duv[2].y=0;
         currPMV->y = currMV->y - center_y;  
         return iMinSAD;  
2426  }  }
2427    //      fprintf(stderr,"wp1 = ( %4d, %4d)  wp2 = ( %4d, %4d) \n", gmc.duv[0].x, gmc.duv[0].y, gmc.duv[1].x, gmc.duv[1].y);
2428    
2429            free(MBmask);
2430    
2431            return gmc;
2432    }
2433    
2434  /* ***********************************************************  // functions which perform BITS-based search/bitcount
         bvop motion estimation  
 ***************************************************************/  
2435    
2436  void  static int
2437  MotionEstimationBVOP(MBParam * const pParam,  CountMBBitsInter(SearchData * const Data,
2438                                           FRAMEINFO * const frame,                                  const MACROBLOCK * const pMBs, const int x, const int y,
2439                                           const int32_t time_bp,                                  const MBParam * const pParam,
2440                                           const int32_t time_pp,                                  const uint32_t MotionFlags)
                                          // forward (past) reference  
                                          const MACROBLOCK * const f_mbs,  
                                          const IMAGE * const f_ref,  
                                          const IMAGE * const f_refH,  
                                          const IMAGE * const f_refV,  
                                          const IMAGE * const f_refHV,  
                                          // backward (future) reference  
                                          const MACROBLOCK * const b_mbs,  
                                          const IMAGE * const b_ref,  
                                          const IMAGE * const b_refH,  
                                          const IMAGE * const b_refV,  
                                          const IMAGE * const b_refHV)  
2441  {  {
2442          const int mb_width = pParam->mb_width;          int i, iDirection;
2443          const int mb_height = pParam->mb_height;          int32_t bsad[5];
         const int edged_width = pParam->edged_width;  
2444    
2445          const int32_t iWidth = pParam->width;          CheckCandidate = CheckCandidateBits16;
2446          const int32_t iHeight = pParam->height;  
2447            if (Data->qpel) {
2448                    for(i = 0; i < 5; i++) {
2449                            Data->currentMV[i].x = Data->currentQMV[i].x/2;
2450                            Data->currentMV[i].y = Data->currentQMV[i].y/2;
2451                    }
2452                    Data->qpel_precision = 1;
2453                    CheckCandidateBits16(Data->currentQMV[0].x, Data->currentQMV[0].y, 255, &iDirection, Data);
2454    
2455          int i, j, k;                  if (MotionFlags & (HALFPELREFINE16_BITS | EXTSEARCH_BITS)) { //we have to prepare for halfpixel-precision search
2456                            for(i = 0; i < 5; i++) bsad[i] = Data->iMinSAD[i];
2457                            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2458                                                    pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
2459                            Data->qpel_precision = 0;
2460                            if (Data->currentQMV->x & 1 || Data->currentQMV->y & 1)
2461                                    CheckCandidateBits16(Data->currentMV[0].x, Data->currentMV[0].y, 255, &iDirection, Data);
2462                    }
2463    
2464          static const VECTOR zeroMV={0,0};          } else { // not qpel
2465    
2466          int f_sad16;    /* forward (as usual) search */                  CheckCandidateBits16(Data->currentMV[0].x, Data->currentMV[0].y, 255, &iDirection, Data);
2467          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) */  
2468    
2469          int best_sad;          if (MotionFlags&EXTSEARCH_BITS) SquareSearch(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
2470    
2471          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/          if (MotionFlags&HALFPELREFINE16_BITS) SubpelRefine(Data);
         VECTOR f_interpolMV, b_interpolMV;  
         VECTOR pmv_dontcare;  
2472    
2473          int min_dx, max_dx, min_dy, max_dy;          if (Data->qpel) {
2474          int f_min_dx, f_max_dx, f_min_dy, f_max_dy;                  if (MotionFlags&(EXTSEARCH_BITS | HALFPELREFINE16_BITS)) { // there was halfpel-precision search
2475          int b_min_dx, b_max_dx, b_min_dy, b_max_dy;                          for(i = 0; i < 5; i++) if (bsad[i] > Data->iMinSAD[i]) {
2476                                    Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // we have found a better match
2477          int f_count=0;                                  Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
2478          int b_count=0;                          }
         int i_count=0;  
         int d_count=0;  
2479    
2480          const int64_t TRB = (int32_t)time_pp - (int32_t)time_bp;                          // preparing for qpel-precision search
2481      const int64_t TRD = (int32_t)time_pp;                          Data->qpel_precision = 1;
2482                            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2483                                            pParam->width, pParam->height, Data->iFcode, 1, 0);
2484                    }
2485                    if (MotionFlags&QUARTERPELREFINE16_BITS) SubpelRefine(Data);
2486            }
2487    
2488          // fprintf(stderr,"TRB = %lld  TRD = %lld  time_bp =%d time_pp =%d\n\n",TRB,TRD,time_bp,time_pp);          if (MotionFlags&CHECKPREDICTION_BITS) { //let's check vector equal to prediction
2489          // note: i==horizontal, j==vertical                  VECTOR * v = Data->qpel ? Data->currentQMV : Data->currentMV;
2490          for (j = 0; j < mb_height; j++) {                  if (!(Data->predMV.x == v->x && Data->predMV.y == v->y))
2491                            CheckCandidateBits16(Data->predMV.x, Data->predMV.y, 255, &iDirection, Data);
2492            }
2493            return Data->iMinSAD[0];
2494    }
2495    
2496                  f_predMV = zeroMV;      /* prediction is reset at left boundary */  static int
2497                  b_predMV = zeroMV;  CountMBBitsInter4v(const SearchData * const Data,
2498                                            MACROBLOCK * const pMB, const MACROBLOCK * const pMBs,
2499                                            const int x, const int y,
2500                                            const MBParam * const pParam, const uint32_t MotionFlags,
2501                                            const VECTOR * const backup)
2502    {
2503    
2504                  for (i = 0; i < mb_width; i++) {          int cbp = 0, bits = 0, t = 0, i, iDirection;
2505                          MACROBLOCK *mb = &frame->mbs[i + j * mb_width];          SearchData Data2, *Data8 = &Data2;
2506                          const MACROBLOCK *f_mb = &f_mbs[i + j * mb_width];          int sumx = 0, sumy = 0;
2507                          const MACROBLOCK *b_mb = &b_mbs[i + j * mb_width];          int16_t *in = Data->dctSpace, *coeff = Data->dctSpace + 64;
2508            uint8_t * ptr;
2509    
2510            memcpy(Data8, Data, sizeof(SearchData));
2511            CheckCandidate = CheckCandidateBits8;
2512    
2513            for (i = 0; i < 4; i++) { //for all luma blocks
2514    
2515                    Data8->iMinSAD = Data->iMinSAD + i + 1;
2516                    Data8->currentMV = Data->currentMV + i + 1;
2517                    Data8->currentQMV = Data->currentQMV + i + 1;
2518                    Data8->Cur = Data->Cur + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2519                    Data8->RefP[0] = Data->RefP[0] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2520                    Data8->RefP[2] = Data->RefP[2] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2521                    Data8->RefP[1] = Data->RefP[1] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2522                    Data8->RefP[3] = Data->RefP[3] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2523    
2524                    if(Data->qpel) {
2525                            Data8->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, i);
2526                            if (i != 0)     t = d_mv_bits(  Data8->currentQMV->x, Data8->currentQMV->y,
2527                                                                                    Data8->predMV, Data8->iFcode, 0, 0);
2528                    } else {
2529                            Data8->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, i);
2530                            if (i != 0)     t = d_mv_bits(  Data8->currentMV->x, Data8->currentMV->y,
2531                                                                                    Data8->predMV, Data8->iFcode, 0, 0);
2532                    }
2533    
2534                          mb->deltamv=zeroMV;                  get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 8,
2535                                            pParam->width, pParam->height, Data8->iFcode, Data8->qpel, 0);
2536    
2537  /* special case, if collocated block is SKIPed: encoding is forward (0,0), cpb=0 without further ado */                  *Data8->iMinSAD += BITS_MULT*t;
2538    
2539                          if (b_mb->mode == MODE_INTER && b_mb->cbp == 0 &&                  Data8->qpel_precision = Data8->qpel;
2540                                  b_mb->mvs[0].x == 0 && b_mb->mvs[0].y == 0) {                  // checking the vector which has been found by SAD-based 8x8 search (if it's different than the one found so far)
2541                                  mb->mode = MODE_NOT_CODED;                  {
2542                                  mb->b_mvs[0] = mb->mvs[0] = zeroMV;                          VECTOR *v = Data8->qpel ? Data8->currentQMV : Data8->currentMV;
2543                                  continue;                          if (!MVequal (*v, backup[i+1]) )
2544                                    CheckCandidateBits8(backup[i+1].x, backup[i+1].y, 255, &iDirection, Data8);
2545                          }                          }
2546    
2547                          if (b_mb->mode == MODE_INTER4V)                  if (Data8->qpel) {
2548                          {                          if (MotionFlags&HALFPELREFINE8_BITS || (MotionFlags&PMV_EXTSEARCH8 && MotionFlags&EXTSEARCH_BITS)) { // halfpixel motion search follows
2549                                  d_sad16 = 0;                                  int32_t s = *Data8->iMinSAD;
2550                          /* same method of scaling as in decoder.c, so we copy from there */                                  Data8->currentMV->x = Data8->currentQMV->x/2;
2551                      for (k = 0; k < 4; k++) {                                  Data8->currentMV->y = Data8->currentQMV->y/2;
2552                                    Data8->qpel_precision = 0;
2553                                    get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 8,
2554                                                            pParam->width, pParam->height, Data8->iFcode - 1, 0, 0);
2555    
2556                                          mb->directmv[k] = b_mb->mvs[k];                                  if (Data8->currentQMV->x & 1 || Data8->currentQMV->y & 1)
2557                                            CheckCandidateBits8(Data8->currentMV->x, Data8->currentMV->y, 255, &iDirection, Data8);
2558    
2559                                          mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);                                  if (MotionFlags & PMV_EXTSEARCH8 && MotionFlags & EXTSEARCH_BITS)
2560                      mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)                                          SquareSearch(Data8->currentMV->x, Data8->currentMV->x, Data8, 255);
2561                                                                                  ? ((TRB - TRD) * mb->directmv[k].x) / TRD  
2562                                              : mb->mvs[k].x - mb->directmv[k].x);                                  if (MotionFlags & HALFPELREFINE8_BITS)
2563                                            SubpelRefine(Data8);
2564                      mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);  
2565                          mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)                                  if (s > *Data8->iMinSAD) { //we have found a better match
2566                                                                                  ? ((TRB - TRD) * mb->directmv[k].y) / TRD                                          Data8->currentQMV->x = 2*Data8->currentMV->x;
2567                                              : mb->mvs[k].y - mb->directmv[k].y);                                          Data8->currentQMV->y = 2*Data8->currentMV->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);  
                                 }  
2568                          }                          }
                         else  
                         {  
                                 mb->directmv[3] = mb->directmv[2] = mb->directmv[1] =  
                                         mb->directmv[0] = b_mb->mvs[0];  
2569    
2570                                  mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);                                  Data8->qpel_precision = 1;
2571                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)                                  get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 8,
2572                                                                          ? ((TRB - TRD) * mb->directmv[0].x) / TRD                                                          pParam->width, pParam->height, Data8->iFcode, 1, 0);
                                     : mb->mvs[0].x - mb->directmv[0].x);  
   
                     mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);  
                 mb->b_mvs[0].y = (int32_t) ((mb->directmv[0].y == 0)  
                                                                         ? ((TRB - TRD) * mb->directmv[0].y) / TRD  
                                     : mb->mvs[0].y - mb->directmv[0].y);  
   
                                 d_sad16 = sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 i, j, 16, &mb->mvs[0], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 i, j, 16, &mb->b_mvs[0], edged_width),  
                                                   edged_width);  
2573    
2574              }              }
2575                      d_sad16 += calc_delta_16(mb->deltamv.x, mb->deltamv.y, 1, frame->quant);                          if (MotionFlags & QUARTERPELREFINE8_BITS) SubpelRefine(Data8);
2576    
2577                          // forward search                  } else { // not qpel
                         f_sad16 = SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 &frame->image, i, j,  
                                                 mb->mvs[0].x, mb->mvs[0].y,                     /* start point f_directMV */  
                                                 f_predMV.x, f_predMV.y,                         /* center is f-prediction */  
                                                 frame->motion_flags,  
                                                 frame->quant, frame->fcode, pParam,  
                                                 f_mbs, f_mbs,  
                                                 &mb->mvs[0], &pmv_dontcare);  
2578    
2579                            if (MotionFlags & PMV_EXTSEARCH8 && MotionFlags & EXTSEARCH_BITS) //extsearch
2580                                    SquareSearch(Data8->currentMV->x, Data8->currentMV->x, Data8, 255);
2581    
2582                          // backward search                          if (MotionFlags & HALFPELREFINE8_BITS)
2583                          b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,                                  SubpelRefine(Data8); //halfpel refinement
                                                 &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 */  
                                                 frame->motion_flags,  
                                                 frame->quant, frame->bcode, pParam,  
                                                 b_mbs, b_mbs,  
                                                 &mb->b_mvs[0], &pmv_dontcare);  
   
                         i_sad16 =  
                                 sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 i, j, 16, &mb->mvs[0], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 i, j, 16, &mb->b_mvs[0], edged_width),  
                                                   edged_width);  
                     i_sad16 += calc_delta_16(mb->mvs[0].x-f_predMV.x, mb->mvs[0].y-f_predMV.y,  
                                                                 frame->fcode, frame->quant);  
                     i_sad16 += calc_delta_16(mb->b_mvs[0].x-b_predMV.x, mb->b_mvs[0].y-b_predMV.y,  
                                                                 frame->bcode, frame->quant);  
   
                         get_range(&f_min_dx, &f_max_dx, &f_min_dy, &f_max_dy, i, j, 16, iWidth, iHeight,  
                           frame->fcode);  
                         get_range(&b_min_dx, &b_max_dx, &b_min_dy, &b_max_dy, i, j, 16, iWidth, iHeight,  
                           frame->bcode);  
   
 /* Interpolated MC motion vector search, this is tedious and more complicated because there are  
    two values for everything, always one for backward and one for forward ME. Still, we don't gain  
    much from this search, maybe it should simply be skipped and simply current i_sad16 value used  
    as "optimal". */  
   
                         i_sad16 = Diamond16_InterpolMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i * 16 + j * 16 * edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 mb->mvs[0].x, mb->mvs[0].y,  
                                                 mb->b_mvs[0].x, mb->b_mvs[0].y,  
                                                 i_sad16,  
                                                 &f_interpolMV, &b_interpolMV,  
                                                 f_predMV.x, f_predMV.y, b_predMV.x, b_predMV.y,  
                                                 f_min_dx, f_max_dx, f_min_dy, f_max_dy,  
                                                 b_min_dx, b_max_dx, b_min_dy, b_max_dy,  
                                                 edged_width,  2,  
                                                 frame->fcode, frame->bcode,frame->quant,0);  
   
                         i_sad16 = Diamond16_InterpolMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i * 16 + j * 16 * edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 f_interpolMV.x, f_interpolMV.y,  
                                                 b_interpolMV.x, b_interpolMV.y,  
                                                 i_sad16,  
                                                 &f_interpolMV, &b_interpolMV,  
                                                 f_predMV.x, f_predMV.y, b_predMV.x, b_predMV.y,  
                                                 f_min_dx, f_max_dx, f_min_dy, f_max_dy,  
                                                 b_min_dx, b_max_dx, b_min_dy, b_max_dy,  
                                                 edged_width,  1,  
                                                 frame->fcode, frame->bcode,frame->quant,0);             // equiv to halfpel refine  
   
   
 /*  DIRECT MODE DELTA VECTOR SEARCH.  
     This has to be made more effective, but at the moment I'm happy it's running at all */  
   
 /* There are two range restrictions for direct mode: deltaMV is limited to [-32,31] in halfpel units, and  
    absolute vector must not lie outside of image dimensions. Constraint one is dealt with by CHECK_MV16_DIRECT  
    and for constraint two we need distance to boundary. This is done by get_range very large fcode (hack!) */  
   
                         get_range(&min_dx, &max_dx, &min_dy, &max_dy, i, j, 16, iWidth, iHeight, 19);  
   
                         d_sad16 = Diamond16_DirectMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i*16 + j*16*edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 TRB,TRD,  
                                                 0,0,  
                                                 d_sad16,  
                                                 &mb->deltamv,  
                                                 mb->directmv, // this has to be pre-initialized with b_mb->mvs[]  
                                         min_dx, max_dx, min_dy, max_dy,  
                                                 edged_width, 2, frame->quant, 0);  
   
                         d_sad16 = Diamond16_DirectMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i*16 + j*16*edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 TRB,TRD,  
                                                 mb->deltamv.x, mb->deltamv.y,  
                                                 d_sad16,  
                                                 &mb->deltamv,  
                                                 mb->directmv, // this has to be pre-initialized with b_mb->mvs[]  
                                         min_dx, max_dx, min_dy, max_dy,  
                                                 edged_width, 1, frame->quant, 0);               // equiv to halfpel refine  
   
   
 //                      i_sad16 = 65535;                /* remove the comment to disable any of the MODEs */  
 //                      f_sad16 = 65535;  
 //                      b_sad16 = 65535;  
 //                      d_sad16 = 65535;  
   
                         if (f_sad16 < b_sad16) {  
                                 best_sad = f_sad16;  
                                 mb->mode = MODE_FORWARD;  
                         } else {  
                                 best_sad = b_sad16;  
                                 mb->mode = MODE_BACKWARD;  
2584                          }                          }
2585    
2586                          if (i_sad16 < best_sad) {                  //checking vector equal to predicion
2587                                  best_sad = i_sad16;                  if (i != 0 && MotionFlags & CHECKPREDICTION_BITS) {
2588                                  mb->mode = MODE_INTERPOLATE;                          const VECTOR * v = Data->qpel ? Data8->currentQMV : Data8->currentMV;
2589                            if (!MVequal(*v, Data8->predMV))
2590                                    CheckCandidateBits8(Data8->predMV.x, Data8->predMV.y, 255, &iDirection, Data8);
2591                          }                          }
2592    
2593                          if (d_sad16 < best_sad) {                  bits += *Data8->iMinSAD;
2594                    if (bits >= Data->iMinSAD[0]) return bits; // no chances for INTER4V
2595    
2596                                  if (b_mb->mode == MODE_INTER4V)                  // MB structures for INTER4V mode; we have to set them here, we don't have predictor anywhere else
2597                                  {                  if(Data->qpel) {
2598                            pMB->pmvs[i].x = Data8->currentQMV->x - Data8->predMV.x;
2599                            pMB->pmvs[i].y = Data8->currentQMV->y - Data8->predMV.y;
2600                            pMB->qmvs[i] = *Data8->currentQMV;
2601                            sumx += Data8->currentQMV->x/2;
2602                            sumy += Data8->currentQMV->y/2;
2603                    } else {
2604                            pMB->pmvs[i].x = Data8->currentMV->x - Data8->predMV.x;
2605                            pMB->pmvs[i].y = Data8->currentMV->y - Data8->predMV.y;
2606                            sumx += Data8->currentMV->x;
2607                            sumy += Data8->currentMV->y;
2608                    }
2609                    pMB->mvs[i] = *Data8->currentMV;
2610                    pMB->sad8[i] = 4 * *Data8->iMinSAD;
2611                    if (Data8->temp[0]) cbp |= 1 << (5 - i);
2612    
2613                                  /* how to calc vectors is defined in standard. mvs[] and b_mvs[] are only for motion compensation */          } // /for all luma blocks
                                 /* for the bitstream, the value mb->deltamv is read directly */  
2614    
2615                              for (k = 0; k < 4; k++) {          bits += BITS_MULT*xvid_cbpy_tab[15-(cbp>>2)].len;
2616    
2617                                                  mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);          // let's check chroma
2618                              mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)          sumx = (sumx >> 3) + roundtab_76[sumx & 0xf];
2619                                                                                          ? ((TRB - TRD) * mb->directmv[k].x) / TRD          sumy = (sumy >> 3) + roundtab_76[sumy & 0xf];
                                                     : 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);  
                                         }  
                                 }  
                                 else  
                                 {  
                                         mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);  
2620    
2621                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)          //chroma U
2622                                                                                  ? ((TRB - TRD) * mb->directmv[0].x) / TRD          ptr = interpolate8x8_switch2(Data->RefQ + 64, Data->RefP[4], 0, 0, sumx, sumy, Data->iEdgedWidth/2, Data->rounding);
2623                                          : mb->mvs[0].x - mb->directmv[0].x);          transfer_8to16subro(in, Data->CurU, ptr, Data->iEdgedWidth/2);
2624            bits += Block_CalcBits(coeff, in, Data->iQuant, Data->quant_type, &cbp, 4);
2625    
2626                              mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);          if (bits >= *Data->iMinSAD) return bits;
2627    
2628                          mb->b_mvs[0].y = (int32_t) ((mb->deltamv.y == 0)          //chroma V
2629                                                                                  ? ((TRB - TRD) * mb->directmv[0].y) / TRD          ptr = interpolate8x8_switch2(Data->RefQ + 64, Data->RefP[5], 0, 0, sumx, sumy, Data->iEdgedWidth/2, Data->rounding);
2630                                              : mb->mvs[0].y - mb->directmv[0].y);          transfer_8to16subro(in, Data->CurV, ptr, Data->iEdgedWidth/2);
2631            bits += Block_CalcBits(coeff, in, Data->iQuant, Data->quant_type, &cbp, 5);
2632    
2633                                          mb->mvs[3] = mb->mvs[2] = mb->mvs[1] = mb->mvs[0];          bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTER4V & 7) | ((cbp & 3) << 3)].len;
                                         mb->b_mvs[3] = mb->b_mvs[2] = mb->b_mvs[1] = mb->b_mvs[0];  
                 }  
2634    
2635                                  best_sad = d_sad16;          return bits;
                                 mb->mode = MODE_DIRECT;  
2636                          }                          }
2637    
2638                          switch (mb->mode)  static int
2639    CountMBBitsIntra(const SearchData * const Data)
2640                          {                          {
2641                                  case MODE_FORWARD:          int bits = BITS_MULT*1; //this one is ac/dc prediction flag bit
2642                                          f_count++;          int cbp = 0, i, dc = 0;
2643                                          f_predMV = mb->mvs[0];          int16_t *in = Data->dctSpace, * coeff = Data->dctSpace + 64;
                                         break;  
                                 case MODE_BACKWARD:  
                                         b_count++;  
                                         b_predMV = mb->b_mvs[0];  
2644    
2645                                          break;          for(i = 0; i < 4; i++) {
2646                                  case MODE_INTERPOLATE:                  int s = 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2647                                          i_count++;                  transfer_8to16copy(in, Data->Cur + s, Data->iEdgedWidth);
2648                                          mb->mvs[0] = f_interpolMV;                  bits += Block_CalcBitsIntra(coeff, in, Data->iQuant, Data->quant_type, &cbp, i, &dc);
                                         mb->b_mvs[0] = b_interpolMV;  
                                         f_predMV = mb->mvs[0];  
                                         b_predMV = mb->b_mvs[0];  
                                         break;  
                                 case MODE_DIRECT:  
                                         d_count++;  
                                         break;  
                                 default:  
                                         break;  
                         }  
2649    
2650                    if (bits >= Data->iMinSAD[0]) return bits;
2651                  }                  }
         }  
2652    
2653  #ifdef _DEBUG_BFRAME_STAT          bits += BITS_MULT*xvid_cbpy_tab[cbp>>2].len;
2654          fprintf(stderr,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d\n",  
2655                                  f_count,b_count,i_count,d_count);          //chroma U
2656  #endif          transfer_8to16copy(in, Data->CurU, Data->iEdgedWidth/2);
2657            bits += Block_CalcBitsIntra(coeff, in, Data->iQuant, Data->quant_type, &cbp, 4, &dc);
2658    
2659            if (bits >= Data->iMinSAD[0]) return bits;
2660    
2661            //chroma V
2662            transfer_8to16copy(in, Data->CurV, Data->iEdgedWidth/2);
2663            bits += Block_CalcBitsIntra(coeff, in, Data->iQuant, Data->quant_type, &cbp, 5, &dc);
2664    
2665            bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTRA & 7) | ((cbp & 3) << 3)].len;
2666    
2667            return bits;
2668  }  }

Legend:
Removed from v.351  
changed lines
  Added in v.1072

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