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

Legend:
Removed from v.370  
changed lines
  Added in v.1022

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