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

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

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

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

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

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