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

Legend:
Removed from v.346  
changed lines
  Added in v.1053

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