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

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

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

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

Legend:
Removed from v.1.40  
changed lines
  Added in v.1.68.2.1

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