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

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

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