[svn] / branches / dev-api-4 / xvidcore / src / motion / motion_est.c Repository:
ViewVC logotype

Diff of /branches/dev-api-4/xvidcore/src/motion/motion_est.c

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

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

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

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