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

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

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

revision 1.26, Sat Jul 6 17:04:57 2002 UTC revision 1.44.2.2, Wed Sep 25 21:27:55 2002 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>
# Line 74  Line 37 
37  #include "../prediction/mbprediction.h"  #include "../prediction/mbprediction.h"
38  #include "../global.h"  #include "../global.h"
39  #include "../utils/timer.h"  #include "../utils/timer.h"
40    #include "motion_est.h"
41  #include "motion.h"  #include "motion.h"
42  #include "sad.h"  #include "sad.h"
43    #include "../utils/emms.h"
44    
45    #define INITIAL_SKIP_THRESH     (10)
46    #define FINAL_SKIP_THRESH       (50)
47    #define MAX_SAD00_FOR_SKIP      (20)
48    #define MAX_CHROMA_SAD_FOR_SKIP (22)
49    #define SKIP_THRESH_B (25)
50    
51    #define CHECK_CANDIDATE(X,Y,D) { \
52    (*CheckCandidate)((const int)(X),(const int)(Y), (D), &iDirection, data ); }
53    
54  static int32_t lambda_vec16[32] =       /* rounded values for lambda param for weight of motion bits as in modified H.26L */  #define iDiamondSize 2
 { 0, (int) (1.00235 + 0.5), (int) (1.15582 + 0.5), (int) (1.31976 + 0.5),  
                 (int) (1.49591 + 0.5), (int) (1.68601 + 0.5),  
         (int) (1.89187 + 0.5), (int) (2.11542 + 0.5), (int) (2.35878 + 0.5),  
                 (int) (2.62429 + 0.5), (int) (2.91455 + 0.5),  
         (int) (3.23253 + 0.5), (int) (3.58158 + 0.5), (int) (3.96555 + 0.5),  
                 (int) (4.38887 + 0.5), (int) (4.85673 + 0.5),  
         (int) (5.37519 + 0.5), (int) (5.95144 + 0.5), (int) (6.59408 + 0.5),  
                 (int) (7.31349 + 0.5), (int) (8.12242 + 0.5),  
         (int) (9.03669 + 0.5), (int) (10.0763 + 0.5), (int) (11.2669 + 0.5),  
                 (int) (12.6426 + 0.5), (int) (14.2493 + 0.5),  
         (int) (16.1512 + 0.5), (int) (18.442 + 0.5), (int) (21.2656 + 0.5),  
                 (int) (24.8580 + 0.5), (int) (29.6436 + 0.5),  
         (int) (36.4949 + 0.5)  
 };  
   
 static int32_t *lambda_vec8 = lambda_vec16;     /* same table for INTER and INTER4V for now */  
55    
56    static __inline int
57    d_mv_bits(int x, int y, const uint32_t iFcode)
58    {
59            int xb, yb;
60    
61            if (x == 0) xb = 1;
62            else {
63                    if (x < 0) x = -x;
64                    x += (1 << (iFcode - 1)) - 1;
65                    x >>= (iFcode - 1);
66                    if (x > 32) x = 32;
67                    xb = mvtab[x] + iFcode;
68            }
69    
70            if (y == 0) yb = 1;
71            else {
72                    if (y < 0) y = -y;
73                    y += (1 << (iFcode - 1)) - 1;
74                    y >>= (iFcode - 1);
75                    if (y > 32) y = 32;
76                    yb = mvtab[y] + iFcode;
77            }
78            return xb + yb;
79    }
80    
 // mv.length table  
 static const uint32_t mvtab[33] = {  
         1, 2, 3, 4, 6, 7, 7, 7,  
         9, 9, 9, 10, 10, 10, 10, 10,  
         10, 10, 10, 10, 10, 10, 10, 10,  
         10, 11, 11, 11, 11, 11, 11, 12, 12  
 };  
81    
82    /* CHECK_CANDIATE FUNCTIONS START */
83    
84  static __inline uint32_t  static void
85  mv_bits(int32_t component,  CheckCandidate16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                 const uint32_t iFcode)  
86  {  {
87          if (component == 0)          int32_t * const sad = data->temp;
88                  return 1;          int t;
89            const uint8_t * Reference;
90    
91          if (component < 0)          if (( x > data->max_dx) || ( x < data->min_dx)
92                  component = -component;                  || ( y > data->max_dy) || (y < data->min_dy)) return;
93    
94          if (iFcode == 1) {          switch ( ((x&1)<<1) + (y&1) ) {
95                  if (component > 32)                  case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
96                          component = 32;                  case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;
97                    case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;
98                  return mvtab[component] + 1;                  default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
99          }          }
100    
101          component += (1 << (iFcode - 1)) - 1;          data->temp[0] = sad16v(data->Cur, Reference, data->iEdgedWidth, sad+1);
         component >>= (iFcode - 1);  
102    
103          if (component > 32)          t = d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
104                  component = 32;          data->temp[0] += lambda_vec16[data->iQuant] * t;
105            data->temp[1] += lambda_vec8[data->iQuant] * t;
106    
107          return mvtab[component] + 1 + iFcode - 1;          if (data->temp[0] < data->iMinSAD[0]) {
108  }                  data->iMinSAD[0] = data->temp[0];
109                    data->currentMV[0].x = x; data->currentMV[0].y = y;
110                    *dir = Direction; }
111    
112            if (data->temp[1] < data->iMinSAD[1]) {
113                    data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
114            if (data->temp[2] < data->iMinSAD[2]) {
115                    data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
116            if (data->temp[3] < data->iMinSAD[3]) {
117                    data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
118            if (data->temp[4] < data->iMinSAD[4]) {
119                    data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
120    
 static __inline uint32_t  
 calc_delta_16(const int32_t dx,  
                           const int32_t dy,  
                           const uint32_t iFcode,  
                           const uint32_t iQuant)  
 {  
         return NEIGH_TEND_16X16 * lambda_vec16[iQuant] * (mv_bits(dx, iFcode) +  
                                                                                                           mv_bits(dy, iFcode));  
121  }  }
122    
123  static __inline uint32_t  static void
124  calc_delta_8(const int32_t dx,  CheckCandidate16no4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                          const int32_t dy,  
                          const uint32_t iFcode,  
                          const uint32_t iQuant)  
125  {  {
126          return NEIGH_TEND_8X8 * lambda_vec8[iQuant] * (mv_bits(dx, iFcode) +          int32_t sad;
127                                                                                                     mv_bits(dy, iFcode));          const uint8_t * Reference;
 }  
128    
129  bool          if (( x > data->max_dx) || ( x < data->min_dx)
130  MotionEstimation(MBParam * const pParam,                  || ( y > data->max_dy) || (y < data->min_dy)) return;
131                                   FRAMEINFO * const current,  
132                                   FRAMEINFO * const reference,          switch ( ((x&1)<<1) + (y&1) )
                                  const IMAGE * const pRefH,  
                                  const IMAGE * const pRefV,  
                                  const IMAGE * const pRefHV,  
                                  const uint32_t iLimit)  
133  {  {
134          const uint32_t iWcount = pParam->mb_width;                  case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
135          const uint32_t iHcount = pParam->mb_height;                  case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;
136          MACROBLOCK *const pMBs = current->mbs;                  case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;
137          MACROBLOCK *const prevMBs = reference->mbs;                  default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
138          const IMAGE *const pCurrent = &current->image;          }
         const IMAGE *const pRef = &reference->image;  
139    
140          const VECTOR zeroMV = { 0, 0 };          sad = lambda_vec16[data->iQuant] *
141                            d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
142            sad += sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
143    
144          long long time;          if (sad < *(data->iMinSAD)) {
145          int32_t x, y;                  *(data->iMinSAD) = sad;
146          int32_t iIntra = 0;                  data->currentMV[0].x = x; data->currentMV[0].y = y;
147          VECTOR pmv;                  *dir = Direction; }
148    }
         if (sadInit)  
                 (*sadInit) ();  
   
         for (y = 0; y < iHcount; y++)   {  
                 for (x = 0; x < iWcount; x ++)  {  
   
                         MACROBLOCK *const pMB = &pMBs[x + y * iWcount];  
   
                         pMB->sad16 =  
                                 SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,  
                                                  y, current->motion_flags, current->quant,  
                                                  current->fcode, pParam, pMBs, prevMBs, &pMB->mv16,  
                                                  &pMB->pmvs[0]);  
149    
150                          if (0 < (pMB->sad16 - MV16_INTER_BIAS)) {  static void
151                                  int32_t deviation;  CheckCandidate16no4vI(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
152    {
153            int32_t sad;
154    
155                                  deviation =          if (( x > data->max_dx) || ( x < data->min_dx)
156                                          dev16(pCurrent->y + x * 16 + y * 16 * pParam->edged_width,                  || ( y > data->max_dy) || (y < data->min_dy)) return;
                                                   pParam->edged_width);  
157    
158                                  if (deviation < (pMB->sad16 - MV16_INTER_BIAS)) {          sad = lambda_vec16[data->iQuant] *
159                                          pMB->mode = MODE_INTRA;                          d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
                                         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;  
160    
161                                          iIntra++;          sad += sad16(data->Cur, data->Ref + x/2 + (y/2)*(data->iEdgedWidth),
162                                          if (iIntra >= iLimit)                                          data->iEdgedWidth, 256*4096);
                                                 return 1;  
163    
164                                          continue;          if (sad < *(data->iMinSAD)) {
165                                  }                  *(data->iMinSAD) = sad;
166                    data->currentMV[0].x = x; data->currentMV[0].y = y;
167                    *dir = Direction; }
168                          }                          }
169    
                         pmv = pMB->pmvs[0];  
                         if (current->global_flags & XVID_INTER4V)  
                                 if ((!(current->global_flags & XVID_LUMIMASKING) ||  
                                          pMB->dquant == NO_CHANGE)) {  
                                         int32_t sad8 = IMV16X16 * current->quant;  
   
                                         if (sad8 < pMB->sad16)  
   
                                                 sad8 += pMB->sad8[0] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x, 2 * y, pMB->mv16.x,  
                                                                         pMB->mv16.y, current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[0],  
                                                                         &pMB->pmvs[0]);  
   
                                         if (sad8 < pMB->sad16)  
                                                 sad8 += pMB->sad8[1] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x + 1, 2 * y, pMB->mv16.x,  
                                                                         pMB->mv16.y, current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[1],  
                                                                         &pMB->pmvs[1]);  
   
                                         if (sad8 < pMB->sad16)  
                                                 sad8 += pMB->sad8[2] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x, 2 * y + 1, pMB->mv16.x,  
                                                                         pMB->mv16.y, current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[2],  
                                                                         &pMB->pmvs[2]);  
   
                                         if (sad8 < pMB->sad16)  
                                                 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,  
                                                                         current->motion_flags, current->quant,  
                                                                         current->fcode, pParam, pMBs, prevMBs,  
                                                                         &pMB->mvs[3], &pMB->pmvs[3]);  
170    
171                                          /* decide: MODE_INTER or MODE_INTER4V  static void
172                                             mpeg4:   if (sad8 < pMB->sad16 - nb/2+1) use_inter4v  CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)
173                                           */  {
174            int32_t sad;
175            const int xb = data->currentMV[1].x;
176            const int yb = data->currentMV[1].y;
177            const uint8_t *ReferenceF, *ReferenceB;
178    
179                                          if (sad8 < pMB->sad16) {          if (( xf > data->max_dx) || ( xf < data->min_dx)
180                                                  pMB->mode = MODE_INTER4V;                  || ( yf > data->max_dy) || (yf < data->min_dy)) return;
                                                 pMB->sad8[0] *= 4;  
                                                 pMB->sad8[1] *= 4;  
                                                 pMB->sad8[2] *= 4;  
                                                 pMB->sad8[3] *= 4;  
                                                 continue;  
                                         }  
181    
182            switch ( ((xf&1)<<1) + (yf&1) ) {
183                    case 0 : ReferenceF = data->Ref + xf/2 + (yf/2)*(data->iEdgedWidth); break;
184                    case 1 : ReferenceF = data->RefV + xf/2 + ((yf-1)/2)*(data->iEdgedWidth); break;
185                    case 2 : ReferenceF = data->RefH + (xf-1)/2 + (yf/2)*(data->iEdgedWidth); break;
186                    default : ReferenceF = data->RefHV + (xf-1)/2 + ((yf-1)/2)*(data->iEdgedWidth); break;
187                                  }                                  }
188    
189                          pMB->mode = MODE_INTER;          switch ( ((xb&1)<<1) + (yb&1) ) {
190                          pMB->pmvs[0] = pmv;     /* pMB->pmvs[1] = pMB->pmvs[2] = pMB->pmvs[3]  are not needed for INTER */                  case 0 : ReferenceB = data->bRef + xb/2 + (yb/2)*(data->iEdgedWidth); break;
191                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mv16;                  case 1 : ReferenceB = data->bRefV + xb/2 + ((yb-1)/2)*(data->iEdgedWidth); break;
192                          pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] =                  case 2 : ReferenceB = data->bRefH + (xb-1)/2 + (yb/2)*(data->iEdgedWidth); break;
193                                  pMB->sad16;                  default : ReferenceB = data->bRefHV + (xb-1)/2 + ((yb-1)/2)*(data->iEdgedWidth); break;
                         }  
194                          }                          }
195    
196          return 0;          sad = lambda_vec16[data->iQuant] *
197  }                          ( d_mv_bits(xf - data->predMV.x, yf - data->predMV.y, data->iFcode) +
198                              d_mv_bits(xb - data->bpredMV.x, yb - data->bpredMV.y, data->iFcode) );
199    
200            sad += sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
201    
202  #define CHECK_MV16_ZERO {\          if (sad < *(data->iMinSAD)) {
203    if ( (0 <= max_dx) && (0 >= min_dx) \                  *(data->iMinSAD) = sad;
204      && (0 <= max_dy) && (0 >= min_dy) ) \                  data->currentMV->x = xf; data->currentMV->y = yf;
205    { \                  *dir = Direction; }
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \  
     iSAD += calc_delta_16(-pmv[0].x, -pmv[0].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) - pmv[0].x, (Y) - pmv[0].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) - pmv[0].x, (Y) - pmv[0].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) - pmv[0].x, (Y) - pmv[0].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) - pmv[0].x, (Y) - pmv[0].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(-pmv[0].x, -pmv[0].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)-pmv[0].x, (Y)-pmv[0].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)-pmv[0].x, (Y)-pmv[0].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)-pmv[0].x, (Y)-pmv[0].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)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
206  }  }
207    
208  /* too slow and not fully functional at the moment */  static void
209  /*  CheckCandidateDirect(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
 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)  
210  {  {
211          const int32_t iEdgedWidth = pParam->edged_width;          int32_t sad;
212          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;          int k;
213          int32_t iSAD;          const uint8_t *ReferenceF;
214          VECTOR pred;          const uint8_t *ReferenceB;
215            VECTOR mvs, b_mvs;
216    
217            if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
218    
219          pred = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          sad = lambda_vec16[data->iQuant] * d_mv_bits(x, y, 1);
220    
221          iSAD = sad16( cur,          for (k = 0; k < 4; k++) {
222                  get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth),                  mvs.x = data->directmvF[k].x + x;
223                  iEdgedWidth, MV_MAX_ERROR);                  b_mvs.x = ((x == 0) ?
224          if (iSAD <= iQuant * 96)                          data->directmvB[k].x
225                  iSAD -= MV16_00_BIAS;                          : mvs.x - data->referencemv[k].x);
226    
227          currMV->x = 0;                  mvs.y = data->directmvF[k].y + y;
228          currMV->y = 0;                  b_mvs.y = ((y == 0) ?
229          currPMV->x = -pred.x;                          data->directmvB[k].y
230          currPMV->y = -pred.y;                          : mvs.y - data->referencemv[k].y);
231    
232          return iSAD;                  if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
233                            || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
234                            || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
235                            || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
236    
237                    switch ( ((mvs.x&1)<<1) + (mvs.y&1) ) {
238                            case 0 : ReferenceF = data->Ref + mvs.x/2 + (mvs.y/2)*(data->iEdgedWidth); break;
239                            case 1 : ReferenceF = data->RefV + mvs.x/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
240                            case 2 : ReferenceF = data->RefH + (mvs.x-1)/2 + (mvs.y/2)*(data->iEdgedWidth); break;
241                            default : ReferenceF = data->RefHV + (mvs.x-1)/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
242  }  }
 */  
243    
244  int32_t                  switch ( ((b_mvs.x&1)<<1) + (b_mvs.y&1) ) {
245  Diamond16_MainSearch(const uint8_t * const pRef,                          case 0 : ReferenceB = data->bRef + b_mvs.x/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
246                                           const uint8_t * const pRefH,                          case 1 : ReferenceB = data->bRefV + b_mvs.x/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
247                                           const uint8_t * const pRefV,                          case 2 : ReferenceB = data->bRefH + (b_mvs.x-1)/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
248                                           const uint8_t * const pRefHV,                          default : ReferenceB = data->bRefHV + (b_mvs.x-1)/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
                                          const uint8_t * const cur,  
                                          const int x,  
                                          const int y,  
                                          int32_t startx,  
                                          int32_t starty,  
                                          int32_t iMinSAD,  
                                          VECTOR * const currMV,  
                                          const VECTOR * const pmv,  
                                          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 iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = startx;  
         backupMV.y = starty;  
   
 /* 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;  
   
                         if (iDirection != 2)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                    backupMV.y, 1);  
                         if (iDirection != 1)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                    backupMV.y, 2);  
                         if (iDirection != 4)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,  
                                                                                    backupMV.y - iDiamondSize, 3);  
                         if (iDirection != 3)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,  
                                                                                    backupMV.y + iDiamondSize, 4);  
         } else {  
                 currMV->x = startx;  
                 currMV->y = starty;  
249          }          }
         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,  
                                         int32_t startx,  
                                         int32_t starty,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                         const VECTOR * const pmv,  
                                         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 = startx;  
         backupMV.y = starty;  
   
 /* 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  
 */  
250    
251          CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);                  sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
252          CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);                                                  ReferenceF + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
253          CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);                                                  ReferenceB + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
254          CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);                                                  data->iEdgedWidth);
255                    if (sad > *(data->iMinSAD)) return;
256          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;  
257    
258                          switch (iDirection) {          if (sad < *(data->iMinSAD)) {
259                          case 1:                  *(data->iMinSAD) = sad;
260                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  data->currentMV->x = x; data->currentMV->y = y;
261                                                                                     backupMV.y, 1);                  *dir = Direction; }
262                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  }
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
                         case 2:  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
263    
264                          case 3:  static void
265                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize,  CheckCandidateDirectno4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
266                                                                                   4);  {
267                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,          int32_t sad;
268                                                                                   backupMV.y - iDiamondSize, 7);          const uint8_t *ReferenceF;
269                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,          const uint8_t *ReferenceB;
270                                                                                   backupMV.y + iDiamondSize, 8);          VECTOR mvs, b_mvs;
                                 break;  
271    
272                          case 4:          if (( x > 31) || ( x < -31) || ( y > 31) || (y < -31)) return;
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 break;  
273    
274                          case 5:                  sad = lambda_vec16[data->iQuant] * d_mv_bits(x, y, 1);
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 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);  
                                 break;  
275    
276                          case 6:          mvs.x = data->directmvF[0].x + x;
277                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y,          b_mvs.x = ((x == 0) ?
278                                                                                   2);                  data->directmvB[0].x
279                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize,                  : mvs.x - data->referencemv[0].x);
                                                                                  3);  
   
                                 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, 8);  
280    
281                                  break;          mvs.y = data->directmvF[0].y + y;
282            b_mvs.y = ((y == 0) ?
283                    data->directmvB[0].y
284                    : mvs.y - data->referencemv[0].y);
285    
286                          case 7:          if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
287                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
288                                                                                     backupMV.y, 1);                  || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
289                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize,                  || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
                                                                                  4);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
290    
291                          case 8:          switch ( ((mvs.x&1)<<1) + (mvs.y&1) ) {
292                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y,                  case 0 : ReferenceF = data->Ref + mvs.x/2 + (mvs.y/2)*(data->iEdgedWidth); break;
293                                                                                   2);                  case 1 : ReferenceF = data->RefV + mvs.x/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
294                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize,                  case 2 : ReferenceF = data->RefH + (mvs.x-1)/2 + (mvs.y/2)*(data->iEdgedWidth); break;
295                                                                                   4);                  default : ReferenceF = data->RefHV + (mvs.x-1)/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
                                 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);  
                                 break;  
                         default:  
                                 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);  
                                 break;  
296                          }                          }
297          } else {  
298                  currMV->x = startx;          switch ( ((b_mvs.x&1)<<1) + (b_mvs.y&1) ) {
299                  currMV->y = starty;                  case 0 : ReferenceB = data->bRef + b_mvs.x/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
300                    case 1 : ReferenceB = data->bRefV + b_mvs.x/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
301                    case 2 : ReferenceB = data->bRefH + (b_mvs.x-1)/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
302                    default : ReferenceB = data->bRefHV + (b_mvs.x-1)/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
303          }          }
304          return iMinSAD;  
305            sad += sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
306    
307            if (sad < *(data->iMinSAD)) {
308                    *(data->iMinSAD) = sad;
309                    data->currentMV->x = x; data->currentMV->y = y;
310                    *dir = Direction; }
311  }  }
312    
313    static void
314    CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
315    {
316            int32_t sad;
317            const uint8_t * Reference;
318    
319  int32_t          if (( x > data->max_dx) || ( x < data->min_dx)
320  Full16_MainSearch(const uint8_t * const pRef,                  || ( y > data->max_dy) || (y < data->min_dy)) return;
                                   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 startx,  
                                   int32_t starty,  
                                   int32_t iMinSAD,  
                                   VECTOR * const currMV,  
                                   const VECTOR * const pmv,  
                                   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 = startx;  
         backupMV.y = starty;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV16_CANDIDATE(dx, dy);  
321    
322          return iMinSAD;          switch ( ((x&1)<<1) + (y&1) )
323            {
324                    case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
325                    case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;
326                    case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;
327                    default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
328  }  }
329    
330  int32_t          sad = sad8(data->Cur, Reference, data->iEdgedWidth);
331  AdvDiamond16_MainSearch(const uint8_t * const pRef,          sad += lambda_vec8[data->iQuant] * d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
                                                 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 startx,  
                                                 int32_t starty,  
                                                 int32_t iMinSAD,  
                                                 VECTOR * const currMV,  
                                                 const VECTOR * const pmv,  
                                                 const int32_t min_dx,  
                                                 const int32_t max_dx,  
                                                 const int32_t min_dy,  
                                                 const int32_t max_dy,  
                                                 const int32_t iEdgedWidth,  
                                                 const int32_t iDiamondSize,  
                                                 const int32_t iFcode,  
                                                 const int32_t iQuant,  
                                                 int iDirection)  
 {  
332    
333          int32_t iSAD;          if (sad < *(data->iMinSAD)) {
334                    *(data->iMinSAD) = sad;
335                    data->currentMV->x = x; data->currentMV->y = y;
336                    *dir = Direction; }
337    }
338    
339  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */  /* CHECK_CANDIATE FUNCTIONS END */
340    
341          if (iDirection) {  /* MAINSEARCH FUNCTIONS START */
                 CHECK_MV16_CANDIDATE(startx - iDiamondSize, starty);  
                 CHECK_MV16_CANDIDATE(startx + iDiamondSize, starty);  
                 CHECK_MV16_CANDIDATE(startx, starty - iDiamondSize);  
                 CHECK_MV16_CANDIDATE(startx, starty + iDiamondSize);  
         } else {  
                 int bDirection = 1 + 2 + 4 + 8;  
342    
343                  do {  static void
344                          iDirection = 0;  AdvDiamondSearch(int x, int y, const SearchData * const data, int bDirection)
345                          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(startx - iDiamondSize, starty, 1);  
346    
347                          if (bDirection & 2)  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
                                 CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);  
348    
349                          if (bDirection & 4)                  int iDirection;
                                 CHECK_MV16_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);  
350    
351                          if (bDirection & 8)                  do {
352                                  CHECK_MV16_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);                          iDirection = 0;
353                            if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
354                            if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
355                            if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
356                            if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
357    
358                          /* now we're doing diagonal checks near our candidate */                          /* now we're doing diagonal checks near our candidate */
359    
360                          if (iDirection)         //checking if anything found                          if (iDirection) {               //checking if anything found
                         {  
361                                  bDirection = iDirection;                                  bDirection = iDirection;
362                                  iDirection = 0;                                  iDirection = 0;
363                                  startx = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
364                                  starty = currMV->y;                                  if (bDirection & 3) {   //our candidate is left or right
365                                  if (bDirection & 3)     //our candidate is left or right                                          CHECK_CANDIDATE(x, y + iDiamondSize, 8);
366                                  {                                          CHECK_CANDIDATE(x, y - iDiamondSize, 4);
367                                          CHECK_MV16_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);                                  } else {                        // what remains here is up or down
368                                          CHECK_MV16_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y, 2);
369                                  } else                  // what remains here is up or down                                          CHECK_CANDIDATE(x - iDiamondSize, y, 1); }
                                 {  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);  
                                 }  
370    
371                                  if (iDirection) {                                  if (iDirection) {
372                                          bDirection += iDirection;                                          bDirection += iDirection;
373                                          startx = currMV->x;                                          x = data->currentMV->x; y = data->currentMV->y; }
374                                          starty = currMV->y;                          } else {                                //about to quit, eh? not so fast....
                                 }  
                         } else                          //about to quit, eh? not so fast....  
                         {  
375                                  switch (bDirection) {                                  switch (bDirection) {
376                                  case 2:                                  case 2:
377                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
378                                                                                           starty - iDiamondSize, 2 + 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
379                                          break;                                          break;
380                                  case 1:                                  case 1:
381                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
382                                                                                           starty - iDiamondSize, 1 + 4);                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty + iDiamondSize, 1 + 8);  
383                                          break;                                          break;
384                                  case 2 + 4:                                  case 2 + 4:
385                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
386                                                                                           starty - iDiamondSize, 1 + 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
387                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                          starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
388                                          break;                                          break;
389                                  case 4:                                  case 4:
390                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
391                                                                                           starty - iDiamondSize, 2 + 4);                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty - iDiamondSize, 1 + 4);  
392                                          break;                                          break;
393                                  case 8:                                  case 8:
394                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
395                                                                                           starty + iDiamondSize, 2 + 8);                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty + iDiamondSize, 1 + 8);  
396                                          break;                                          break;
397                                  case 1 + 4:                                  case 1 + 4:
398                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
399                                                                                           starty + iDiamondSize, 1 + 8);                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
400                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
                                                                                          starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty - iDiamondSize, 2 + 4);  
401                                          break;                                          break;
402                                  case 2 + 8:                                  case 2 + 8:
403                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
404                                                                                           starty - iDiamondSize, 1 + 4);                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
405                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                          starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
406                                          break;                                          break;
407                                  case 1 + 8:                                  case 1 + 8:
408                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
409                                                                                           starty - iDiamondSize, 2 + 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
410                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                                                                          starty + iDiamondSize, 2 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty + iDiamondSize, 1 + 8);  
411                                          break;                                          break;
412                                  default:                //1+2+4+8 == we didn't find anything at all                                  default:                //1+2+4+8 == we didn't find anything at all
413                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
414                                                                                           starty - iDiamondSize, 1 + 4);                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
415                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
416                                                                                           starty + iDiamondSize, 1 + 8);                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
417                                          break;                                          break;
418                                  }                                  }
419                                  if (!iDirection)                                  if (!iDirection) break;         //ok, the end. really
                                         break;          //ok, the end. really  
                                 else {  
420                                          bDirection = iDirection;                                          bDirection = iDirection;
421                                          startx = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
                                         starty = currMV->y;  
                                 }  
422                          }                          }
423                  }                  }
424                  while (1);                              //forever                  while (1);                              //forever
425          }          }
         return iMinSAD;  
 }  
426    
427  int32_t  static void
428  AdvDiamond8_MainSearch(const uint8_t * const pRef,  SquareSearch(int x, int y, const SearchData * const data, int bDirection)
                                            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 startx,  
                                            int32_t starty,  
                                            int32_t iMinSAD,  
                                            VECTOR * const currMV,  
                                            const VECTOR * const pmv,  
                                            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)  
429  {  {
430            int iDirection;
431    
432            do {
433                    iDirection = 0;
434                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);
435                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);
436                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);
437                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128);
438                    if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64);
439                    if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128);
440                    if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128);
441                    if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128);
442    
443                    bDirection = iDirection;
444                    x = data->currentMV->x; y = data->currentMV->y;
445            } while (iDirection);
446    }
447    
448          int32_t iSAD;  static void
449    DiamondSearch(int x, int y, const SearchData * const data, int bDirection)
450    {
451    
452  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
453    
454          if (iDirection) {                  int iDirection;
                 CHECK_MV8_CANDIDATE(startx - iDiamondSize, starty);  
                 CHECK_MV8_CANDIDATE(startx + iDiamondSize, starty);  
                 CHECK_MV8_CANDIDATE(startx, starty - iDiamondSize);  
                 CHECK_MV8_CANDIDATE(startx, starty + iDiamondSize);  
         } else {  
                 int bDirection = 1 + 2 + 4 + 8;  
455    
456                  do {                  do {
457                          iDirection = 0;                          iDirection = 0;
458                          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)                          if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
459                                  CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);                          if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
460                            if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
461                          if (bDirection & 2)                          if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
                                 CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);  
   
                         if (bDirection & 4)  
                                 CHECK_MV8_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);  
   
                         if (bDirection & 8)  
                                 CHECK_MV8_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);  
462    
463                          /* now we're doing diagonal checks near our candidate */                          /* now we're doing diagonal checks near our candidate */
464    
465                          if (iDirection)         //checking if anything found                          if (iDirection) {               //checking if anything found
                         {  
466                                  bDirection = iDirection;                                  bDirection = iDirection;
467                                  iDirection = 0;                                  iDirection = 0;
468                                  startx = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
469                                  starty = currMV->y;                                  if (bDirection & 3) {   //our candidate is left or right
470                                  if (bDirection & 3)     //our candidate is left or right                                          CHECK_CANDIDATE(x, y + iDiamondSize, 8);
471                                  {                                          CHECK_CANDIDATE(x, y - iDiamondSize, 4);
472                                          CHECK_MV8_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);                                  } else {                        // what remains here is up or down
473                                          CHECK_MV8_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y, 2);
474                                  } else                  // what remains here is up or down                                          CHECK_CANDIDATE(x - iDiamondSize, y, 1); }
                                 {  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);  
                                 }  
475    
                                 if (iDirection) {  
476                                          bDirection += iDirection;                                          bDirection += iDirection;
477                                          startx = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
                                         starty = currMV->y;  
                                 }  
                         } else                          //about to quit, eh? not so fast....  
                         {  
                                 switch (bDirection) {  
                                 case 2:  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1:  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 2 + 4:  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 4:  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         break;  
                                 case 8:  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 1 + 4:  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         break;  
                                 case 2 + 8:  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1 + 8:  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         break;  
                                 default:                //1+2+4+8 == we didn't find anything at all  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         break;  
                                 }  
                                 if (!(iDirection))  
                                         break;          //ok, the end. really  
                                 else {  
                                         bDirection = iDirection;  
                                         startx = currMV->x;  
                                         starty = currMV->y;  
                                 }  
478                          }                          }
479                  }                  }
480                  while (1);                              //forever                  while (iDirection);
         }  
         return iMinSAD;  
481  }  }
482    
483    /* MAINSEARCH FUNCTIONS END */
484    
485  int32_t  /* HALFPELREFINE COULD BE A MAINSEARCH FUNCTION, BUT THERE IS NO NEED FOR IT */
 Full8_MainSearch(const uint8_t * const pRef,  
                                  const uint8_t * const pRefH,  
                                  const uint8_t * const pRefV,  
                                  const uint8_t * const pRefHV,  
                                  const uint8_t * const cur,  
                                  const int x,  
                                  const int y,  
                                  int32_t startx,  
                                  int32_t starty,  
                                  int32_t iMinSAD,  
                                  VECTOR * const currMV,  
                                  const VECTOR * const pmv,  
                                  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 = startx;  
         backupMV.y = starty;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV8_CANDIDATE(dx, dy);  
486    
487          return iMinSAD;  static void
488  }  HalfpelRefine(const SearchData * const data)
   
   
   
 int32_t  
 Halfpel16_Refine(const uint8_t * const pRef,  
                                  const uint8_t * const pRefH,  
                                  const uint8_t * const pRefV,  
                                  const uint8_t * const pRefHV,  
                                  const uint8_t * const cur,  
                                  const int x,  
                                  const int y,  
                                  VECTOR * const currMV,  
                                  int32_t iMinSAD,  
                                  const VECTOR * const pmv,  
                                  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)  
489  {  {
490  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */
491    
492          int32_t iSAD;          VECTOR backupMV = *(data->currentMV);
493          VECTOR backupMV = *currMV;          int iDirection; //not needed
494    
495          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y - 1);          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y - 1, 0);
496          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y - 1);          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y - 1, 0);
497          CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y - 1);          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y + 1, 0);
498          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y);          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y + 1, 0);
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y + 1);  
         CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y + 1);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y + 1);  
499    
500          return iMinSAD;          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y, 0);
501  }          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y, 0);
   
 #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)  
502    
503            CHECK_CANDIDATE(backupMV.x, backupMV.y + 1, 0);
504  int32_t          CHECK_CANDIDATE(backupMV.x, backupMV.y - 1, 0);
 PMVfastSearch16(const uint8_t * const pRef,  
                                 const uint8_t * const pRefH,  
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const IMAGE * const pCur,  
                                 const int x,  
                                 const int y,  
                                 const 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)  
 {  
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
   
         const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;  
   
         int32_t iDiamondSize;  
   
         int32_t min_dx;  
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
   
         int32_t iFound;  
   
         VECTOR newMV;  
         VECTOR backupMV;                        /* just for PMVFAST */  
   
         VECTOR pmv[4];  
         int32_t psad[4];  
   
         MainSearch16FuncPtr MainSearchPtr;  
   
         const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;  
   
         int32_t threshA, threshB;  
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD;  
   
 /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
   
 /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  
   
         if (!(MotionFlags & PMV_HALFPEL16)) {  
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
505          }          }
506    
507          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  static __inline int
508          bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  SkipDecisionP(const IMAGE * current, const IMAGE * reference,
509          // bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);                                                          const int x, const int y,
510                                                            const uint32_t iEdgedWidth, const uint32_t iQuant)
 /*      fprintf(stderr,"pmv: %d %d / %d --- %d %d   %d %d   %d %d - %d %d %d\n",  
                 pmv[0].x,pmv[0].y,psad[0],  
                 pmv[1].x,pmv[1].y,pmv[2].x,pmv[2].y,pmv[3].x,pmv[3].y,  
                 psad[1],psad[2],psad[3]);  
 */  
         if ((x == 0) && (y == 0)) {  
                 threshA = 512;  
                 threshB = 1024;  
         } else {  
                 threshA = psad[0];  
                 threshB = threshA + 256;  
                 if (threshA < 512)  
                         threshA = 512;  
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
         }  
   
         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.  
 */  
511    
512          *currMV = pmv[0];                       /* current best := prediction */  {
513          if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */  /*      keep repeating checks for all b-frames before this P frame,
514                  currMV->x = EVEN(currMV->x);          to make sure that SKIP is possible (todo)
515                  currMV->y = EVEN(currMV->y);          how: if skip is not possible set sad00 to a very high value */
516          }  
517            uint32_t sadC = sad8(current->u + x*8 + y*(iEdgedWidth/2)*8,
518                                            reference->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2);
519            if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
520            sadC += sad8(current->v + x*8 + y*(iEdgedWidth/2)*8,
521                                            reference->v + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2);
522            if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
523    
524          if (currMV->x > max_dx) {          return 1;
                 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;  
525          }          }
526    
527          iMinSAD =  static __inline void
528                  sad16(cur,  SkipMacroblockP(MACROBLOCK *pMB, const int32_t sad)
                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - pmv[0].x, currMV->y - pmv[0].y,  
                                           (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->mvs[0])) &&  
                  ((uint32_t) iMinSAD < prevMB->sad16))) {  
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
529                  {                  {
530                          if (!MVzero(*currMV)) {          pMB->mode = MODE_NOT_CODED;
531                                  iMinSAD += MV16_00_BIAS;          pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = 0;
532                                  CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures          pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = 0;
533                                  iMinSAD -= MV16_00_BIAS;          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
534                          }                          }
                 }  
   
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_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  
 */  
   
         if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[0])))  
                 iFound = 2;  
   
 /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.  
    Otherwise select large Diamond Search.  
 */  
   
         if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))  
                 iDiamondSize = 1;               // halfpel!  
         else  
                 iDiamondSize = 2;               // halfpel!  
535    
536          if (!(MotionFlags & PMV_HALFPELDIAMOND16))  bool
537                  iDiamondSize *= 2;  MotionEstimation(MBParam * const pParam,
538                                     FRAMEINFO * const current,
539  /*                                   FRAMEINFO * const reference,
540     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.                                   const IMAGE * const pRefH,
541     Also calculate (0,0) but do not subtract offset.                                   const IMAGE * const pRefV,
542     Let MinSAD be the smallest SAD up to this point.                                   const IMAGE * const pRefHV,
543     If MV is (0,0) subtract offset.                                   const uint32_t iLimit)
544  */  {
545            MACROBLOCK *const pMBs = current->mbs;
546  // (0,0) is always possible          const IMAGE *const pCurrent = &current->image;
547            const IMAGE *const pRef = &reference->image;
548    
549          if (!MVzero(pmv[0]))          const VECTOR zeroMV = { 0, 0 };
                 CHECK_MV16_ZERO;  
550    
551  // previous frame MV is always possible          uint32_t x, y;
552            uint32_t iIntra = 0;
553            int32_t InterBias;
554    
555            // some pre-initialized thingies for SearchP
556            int32_t temp[5];
557            VECTOR currentMV[5];
558            int32_t iMinSAD[5];
559            SearchData Data;
560            Data.iEdgedWidth = pParam->edged_width;
561            Data.currentMV = currentMV;
562            Data.iMinSAD = iMinSAD;
563            Data.temp = temp;
564            Data.iFcode = current->fcode;
565    
566            if (sadInit) (*sadInit) ();
567    
568            for (y = 0; y < pParam->mb_height; y++) {
569                    for (x = 0; x < pParam->mb_width; x++)  {
570    
571                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
572                            int32_t sad00 =  pMB->sad16
573                                    = sad16v(pCurrent->y + (x + y * pParam->edged_width) * 16,
574                                                            pRef->y + (x + y * pParam->edged_width) * 16,
575                                                            pParam->edged_width, pMB->sad8 );
576    
577                            if (!(current->global_flags & XVID_LUMIMASKING)) {
578                                    pMB->dquant = NO_CHANGE;
579                                    pMB->quant = current->quant; }
580    
581    //initial skip decision
582    
583                            if ((pMB->dquant == NO_CHANGE) && (sad00 <= MAX_SAD00_FOR_SKIP * pMB->quant)
584                                    && (SkipDecisionP(pCurrent, pRef, x, y, pParam->edged_width, pMB->quant)) ) {
585                                    if (pMB->sad16 < pMB->quant * INITIAL_SKIP_THRESH) {
586                                                    SkipMacroblockP(pMB, sad00);
587                                                    continue;
588                                    }
589                            } else sad00 = 256*4096; // skip not allowed - for final skip decision
590    
591          if (!MVzero(prevMB->mvs[0]))                          SearchP(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
592                  if (!MVequal(prevMB->mvs[0], pmv[0]))                                                  y, current->motion_flags, pMB->quant,
593                          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);                                                  &Data, pParam, pMBs, reference->mbs,
594                                                    current->global_flags & XVID_INTER4V, pMB);
595    
596    /* final skip decision, a.k.a. "the vector you found, really that good?" */
597                            if (sad00 < pMB->quant * MAX_SAD00_FOR_SKIP)
598                                    if ((100*pMB->sad16)/(sad00+1) > FINAL_SKIP_THRESH)
599                                    { SkipMacroblockP(pMB, sad00); continue; }
600    
601  // left neighbour, if allowed  /* finally, intra decision */
602    
603          if (!MVzero(pmv[1]))                          InterBias = MV16_INTER_BIAS;
604                  if (!MVequal(pmv[1], prevMB->mvs[0]))                          if (pMB->quant > 8)  InterBias += 50 * (pMB->quant - 8); // to make high quants work
605                          if (!MVequal(pmv[1], pmv[0])) {                          if (y != 0)
606                                  if (!(MotionFlags & PMV_HALFPEL16)) {                                  if ((pMB - pParam->mb_width)->mode == MODE_INTER ) InterBias -= 50;
607                                          pmv[1].x = EVEN(pmv[1].x);                          if (x != 0)
608                                          pmv[1].y = EVEN(pmv[1].y);                                  if ((pMB - 1)->mode == MODE_INTER ) InterBias -= 50;
                                 }  
609    
610                                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);                          if (InterBias < pMB->sad16)  {
611                          }                                  const int32_t deviation =
612  // top neighbour, if allowed                                          dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,
613          if (!MVzero(pmv[2]))                                                    pParam->edged_width);
                 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);  
614    
615  // top right neighbour, if allowed                                  if (deviation < (pMB->sad16 - InterBias)) {
616                                          if (!MVzero(pmv[3]))                                          if (++iIntra >= iLimit) return 1;
617                                                  if (!MVequal(pmv[3], prevMB->mvs[0]))                                          pMB->mode = MODE_INTRA;
618                                                          if (!MVequal(pmv[3], pmv[0]))                                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =
619                                                                  if (!MVequal(pmv[3], pmv[1]))                                                          pMB->mvs[3] = zeroMV;
620                                                                          if (!MVequal(pmv[3], pmv[2])) {                                          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =
621                                                                                  if (!(MotionFlags & PMV_HALFPEL16)) {                                                  pMB->sad8[3] = 0;
                                                                                         pmv[3].x = EVEN(pmv[3].x);  
                                                                                         pmv[3].y = EVEN(pmv[3].y);  
622                                                                                  }                                                                                  }
                                                                                 CHECK_MV16_CANDIDATE(pmv[3].x,  
                                                                                                                          pmv[3].y);  
623                                                                          }                                                                          }
624                                  }                                  }
   
         if ((MVzero(*currMV)) &&  
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV16_00_BIAS;  
   
   
 /* Step 6: If MinSAD <= thresa goto Step 10.  
    If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
 */  
   
         if ((iMinSAD <= threshA) ||  
                 (MVequal(*currMV, prevMB->mvs[0]) &&  
                  ((uint32_t) iMinSAD < prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
625          }          }
626            return 0;
   
 /************ (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.  
 */  
   
         if (MotionFlags & PMV_USESQUARES16)  
                 MainSearchPtr = Square16_MainSearch;  
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
   
         backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  
   
   
 //      fprintf(stderr,"Entering Diamond %d %d (%d):\n",x,y,iMinSAD);  
   
 /* 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, pmv, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
627          }          }
628    
         if (MotionFlags & PMV_EXTSEARCH16) {  
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
629    
630                  if (!(MVequal(pmv[0], backupMV))) {  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, pmv,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
                 }  
631    
632                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {  static __inline int
633                          iSAD =  make_mask(const VECTOR * const pmv, const int i)
634                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  {
635                                                                    iMinSAD, &newMV, pmv, min_dx, max_dx, min_dy,          int mask = 255, j;
636                                                                    max_dy, iEdgedWidth, iDiamondSize, iFcode,          for (j = 0; j < i; j++) {
637                                                                    iQuant, iFound);                  if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already
638                    if (pmv[i].x == pmv[j].x) {
639                          if (iSAD < iMinSAD) {                          if (pmv[i].y == pmv[j].y + iDiamondSize) { mask &= ~4; continue; }
640                                  *currMV = newMV;                          if (pmv[i].y == pmv[j].y - iDiamondSize) { mask &= ~8; continue; }
641                                  iMinSAD = iSAD;                  } else
642                          }                          if (pmv[i].y == pmv[j].y) {
643                                    if (pmv[i].x == pmv[j].x + iDiamondSize) { mask &= ~1; continue; }
644                                    if (pmv[i].x == pmv[j].x - iDiamondSize) { mask &= ~2; continue; }
645                  }                  }
646          }          }
647            return mask;
 /*  
    Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  
 */  
   
   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, pmv, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
   
 /*fprintf(stderr,"Chosen for %d %d: %d %d - %d %d\n",x,y,currMV->x,currMV->y,pmv[0].x,pmv[0].y);  
 */  
   PMVfast16_Terminate_without_Refine:  
         currPMV->x = currMV->x - pmv[0].x;  
         currPMV->y = currMV->y - pmv[0].y;  
         return iMinSAD;  
648  }  }
649    
650    static __inline void
651    PreparePredictionsP(VECTOR * const pmv, int x, int y, const int iWcount,
652                            const int iHcount, const MACROBLOCK * const prevMB)
653    {
654    
655    //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself
656    
657            if ( (y != 0) && (x != (iWcount-1)) ) {         // [5] top-right neighbour
658                    pmv[5].x = EVEN(pmv[3].x);
659                    pmv[5].y = EVEN(pmv[3].y);
660            } else pmv[5].x = pmv[5].y = 0;
661    
662            if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }// pmv[3] is left neighbour
663            else pmv[3].x = pmv[3].y = 0;
664    
665            if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }// [4] top neighbour
666        else pmv[4].x = pmv[4].y = 0;
667    
668  int32_t          // [1] median prediction
669  Diamond8_MainSearch(const uint8_t * const pRef,          pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
                                         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 startx,  
                                         int32_t starty,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                         const VECTOR * const pmv,  
                                         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 iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = startx;  
         backupMV.y = starty;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
   
         if (iDirection)  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;     // since iDirection!=0, this is well defined!  
   
                         if (iDirection != 2)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                   backupMV.y, 1);  
                         if (iDirection != 1)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                   backupMV.y, 2);  
                         if (iDirection != 4)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y - iDiamondSize, 3);  
                         if (iDirection != 3)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y + iDiamondSize, 4);  
         } else {  
                 currMV->x = startx;  
                 currMV->y = starty;  
         }  
         return iMinSAD;  
 }  
   
 int32_t  
 Halfpel8_Refine(const uint8_t * const pRef,  
                                 const uint8_t * const pRefH,  
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const uint8_t * const cur,  
                                 const int x,  
                                 const int y,  
                                 VECTOR * const currMV,  
                                 int32_t iMinSAD,  
                                 const VECTOR * const pmv,  
                                 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);  
670    
671          return iMinSAD;          pmv[0].x = pmv[0].y = 0; // [0] is zero; not used in the loop (checked before) but needed here for make_mask
 }  
672    
673            pmv[2].x = EVEN(prevMB->mvs[0].x); // [2] is last frame
674            pmv[2].y = EVEN(prevMB->mvs[0].y);
675    
676  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)          if ((x != iWcount-1) && (y != iHcount-1)) {
677                    pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); //[6] right-down neighbour in last frame
678                    pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
679            } else pmv[6].x = pmv[6].y = 0;
680    }
681    
682  int32_t  static void
683  PMVfastSearch8(const uint8_t * const pRef,  SearchP(const uint8_t * const pRef,
684                             const uint8_t * const pRefH,                             const uint8_t * const pRefH,
685                             const uint8_t * const pRefV,                             const uint8_t * const pRefV,
686                             const uint8_t * const pRefHV,                             const uint8_t * const pRefHV,
687                             const IMAGE * const pCur,                             const IMAGE * const pCur,
688                             const int x,                             const int x,
689                             const int y,                             const int y,
                            const int start_x,  
                            const int start_y,  
690                             const uint32_t MotionFlags,                             const uint32_t MotionFlags,
691                             const uint32_t iQuant,                             const uint32_t iQuant,
692                             const uint32_t iFcode,                  SearchData * const Data,
693                             const MBParam * const pParam,                             const MBParam * const pParam,
694                             const MACROBLOCK * const pMBs,                             const MACROBLOCK * const pMBs,
695                             const MACROBLOCK * const prevMBs,                             const MACROBLOCK * const prevMBs,
696                             VECTOR * const currMV,                  int inter4v,
697                             VECTOR * const currPMV)                  MACROBLOCK * const pMB)
698  {  {
         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;  
699    
700          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;          int i, iDirection = 255, mask, threshA;
701            VECTOR pmv[7];
702    
703          int32_t iDiamondSize;          get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);  //has to be changed to get_pmv(2)()
704            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
705                                    pParam->width, pParam->height, Data->iFcode);
706    
707          int32_t min_dx;          Data->predMV = pmv[0];
708          int32_t max_dx;          Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16;
709          int32_t min_dy;          Data->Ref = pRef + (x + Data->iEdgedWidth*y)*16;
710          int32_t max_dy;          Data->RefH = pRefH + (x + Data->iEdgedWidth*y) * 16;
711            Data->RefV = pRefV + (x + Data->iEdgedWidth*y) * 16;
712            Data->RefHV = pRefHV + (x + Data->iEdgedWidth*y) * 16;
713    
714          VECTOR pmv[4];          Data->iQuant = iQuant;
         int32_t psad[4];  
         VECTOR newMV;  
         VECTOR backupMV;  
         VECTOR startMV;  
715    
716  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          if (!(MotionFlags & PMV_HALFPEL16)) {
717          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;                  Data->min_dx = EVEN(Data->min_dx);
718                    Data->max_dx = EVEN(Data->max_dx);
719                    Data->min_dy = EVEN(Data->min_dy);
720                    Data->max_dy = EVEN(Data->max_dy); }
721    
722           int32_t threshA, threshB;          for(i = 0;  i < 5; i++) Data->iMinSAD[i] = 256*4096;
         int32_t iFound, bPredEq;  
         int32_t iMinSAD, iSAD;  
723    
724          int32_t iSubBlock = (y & 1) + (y & 1) + (x & 1);          if (inter4v) CheckCandidate = CheckCandidate16;
725            else CheckCandidate = CheckCandidate16no4v;
726    
727          MainSearch8FuncPtr MainSearchPtr;          (*CheckCandidate)(Data->predMV.x, Data->predMV.y, 0, &iDirection, Data);
728    
729          /* Init variables */          for(i = 0;  i < 5; i++) Data->currentMV[i].x = Data->currentMV[i].y = 0;
         startMV.x = start_x;  
         startMV.y = start_y;  
730    
731          /* Get maximum range */          i = d_mv_bits(Data->predMV.x, Data->predMV.y, Data->iFcode);
732          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,          Data->iMinSAD[0] = pMB->sad16 + lambda_vec16[iQuant] * i;
733                            iFcode);          Data->iMinSAD[1] = pMB->sad8[0] + lambda_vec8[iQuant] * i;
734            Data->iMinSAD[2] = pMB->sad8[1];
735            Data->iMinSAD[3] = pMB->sad8[2];
736            Data->iMinSAD[4] = pMB->sad8[3];
737    
738          if (!(MotionFlags & PMV_HALFPELDIAMOND8)) {          if (pMB->dquant != NO_CHANGE) inter4v = 0;
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
         }  
739    
740          /* because we might use IF (dx>max_dx) THEN dx=max_dx; */          if ((x == 0) && (y == 0)) threshA = 512;
741          bPredEq = get_pmvdata(pMBs, (x >> 1), (y >> 1), iWcount, iSubBlock, pmv, psad);          else {
742          // bPredEq = get_pmvdata2(pMBs, iWcount, 0, (x >> 1), (y >> 1), iSubBlock, pmv, psad);                  threshA = Data->temp[0] + 20;
743                    if (threshA < 512) threshA = 512;
744                    if (threshA > 1024) threshA = 1024; }
745    
746          if ((x == 0) && (y == 0)) {          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
747                  threshA = 512 / 4;                                          prevMBs + x + y * pParam->mb_width);
                 threshB = 1024 / 4;  
748    
749          } else {  /* main loop. checking all predictions */
                 threshA = psad[0] / 4;  /* good estimate */  
                 threshB = threshA + 256 / 4;  
                 if (threshA < 512 / 4)  
                         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.  
 */  
750    
751            for (i = 1; i < 7; i++) {
752                    if (!(mask = make_mask(pmv, i)) ) continue;
753                    CheckCandidate16(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
754                    if (Data->iMinSAD[0] <= threshA) break;
755            }
756    
757  // Prepare for main loop          if ((Data->iMinSAD[0] <= threshA) ||
758                            (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
759                            (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16))) {
760                    inter4v = 0;
761            } else {
762    
763  //  if (MotionFlags & PMV_USESQUARES8)                  MainSearchFunc * MainSearchPtr;
764  //      MainSearchPtr = Square8_MainSearch;                  if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
765  //  else                  else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
766                            else MainSearchPtr = DiamondSearch;
767          if (MotionFlags & PMV_ADVANCEDDIAMOND8)  
768                  MainSearchPtr = AdvDiamond8_MainSearch;                  (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
769          else  
770                  MainSearchPtr = Diamond8_MainSearch;  /* extended search, diamond starting in 0,0 and in prediction.
771            note that this search is/might be done in halfpel positions,
772            which makes it more different than the diamond above */
         *currMV = startMV;  
   
         iMinSAD =  
                 sad8(cur,  
                          get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  
                                                 iEdgedWidth), iEdgedWidth);  
         iMinSAD +=  
                 calc_delta_8(currMV->x - pmv[0].x, currMV->y - pmv[0].y,  
                                          (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256 / 4) || ((MVequal(*currMV, prevMB->mvs[iSubBlock]))  
                                                                 && ((uint32_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  
 */  
773    
774          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[iSubBlock])))                  if (MotionFlags & PMV_EXTSEARCH16) {
775                  iFound = 2;                          int32_t bSAD;
776                            VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
777                            if (!(MotionFlags & PMV_HALFPELREFINE16)) // who's gonna use extsearch and no halfpel?
778                                    startMV.x = EVEN(startMV.x); startMV.y = EVEN(startMV.y);
779                            if (!(MVequal(startMV, backupMV))) {
780                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
781    
782                                    CheckCandidate16(startMV.x, startMV.y, 255, &iDirection, Data);
783                                    (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
784                                    if (bSAD < Data->iMinSAD[0]) {
785                                            Data->currentMV[0] = backupMV;
786                                            Data->iMinSAD[0] = bSAD; }
787                            }
788    
789                            backupMV = Data->currentMV[0];
790                            if (MotionFlags & PMV_HALFPELREFINE16) startMV.x = startMV.y = 1;
791                            else startMV.x = startMV.y = 0;
792                            if (!(MVequal(startMV, backupMV))) {
793                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
794    
795                                    CheckCandidate16(startMV.x, startMV.y, 255, &iDirection, Data);
796                                    (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
797                                    if (bSAD < Data->iMinSAD[0]) {
798                                            Data->currentMV[0] = backupMV;
799                                            Data->iMinSAD[0] = bSAD; }
800                            }
801                    }
802            }
803    
804  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(Data);
805     Otherwise select large Diamond Search.  
806  */          if (inter4v) {
807                    SearchData Data8;
808                    Data8.iFcode = Data->iFcode;
809                    Data8.iQuant = Data->iQuant;
810                    Data8.iEdgedWidth = Data->iEdgedWidth;
811                    Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
812                    Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
813                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
814                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
815            }
816    
817            if (!(inter4v) ||
818                    (Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
819                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {
820    // INTER MODE
821                    pMB->mode = MODE_INTER;
822                    pMB->mvs[0] = pMB->mvs[1]
823                            = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
824    
825          if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
826                  iDiamondSize = 1;               // 1 halfpel!                          pMB->sad8[2] = pMB->sad8[3] =  Data->iMinSAD[0];
         else  
                 iDiamondSize = 2;               // 2 halfpel = 1 full pixel!  
827    
828          if (!(MotionFlags & PMV_HALFPELDIAMOND8))                  pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
829                  iDiamondSize *= 2;                  pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
830            } else {
831    // INTER4V MODE; all other things are already set in Search8
832                    pMB->mode = MODE_INTER4V;
833                    pMB->sad16 = Data->iMinSAD[1] + Data->iMinSAD[2] +
834                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * iQuant;
835            }
836    
837    }
838    
839  /*  static void
840     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  Search8(const SearchData * const OldData,
841     Also calculate (0,0) but do not subtract offset.                  const int x, const int y,
842     Let MinSAD be the smallest SAD up to this point.                  const uint32_t MotionFlags,
843     If MV is (0,0) subtract offset.                  const MBParam * const pParam,
844  */                  MACROBLOCK * const pMB,
845                    const MACROBLOCK * const pMBs,
846                    const int block,
847                    SearchData * const Data)
848    {
849            Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2 , y/2, block);
850            Data->iMinSAD = OldData->iMinSAD + 1 + block;
851            Data->currentMV = OldData->currentMV + 1 + block;
852    
853  // the median prediction might be even better than mv16          if (block != 0)
854                    *(Data->iMinSAD) += lambda_vec8[Data->iQuant] *
855                                                                    d_mv_bits(      Data->currentMV->x - Data->predMV.x,
856                                                                                            Data->currentMV->y - Data->predMV.y,
857                                                                                            Data->iFcode);
858    
859          if (!MVequal(pmv[0], startMV))          if (MotionFlags & (PMV_EXTSEARCH8|PMV_HALFPELREFINE8)) {
                 CHECK_MV8_CANDIDATE(pmv[0].x, pmv[0].y);  
860    
861  // (0,0) if needed                  Data->Ref = OldData->Ref + 8 * ((block&1) + pParam->edged_width*(block>>1));
862          if (!MVzero(pmv[0]))                  Data->RefH = OldData->RefH + 8 * ((block&1) + pParam->edged_width*(block>>1));
863                  if (!MVzero(startMV))                  Data->RefV = OldData->RefV + 8 * ((block&1) + pParam->edged_width*(block>>1));
864                          CHECK_MV8_ZERO;                  Data->RefHV = OldData->RefHV + 8 * ((block&1) + pParam->edged_width*(block>>1));
   
 // 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]) &&  
                  ((uint32_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;  
865    
866                    Data->Cur = OldData->Cur + 8 * ((block&1) + pParam->edged_width*(block>>1));
867    
868  /* Step 6: If MinSAD <= thresa goto Step 10.                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
869     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.                                  pParam->width, pParam->height, OldData->iFcode);
 */  
870    
871          if ((iMinSAD <= threshA) ||                  CheckCandidate = CheckCandidate8;
                 (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&  
                  ((uint32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
872    
873  /************ (Diamond Search)  **************/                  if (MotionFlags & PMV_EXTSEARCH8) {
 /*  
    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.  
 */  
874    
875          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                          MainSearchFunc *MainSearchPtr;
876                            if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
877                                    else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
878                                            else MainSearchPtr = DiamondSearch;
879    
880  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);    }
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  
                                                   currMV->y, iMinSAD, &newMV, pmv, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
881    
882          if (MotionFlags & PMV_EXTSEARCH8) {                  if (MotionFlags & PMV_HALFPELREFINE8) HalfpelRefine(Data);
883  /* extended: search (up to) two more times: orignal prediction and (0,0) */          }
884    
885                  if (!(MVequal(pmv[0], backupMV))) {          pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
886                          iSAD =          pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
887                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,          pMB->mvs[block] = *(Data->currentMV);
888                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, pmv,          pMB->sad8[block] =  4 * (*Data->iMinSAD);
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
889    
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
890                  }                  }
891    
892                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {  /* B-frames code starts here */
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, pmv, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
893    
894                          if (iSAD < iMinSAD) {  static __inline VECTOR
895                                  *currMV = newMV;  ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
896                                  iMinSAD = iSAD;  {
897                          }  /* the stupidiest function ever */
898                  }          if (mode == MODE_FORWARD) return pMB->mvs[0];
899            else return pMB->b_mvs[0];
900          }          }
901    
902  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.  static void __inline
903     By performing an optional local half-pixel search, we can refine this result even further.  PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
904  */                                                          const uint32_t iWcount,
905                                                            const MACROBLOCK * const pMB,
906                                                            const uint32_t mode_curr)
907    {
908    
909    PMVfast8_Terminate_with_Refine:          // [0] is prediction
910          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step          pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
                 iMinSAD =  
                         Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                         iMinSAD, pmv, min_dx, max_dx, min_dy, max_dy,  
                                                         iFcode, iQuant, iEdgedWidth);  
911    
912            pmv[1].x = pmv[1].y = 0; // [1] is zero
913    
914    PMVfast8_Terminate_without_Refine:          pmv[2] = ChoosePred(pMB, mode_curr);
915          currPMV->x = currMV->x - pmv[0].x;          pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
         currPMV->y = currMV->y - pmv[0].y;  
916    
917          return iMinSAD;          if ((y != 0)&&(x != (int)(iWcount+1))) {                        // [3] top-right neighbour
918                    pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
919                    pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
920            } else pmv[3].x = pmv[3].y = 0;
921    
922            if (y != 0) {
923                    pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
924                    pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
925            } else pmv[4].x = pmv[4].y = 0;
926    
927            if (x != 0) {
928                    pmv[5] = ChoosePred(pMB-1, mode_curr);
929                    pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
930            } else pmv[5].x = pmv[5].y = 0;
931    
932            if ((x != 0)&&(y != 0)) {
933                    pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
934                    pmv[6].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
935            } else pmv[6].x = pmv[6].y = 0;
936    
937    // more?
938  }  }
939    
940  int32_t  
941  EPZSSearch16(const uint8_t * const pRef,  /* search backward or forward, for b-frames */
942    static void
943    SearchBF(       const uint8_t * const pRef,
944                           const uint8_t * const pRefH,                           const uint8_t * const pRefH,
945                           const uint8_t * const pRefV,                           const uint8_t * const pRefV,
946                           const uint8_t * const pRefHV,                           const uint8_t * const pRefHV,
947                           const IMAGE * const pCur,                           const IMAGE * const pCur,
948                           const int x,                          const int x, const int y,
                          const int y,  
949                           const uint32_t MotionFlags,                           const uint32_t MotionFlags,
950                           const uint32_t iQuant,                           const uint32_t iQuant,
951                           const uint32_t iFcode,                           const uint32_t iFcode,
952                           const MBParam * const pParam,                           const MBParam * const pParam,
953                           const MACROBLOCK * const pMBs,                          MACROBLOCK * const pMB,
954                           const MACROBLOCK * const prevMBs,                          const VECTOR * const predMV,
955                           VECTOR * const currMV,                          int32_t * const best_sad,
956                           VECTOR * const currPMV)                          const int32_t mode_current)
957  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const uint32_t iHcount = pParam->mb_height;  
958    
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
959          const int32_t iEdgedWidth = pParam->edged_width;          const int32_t iEdgedWidth = pParam->edged_width;
960    
961          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          int i, iDirection, mask;
962            VECTOR currentMV, pmv[7];
963          int32_t min_dx;          MainSearchFunc *MainSearchPtr;
964          int32_t max_dx;          int32_t iMinSAD = MV_MAX_ERROR;
965          int32_t min_dy;          SearchData Data;
966          int32_t max_dy;  
967            Data.iMinSAD = &iMinSAD;
968            Data.Cur = pCur->y + (x + y * iEdgedWidth) * 16;
969            Data.iEdgedWidth = iEdgedWidth;
970            Data.currentMV = &currentMV;
971            Data.iMinSAD = &iMinSAD;
972            Data.Ref = pRef + (x + y * iEdgedWidth) * 16;
973            Data.RefH = pRefH + (x + y * iEdgedWidth) * 16;
974            Data.RefV = pRefV + (x + y * iEdgedWidth) * 16;
975            Data.RefHV = pRefHV + (x + y * iEdgedWidth) * 16;
976    
977            Data.iQuant = iQuant;
978            Data.iFcode = iFcode;
979            Data.predMV = *predMV;
980    
981          VECTOR newMV;          get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 16,
982          VECTOR backupMV;                                  pParam->width, pParam->height, iFcode);
983    
984          VECTOR pmv[4];          if (!(MotionFlags & PMV_HALFPEL16)) {
985          int32_t psad[8];                  Data.min_dx = EVEN(Data.min_dx);
986                    Data.max_dx = EVEN(Data.max_dx);
987                    Data.min_dy = EVEN(Data.min_dy);
988                    Data.max_dy = EVEN(Data.max_dy); } // no-halpel and b-frames. do we need it?
989    
         static MACROBLOCK *oldMBs = NULL;  
990    
991  //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;          pmv[0] = Data.predMV;
992          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;          PreparePredictionsBF(pmv, x, y, pParam->mb_width,
993          MACROBLOCK *oldMB = NULL;                                          pMB, mode_current);
994    
995           int32_t thresh2;          currentMV.x = currentMV.y = 0;
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD = 9999;  
996    
997          MainSearch16FuncPtr MainSearchPtr;          CheckCandidate = CheckCandidate16no4v;
998    
999          if (oldMBs == NULL) {  // main loop. checking all predictions
1000                  oldMBs = (MACROBLOCK *) calloc(iWcount * iHcount, sizeof(MACROBLOCK));          for (i = 0; i < 8; i++) {
1001  //      fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));                  if (!(mask = make_mask(pmv, i)) ) continue;
1002                    CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, &Data);
1003          }          }
         oldMB = oldMBs + x + y * iWcount;  
   
 /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
   
         if (!(MotionFlags & PMV_HALFPEL16)) {  
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
         }  
         /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
         bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  
         // bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);  
   
 /* Step 4: Calculate SAD around the Median prediction.  
         MinSAD=SAD  
         If Motion Vector equal to Previous frame motion vector  
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
 */  
   
 // Prepare for main loop  
1004    
1005          *currMV = pmv[0];                       /* current best := median prediction */          if (MotionFlags & PMV_USESQUARES16)
1006          if (!(MotionFlags & PMV_HALFPEL16)) {                  MainSearchPtr = SquareSearch;
1007                  currMV->x = EVEN(currMV->x);          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
1008                  currMV->y = EVEN(currMV->y);                  MainSearchPtr = AdvDiamondSearch;
1009          }                  else MainSearchPtr = DiamondSearch;
1010    
1011          if (currMV->x > max_dx)          (*MainSearchPtr)(currentMV.x, currentMV.y, &Data, 255);
                 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 - pmv[0].x, currMV->y - pmv[0].y,  
                                           (uint8_t) iFcode, iQuant);  
   
 // thresh1 is fixed to 256  
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->mvs[0])) &&  
                  ((uint32_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 **************/  
1012    
1013  // previous frame MV          if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(&Data);
         CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);  
1014    
1015  // set threshhold based on Min of Prediction and SAD of collocated block  // three bits are needed to code backward mode. four for forward
1016  // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want  // we treat the bits just like they were vector's
1017            if (mode_current == MODE_FORWARD) iMinSAD +=  4 * lambda_vec16[iQuant];
1018            else iMinSAD +=  3 * lambda_vec16[iQuant];
1019    
         if ((x == 0) && (y == 0)) {  
                 thresh2 = 512;  
         } else {  
 /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */  
1020    
1021                  thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;          if (iMinSAD < *best_sad) {
1022                    *best_sad = iMinSAD;
1023                    pMB->mode = mode_current;
1024                    pMB->pmvs[0].x = currentMV.x - predMV->x;
1025                    pMB->pmvs[0].y = currentMV.y - predMV->y;
1026                    if (mode_current == MODE_FORWARD) pMB->mvs[0] = currentMV;
1027                    else pMB->b_mvs[0] = currentMV;
1028          }          }
1029    
 // MV=(0,0) is often a good choice  
   
         CHECK_MV16_ZERO;  
   
   
 // left neighbour, if allowed  
         if (x != 0) {  
                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                         pmv[1].x = EVEN(pmv[1].x);  
                         pmv[1].y = EVEN(pmv[1].y);  
1030                  }                  }
                 CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].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);  
                 }  
                 CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
1031    
1032  // top right neighbour, if allowed  static int32_t
1033                  if ((uint32_t) x != (iWcount - 1)) {  SearchDirect(const IMAGE * const f_Ref,
1034                          if (!(MotionFlags & PMV_HALFPEL16)) {                                  const uint8_t * const f_RefH,
1035                                  pmv[3].x = EVEN(pmv[3].x);                                  const uint8_t * const f_RefV,
1036                                  pmv[3].y = EVEN(pmv[3].y);                                  const uint8_t * const f_RefHV,
1037                          }                                  const IMAGE * const b_Ref,
1038                          CHECK_MV16_CANDIDATE(pmv[3].x, pmv[3].y);                                  const uint8_t * const b_RefH,
1039                  }                                  const uint8_t * const b_RefV,
1040          }                                  const uint8_t * const b_RefHV,
1041                                    const IMAGE * const pCur,
1042                                    const int x, const int y,
1043                                    const uint32_t MotionFlags,
1044                                    const uint32_t iQuant,
1045                                    const int32_t TRB, const int32_t TRD,
1046                                    const MBParam * const pParam,
1047                                    MACROBLOCK * const pMB,
1048                                    const MACROBLOCK * const b_mb,
1049                                    int32_t * const best_sad)
1050    
1051    {
1052            const uint32_t iEdgedWidth = pParam->edged_width;
1053            int32_t iMinSAD = 266*4096, skip_sad;
1054            int k;
1055            VECTOR currentMV;
1056            MainSearchFunc *MainSearchPtr;
1057            SearchData Data;
1058    
1059            Data.iMinSAD = &iMinSAD;
1060            Data.Cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;
1061            Data.iEdgedWidth = iEdgedWidth;
1062            Data.currentMV = &currentMV;
1063            Data.iQuant = iQuant;
1064            Data.referencemv = b_mb->mvs;
1065    
1066            Data.Ref= f_Ref->y + (x + iEdgedWidth*y) * 16;
1067            Data.RefH = f_RefH + (x + iEdgedWidth*y) * 16;
1068            Data.RefV = f_RefV + (x + iEdgedWidth*y) * 16;
1069            Data.RefHV = f_RefHV + (x + iEdgedWidth*y) * 16;
1070            Data.bRef = b_Ref->y + (x + iEdgedWidth*y) * 16;
1071            Data.bRefH = b_RefH + (x + iEdgedWidth*y) * 16;
1072            Data.bRefV = b_RefV + (x + iEdgedWidth*y) * 16;
1073            Data.bRefHV = b_RefHV + (x + iEdgedWidth*y) * 16;
1074    /*
1075    //What we do here is a complicated version of CheckCandidateDirect(0,0);
1076    get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 16, pParam->width, pParam->height, 19);
1077    
 /* Terminate if MinSAD <= T_2  
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
1078  */  */
1079            Data.max_dx = 2 * pParam->width - 2 * (x) * 16;
1080          if ((iMinSAD <= thresh2)          Data.max_dy = 2 * pParam->height - 2 * (y) * 16;
1081                  || (MVequal(*currMV, prevMB->mvs[0]) &&          Data.min_dx = -(2 * 16 + 2 * (x) * 16);
1082                          ((uint32_t) iMinSAD <= prevMB->sad16))) {          Data.min_dy = -(2 * 16 + 2 * (y) * 16);
1083                  if (MotionFlags & PMV_QUICKSTOP16)  
1084                          goto EPZS16_Terminate_without_Refine;          for (k = 0; k < 4; k++) {
1085                  if (MotionFlags & PMV_EARLYSTOP16)                  pMB->mvs[k].x = Data.directmvF[k].x = ((TRB * Data.referencemv[k].x) / TRD);
1086                          goto EPZS16_Terminate_with_Refine;                  pMB->b_mvs[k].x = Data.directmvB[k].x = ((TRB - TRD) * Data.referencemv[k].x) / TRD;
1087                    pMB->mvs[k].y = Data.directmvF[k].y = ((TRB * Data.referencemv[k].y) / TRD);
1088                    pMB->b_mvs[k].y = Data.directmvB[k].y = ((TRB - TRD) * Data.referencemv[k].y) / TRD;
1089    
1090                    if (( pMB->mvs[k].x > Data.max_dx ) || ( pMB->mvs[k].x < Data.min_dx )
1091                            || ( pMB->mvs[k].y > Data.max_dy ) || ( pMB->mvs[k].y < Data.min_dy )
1092                            || ( pMB->b_mvs[k].x > Data.max_dx ) || ( pMB->b_mvs[k].x < Data.min_dx )
1093                            || ( pMB->b_mvs[k].y > Data.max_dy ) || ( pMB->b_mvs[k].y < Data.min_dy )) {
1094    
1095                            *best_sad = 256*4096; // in that case, we won't use direct mode
1096                            pMB->mode = MODE_DIRECT; // just to make sure it doesn't say "MODE_DIRECT_NONE_MV"
1097                            pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;
1098                            return 0;
1099                    }
1100                    if (b_mb->mode != MODE_INTER4V) {
1101                            pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mvs[0];
1102                            pMB->b_mvs[1] = pMB->b_mvs[2] = pMB->b_mvs[3] = pMB->b_mvs[0];
1103                            Data.directmvF[1] = Data.directmvF[2] = Data.directmvF[3] = Data.directmvF[0];
1104                            Data.directmvB[1] = Data.directmvB[2] = Data.directmvB[3] = Data.directmvB[0];
1105                            break;
1106                    }
1107          }          }
1108    
1109  /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/          if (b_mb->mode == MODE_INTER4V)
1110                    CheckCandidate = CheckCandidateDirect;
1111            else CheckCandidate = CheckCandidateDirectno4v;
1112    
1113          backupMV = prevMB->mvs[0];      // collocated MV          (*CheckCandidate)(0, 0, 255, &k, &Data);
         backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x);     // acceleration X  
         backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y);     // acceleration Y  
1114    
1115          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y);  // skip decision
1116            if (iMinSAD - 2 * lambda_vec16[iQuant] < (int32_t)iQuant * SKIP_THRESH_B) {
1117                    //checking chroma. everything copied from MC
1118                    //this is not full chroma compensation, only it's fullpel approximation. should work though
1119                    int sum, dx, dy, b_dx, b_dy;
1120    
1121  // left neighbour                  sum = pMB->mvs[0].x + pMB->mvs[1].x + pMB->mvs[2].x + pMB->mvs[3].x;
1122          if (x != 0)                  dx = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
                 CHECK_MV16_CANDIDATE((prevMB - 1)->mvs[0].x, (prevMB - 1)->mvs[0].y);  
1123    
1124  // top neighbour                  sum = pMB->mvs[0].y + pMB->mvs[1].y + pMB->mvs[2].y + pMB->mvs[3].y;
1125          if (y != 0)                  dy = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
                 CHECK_MV16_CANDIDATE((prevMB - iWcount)->mvs[0].x,  
                                                          (prevMB - iWcount)->mvs[0].y);  
1126    
1127  // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs                  sum = pMB->b_mvs[0].x + pMB->b_mvs[1].x + pMB->b_mvs[2].x + pMB->b_mvs[3].x;
1128                    b_dx = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1129    
1130          if ((uint32_t) x != iWcount - 1)                  sum = pMB->b_mvs[0].y + pMB->b_mvs[1].y + pMB->b_mvs[2].y + pMB->b_mvs[3].y;
1131                  CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);                  b_dy = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1132    
1133  // bottom neighbour, dito                  sum = sad8bi(pCur->u + 8*x + 8*y*(iEdgedWidth/2),
1134          if ((uint32_t) y != iHcount - 1)                                          f_Ref->u + (y*8 + dy/2) * (iEdgedWidth/2) + x*8 + dx/2,
1135                  CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,                                          b_Ref->u + (y*8 + b_dy/2) * (iEdgedWidth/2) + x*8 + b_dx/2,
1136                                                           (prevMB + iWcount)->mvs[0].y);                                          iEdgedWidth/2);
1137                    sum += sad8bi(pCur->v + 8*x + 8*y*(iEdgedWidth/2),
1138                                            f_Ref->v + (y*8 + dy/2) * (iEdgedWidth/2) + x*8 + dx/2,
1139                                            b_Ref->v + (y*8 + b_dy/2) * (iEdgedWidth/2) + x*8 + b_dx/2,
1140                                            iEdgedWidth/2);
1141    
1142  /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */                  if ((uint32_t) sum < MAX_CHROMA_SAD_FOR_SKIP * Data.iQuant) {
1143          if (iMinSAD <= thresh2) {                          pMB->mode = MODE_DIRECT_NONE_MV;
1144                  if (MotionFlags & PMV_QUICKSTOP16)                          return iMinSAD;
1145                          goto EPZS16_Terminate_without_Refine;                  }
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
1146          }          }
1147    
1148  /************ (if Diamond Search)  **************/          skip_sad = iMinSAD;
   
         backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  
   
         if (MotionFlags & PMV_USESQUARES8)  
                 MainSearchPtr = Square16_MainSearch;  
         else  
          if (MotionFlags & PMV_ADVANCEDDIAMOND8)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
   
 /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  
1149    
1150          iSAD =  //  DIRECT MODE DELTA VECTOR SEARCH.
1151                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  //      This has to be made more effective, but at the moment I'm happy it's running at all
                                                   currMV->y, iMinSAD, &newMV, pmv, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);  
1152    
1153          if (iSAD < iMinSAD) {          if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1154                  *currMV = newMV;                  else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1155                  iMinSAD = iSAD;                          else MainSearchPtr = DiamondSearch;
         }  
1156    
1157            (*MainSearchPtr)(0, 0, &Data, 255);
1158    
1159          if (MotionFlags & PMV_EXTSEARCH16) {          HalfpelRefine(&Data);
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
1160    
1161                  if (!(MVequal(pmv[0], backupMV))) {          iMinSAD +=  1 * lambda_vec16[iQuant]; // one bit is needed to code direct mode. we treat this bit just like it was vector's
1162                          iSAD =          *best_sad = iMinSAD;
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, pmv,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   2, iFcode, iQuant, 0);  
                 }  
1163    
1164                  if (iSAD < iMinSAD) {          if (b_mb->mode == MODE_INTER4V)
1165                          *currMV = newMV;                  pMB->mode = MODE_DIRECT;
1166                          iMinSAD = iSAD;          else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation
                 }  
1167    
1168                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          pMB->pmvs[3] = currentMV;
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, pmv, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);  
1169    
1170                          if (iSAD < iMinSAD) {          for (k = 0; k < 4; k++) {
1171                                  *currMV = newMV;                  pMB->mvs[k].x = Data.directmvF[k].x + currentMV.x;
1172                                  iMinSAD = iSAD;                  pMB->b_mvs[k].x = ((currentMV.x == 0)
1173                          }                                                          ? Data.directmvB[k].x
1174                                                            : pMB->mvs[k].x - Data.referencemv[k].x);
1175                    pMB->mvs[k].y = (Data.directmvF[k].y + currentMV.y);
1176                    pMB->b_mvs[k].y = ((currentMV.y == 0)
1177                                                            ? Data.directmvB[k].y
1178                                                            : pMB->mvs[k].y - Data.referencemv[k].y);
1179                    if (b_mb->mode != MODE_INTER4V) {
1180                            pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1181                            pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1182                            break;
1183                  }                  }
1184          }          }
1185            return 0;//skip_sad;
 /***************        Choose best MV found     **************/  
   
   EPZS16_Terminate_with_Refine:  
         if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step  
                 iMinSAD =  
                         Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                          iMinSAD, pmv, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
   
   EPZS16_Terminate_without_Refine:  
   
         *oldMB = *prevMB;  
   
         currPMV->x = currMV->x - pmv[0].x;  
         currPMV->y = currMV->y - pmv[0].y;  
         return iMinSAD;  
1186  }  }
1187    
1188    static __inline void
1189  int32_t  SearchInterpolate(const uint8_t * const f_Ref,
1190  EPZSSearch8(const uint8_t * const pRef,                                  const uint8_t * const f_RefH,
1191                          const uint8_t * const pRefH,                                  const uint8_t * const f_RefV,
1192                          const uint8_t * const pRefV,                                  const uint8_t * const f_RefHV,
1193                          const uint8_t * const pRefHV,                                  const uint8_t * const b_Ref,
1194                                    const uint8_t * const b_RefH,
1195                                    const uint8_t * const b_RefV,
1196                                    const uint8_t * const b_RefHV,
1197                          const IMAGE * const pCur,                          const IMAGE * const pCur,
1198                          const int x,                                  const int x, const int y,
1199                          const int y,                                  const uint32_t fcode,
1200                          const int start_x,                                  const uint32_t bcode,
                         const int start_y,  
1201                          const uint32_t MotionFlags,                          const uint32_t MotionFlags,
1202                          const uint32_t iQuant,                          const uint32_t iQuant,
                         const uint32_t iFcode,  
1203                          const MBParam * const pParam,                          const MBParam * const pParam,
1204                          const MACROBLOCK * const pMBs,                                  const VECTOR * const f_predMV,
1205                          const MACROBLOCK * const prevMBs,                                  const VECTOR * const b_predMV,
1206                          VECTOR * const currMV,                                  MACROBLOCK * const pMB,
1207                          VECTOR * const currPMV)                                  int32_t * const best_sad)
1208    
1209  {  {
1210  /* Please not that EPZS might not be a good choice for 8x8-block motion search ! */  /* Interpolated MC motion vector search, this is tedious and more complicated because there are
1211       two values for everything, always one for backward and one for forward ME. Still, we don't gain
1212       much from this search, maybe it should simply be skipped and simply current i_sad16 value used
1213       as "optimal". */
1214    
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
1215          const int32_t iEdgedWidth = pParam->edged_width;          const int32_t iEdgedWidth = pParam->edged_width;
1216    
1217          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;          int iDirection, i, j;
1218            int32_t iMinSAD = 256*4096;
1219            VECTOR currentMV[3];
1220            SearchData fData, bData;
1221    
1222            fData.iMinSAD = bData.iMinSAD = &iMinSAD;
1223    
1224            fData.Cur = bData.Cur = pCur->y + (x + y * iEdgedWidth) * 16;
1225            fData.iEdgedWidth = bData.iEdgedWidth = iEdgedWidth;
1226            fData.currentMV = currentMV; bData.currentMV = currentMV + 1;
1227            fData.iQuant = bData.iQuant = iQuant;
1228            fData.iFcode = bData.bFcode = fcode; fData.bFcode = bData.iFcode = bcode;
1229    
1230            bData.bRef = fData.Ref = f_Ref + (x + y * iEdgedWidth) * 16;
1231            bData.bRefH = fData.RefH = f_RefH + (x + y * iEdgedWidth) * 16;
1232            bData.bRefV = fData.RefV = f_RefV + (x + y * iEdgedWidth) * 16;
1233            bData.bRefHV = fData.RefHV = f_RefHV + (x + y * iEdgedWidth) * 16;
1234            bData.Ref = fData.bRef = b_Ref + (x + y * iEdgedWidth) * 16;
1235            bData.RefH = fData.bRefH = b_RefH + (x + y * iEdgedWidth) * 16;
1236            bData.RefV = fData.bRefV = b_RefV + (x + y * iEdgedWidth) * 16;
1237            bData.RefHV = fData.bRefHV = b_RefHV + (x + y * iEdgedWidth) * 16;
1238    
1239            bData.bpredMV = fData.predMV = *f_predMV;
1240            fData.bpredMV = bData.predMV = *b_predMV;
1241    
1242            currentMV[0] = pMB->mvs[0];
1243            currentMV[1] = pMB->b_mvs[0];
1244            get_range(&fData.min_dx, &fData.max_dx, &fData.min_dy, &fData.max_dy, x, y, 16, pParam->width, pParam->height, fcode);
1245            get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode);
1246    
1247            if (currentMV[0].x > fData.max_dx) currentMV[0].x = fData.max_dx;
1248            if (currentMV[0].x < fData.min_dx) currentMV[0].x = fData.min_dy;
1249            if (currentMV[0].y > fData.max_dy) currentMV[0].y = fData.max_dx;
1250            if (currentMV[0].y > fData.min_dy) currentMV[0].y = fData.min_dy;
1251    
1252            if (currentMV[1].x > bData.max_dx) currentMV[1].x = bData.max_dx;
1253            if (currentMV[1].x < bData.min_dx) currentMV[1].x = bData.min_dy;
1254            if (currentMV[1].y > bData.max_dy) currentMV[1].y = bData.max_dx;
1255            if (currentMV[1].y > bData.min_dy) currentMV[1].y = bData.min_dy;
1256    
1257          int32_t iDiamondSize = 1;          CheckCandidateInt(currentMV[0].x, currentMV[0].y, 255, &iDirection, &fData);
1258    
1259          int32_t min_dx;  //diamond. I wish we could use normal mainsearch functions (square, advdiamond)
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
1260    
1261          VECTOR newMV;          do {
1262          VECTOR backupMV;                  iDirection = 255;
1263                    // forward MV moves
1264                    i = currentMV[0].x; j = currentMV[0].y;
1265    
1266                    CheckCandidateInt(i + 1, j, 0, &iDirection, &fData);
1267                    CheckCandidateInt(i, j + 1, 0, &iDirection, &fData);
1268                    CheckCandidateInt(i - 1, j, 0, &iDirection, &fData);
1269                    CheckCandidateInt(i, j - 1, 0, &iDirection, &fData);
1270    
1271                    // backward MV moves
1272                    i = currentMV[1].x; j = currentMV[1].y;
1273                    currentMV[2] = currentMV[0];
1274    
1275                    CheckCandidateInt(i + 1, j, 0, &iDirection, &bData);
1276                    CheckCandidateInt(i, j + 1, 0, &iDirection, &bData);
1277                    CheckCandidateInt(i - 1, j, 0, &iDirection, &bData);
1278                    CheckCandidateInt(i, j - 1, 0, &iDirection, &bData);
1279    
1280            } while (!(iDirection));
1281    
1282    // two bits are needed to code interpolate mode. we treat the bits just like they were vector's
1283            iMinSAD +=  2 * lambda_vec16[iQuant];
1284            if (iMinSAD < *best_sad) {
1285                    *best_sad = iMinSAD;
1286                    pMB->mvs[0] = currentMV[0];
1287                    pMB->b_mvs[0] = currentMV[1];
1288                    pMB->mode = MODE_INTERPOLATE;
1289    
1290                    pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;
1291                    pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;
1292                    pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;
1293                    pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;
1294            }
1295    }
1296    
1297          VECTOR pmv[4];  void
1298          int32_t psad[8];  MotionEstimationBVOP(MBParam * const pParam,
1299                                             FRAMEINFO * const frame,
1300                                             const int32_t time_bp,
1301                                             const int32_t time_pp,
1302                                             // forward (past) reference
1303                                             const MACROBLOCK * const f_mbs,
1304                                             const IMAGE * const f_ref,
1305                                             const IMAGE * const f_refH,
1306                                             const IMAGE * const f_refV,
1307                                             const IMAGE * const f_refHV,
1308                                             // backward (future) reference
1309                                             const MACROBLOCK * const b_mbs,
1310                                             const IMAGE * const b_ref,
1311                                             const IMAGE * const b_refH,
1312                                             const IMAGE * const b_refV,
1313                                             const IMAGE * const b_refHV)
1314    {
1315            uint32_t i, j;
1316            int32_t best_sad, skip_sad;
1317            int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;
1318            static const VECTOR zeroMV={0,0};
1319    
1320          const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
1321    
1322  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          const int32_t TRB = time_pp - time_bp;
1323          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;          const int32_t TRD = time_pp;
1324    
1325          int32_t bPredEq;          // note: i==horizontal, j==vertical
         int32_t iMinSAD, iSAD = 9999;  
1326    
1327          MainSearch8FuncPtr MainSearchPtr;          for (j = 0; j < pParam->mb_height; j++) {
1328    
1329  /* Get maximum range */                  f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,  
                           iFcode);  
1330    
1331  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */                  for (i = 0; i < pParam->mb_width; i++) {
1332                            MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
1333                            const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
1334    
1335          if (!(MotionFlags & PMV_HALFPEL8)) {  /* special case, if collocated block is SKIPed: encoding is forward (0,0), cpb=0 without further ado */
1336                  min_dx = EVEN(min_dx);                          if (b_mb->mode == MODE_NOT_CODED) {
1337                  max_dx = EVEN(max_dx);                                  pMB->mode = MODE_NOT_CODED;
1338                  min_dy = EVEN(min_dy);                                  continue;
                 max_dy = EVEN(max_dy);  
1339          }          }
         /* 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, psad);  
         // bPredEq = get_pmvdata2(pMBs, iWcount, 0, x >> 1, y >> 1, iSubBlock, pmv, psad);  
1340    
1341    /* direct search comes first, because it (1) checks for SKIP-mode
1342            and (2) sets very good predictions for forward and backward search */
1343    
1344  /* Step 4: Calculate SAD around the Median prediction.                          skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
1345          MinSAD=SAD                                                                          b_ref, b_refH->y, b_refV->y, b_refHV->y,
1346          If Motion Vector equal to Previous frame motion vector                                                                          &frame->image,
1347                  and MinSAD<PrevFrmSAD goto Step 10.                                                                          i, j,
1348          If SAD<=256 goto Step 10.                                                                          frame->motion_flags,
1349  */                                                                          frame->quant,
1350                                                                            TRB, TRD,
1351                                                                            pParam,
1352                                                                            pMB, b_mb,
1353                                                                            &best_sad);
1354    
1355  // Prepare for main loop                          if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
1356    
1357    //                      best_sad = 256*4096; //uncomment to disable Directsearch.
1358    //      To disable any other mode, just comment the function call
1359    
1360          if (!(MotionFlags & PMV_HALFPEL8)) {                          // forward search
1361                  currMV->x = EVEN(currMV->x);                          SearchBF(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
1362                  currMV->y = EVEN(currMV->y);                                                  &frame->image, i, j,
1363                                                    frame->motion_flags,
1364                                                    frame->quant, frame->fcode, pParam,
1365                                                    pMB, &f_predMV, &best_sad,
1366                                                    MODE_FORWARD);
1367    
1368                            // backward search
1369                            SearchBF(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
1370                                                    &frame->image, i, j,
1371                                                    frame->motion_flags,
1372                                                    frame->quant, frame->bcode, pParam,
1373                                                    pMB, &b_predMV, &best_sad,
1374                                                    MODE_BACKWARD);
1375    
1376                            // interpolate search comes last, because it uses data from forward and backward as prediction
1377    
1378                            SearchInterpolate(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
1379                                                    b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
1380                                                    &frame->image,
1381                                                    i, j,
1382                                                    frame->fcode, frame->bcode,
1383                                                    frame->motion_flags,
1384                                                    frame->quant, pParam,
1385                                                    &f_predMV, &b_predMV,
1386                                                    pMB, &best_sad);
1387    
1388                            switch (pMB->mode) {
1389                                    case MODE_FORWARD:
1390                                            f_count++;
1391                                            f_predMV = pMB->mvs[0];
1392                                            break;
1393                                    case MODE_BACKWARD:
1394                                            b_count++;
1395                                            b_predMV = pMB->b_mvs[0];
1396                                            break;
1397                                    case MODE_INTERPOLATE:
1398                                            i_count++;
1399                                            f_predMV = pMB->mvs[0];
1400                                            b_predMV = pMB->b_mvs[0];
1401                                            break;
1402                                    case MODE_DIRECT:
1403                                    case MODE_DIRECT_NO4V:
1404                                            d_count++;
1405                                            break;
1406                                    default:
1407                                            break;
1408                            }
1409                    }
1410          }          }
1411    
1412          if (currMV->x > max_dx)  //      fprintf(debug,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d, N: %04d\n",
1413                  currMV->x = max_dx;  //                              f_count,b_count,i_count,d_count,n_count);
1414          if (currMV->x < min_dx)  
1415                  currMV->x = min_dx;  }
1416          if (currMV->y > max_dy)  
1417                  currMV->y = max_dy;  /* Hinted ME starts here */
1418          if (currMV->y < min_dy)  
1419                  currMV->y = min_dy;  static __inline void
1420    Search8hinted(  const SearchData * const OldData,
1421                                    const int x, const int y,
1422                                    const uint32_t MotionFlags,
1423                                    const MBParam * const pParam,
1424                                    MACROBLOCK * const pMB,
1425                                    const MACROBLOCK * const pMBs,
1426                                    const int block)
1427    {
1428            SearchData Data;
1429            MainSearchFunc *MainSearchPtr;
1430    
1431  /***************** This is predictor SET A: only median prediction ******************/          Data.predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2 , y/2, block);
1432            Data.iMinSAD = OldData->iMinSAD + 1 + block;
1433            Data.currentMV = OldData->currentMV+1+block;
1434            Data.iFcode = OldData->iFcode;
1435            Data.iQuant = OldData->iQuant;
1436    
1437            Data.Ref = OldData->Ref + 8 * ((block&1) + pParam->edged_width*(block>>1));
1438            Data.RefH = OldData->RefH + 8 * ((block&1) + pParam->edged_width*(block>>1));
1439            Data.RefV = OldData->RefV + 8 * ((block&1) + pParam->edged_width*(block>>1));
1440            Data.RefHV = OldData->RefHV + 8 * ((block&1) + pParam->edged_width*(block>>1));
1441            Data.iEdgedWidth = pParam->edged_width;
1442            Data.Cur = OldData->Cur + 8 * ((block&1) + pParam->edged_width*(block>>1));
1443    
1444          iMinSAD =          CheckCandidate = CheckCandidate8;
                 sad8(cur,  
                          get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  
                                                 iEdgedWidth), iEdgedWidth);  
         iMinSAD +=  
                 calc_delta_8(currMV->x - pmv[0].x, currMV->y - pmv[0].y,  
                                          (uint8_t) iFcode, iQuant);  
1445    
1446            if (block != 0)
1447                    *(Data.iMinSAD) += lambda_vec8[Data.iQuant] *
1448                                                                    d_mv_bits(      Data.currentMV->x - Data.predMV.x,
1449                                                                                            Data.currentMV->y - Data.predMV.y,
1450                                                                                            Data.iFcode);
1451    
 // thresh1 is fixed to 256  
         if (iMinSAD < 256 / 4) {  
                 if (MotionFlags & PMV_QUICKSTOP8)  
                         goto EPZS8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
         }  
1452    
1453  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/          get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 8,
1454                                    pParam->width, pParam->height, OldData->iFcode);
1455    
1456            if (pMB->mode == MODE_INTER4V) {
1457                    int dummy;
1458                    CheckCandidate8(pMB->mvs[block].x, pMB->mvs[block].y, 0, &dummy, &Data); }
1459    
1460  // MV=(0,0) is often a good choice          if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
1461          CHECK_MV8_ZERO;                  else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1462                            else MainSearchPtr = DiamondSearch;
1463    
1464  // previous frame MV          (*MainSearchPtr)(Data.currentMV->x, Data.currentMV->y, &Data, 255);
         CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x, prevMB->mvs[iSubBlock].y);  
1465    
1466  // left neighbour, if allowed          if (MotionFlags & PMV_HALFPELREFINE8) HalfpelRefine(&Data);
         if (psad[1] != MV_MAX_ERROR) {  
                 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  
         if (psad[2] != MV_MAX_ERROR) {  
                 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);  
1467    
1468  // top right neighbour, if allowed          pMB->pmvs[block].x = Data.currentMV->x - Data.predMV.x;
1469                  if (psad[3] != MV_MAX_ERROR) {          pMB->pmvs[block].y = Data.currentMV->y - Data.predMV.y;
1470                          if (!(MotionFlags & PMV_HALFPEL8)) {          pMB->mvs[block] = *(Data.currentMV);
1471                                  pmv[3].x = EVEN(pmv[3].x);          pMB->sad8[block] =  4 * (*(Data.iMinSAD));
                                 pmv[3].y = EVEN(pmv[3].y);  
                         }  
                         CHECK_MV8_CANDIDATE(pmv[3].x, pmv[3].y);  
                 }  
1472          }          }
1473    
 /*  // this bias is zero anyway, at the moment!  
1474    
1475          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)  static void
1476                  iMinSAD -= MV8_00_BIAS;  SearchPhinted ( const uint8_t * const pRef,
1477                                    const uint8_t * const pRefH,
1478                                    const uint8_t * const pRefV,
1479                                    const uint8_t * const pRefHV,
1480                                    const IMAGE * const pCur,
1481                                    const int x,
1482                                    const int y,
1483                                    const uint32_t MotionFlags,
1484                                    const uint32_t iQuant,
1485                                    const uint32_t iFcode,
1486                                    const MBParam * const pParam,
1487                                    const MACROBLOCK * const pMBs,
1488                                    int inter4v,
1489                                    MACROBLOCK * const pMB)
1490    {
1491    
1492  */          const int32_t iEdgedWidth = pParam->edged_width;
1493    
1494  /* Terminate if MinSAD <= T_2          int i;
1495     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]          VECTOR currentMV[5];
1496  */          int32_t iMinSAD[5];
1497            int32_t temp[5];
1498            MainSearchFunc * MainSearchPtr;
1499            SearchData Data;
1500    
1501            Data.predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1502            get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 16,
1503                                    pParam->width, pParam->height, iFcode);
1504    
1505            Data.Cur = pCur->y + (x + y * iEdgedWidth) * 16;
1506            Data.iEdgedWidth = iEdgedWidth;
1507            Data.currentMV = currentMV;
1508            Data.iMinSAD = iMinSAD;
1509            Data.Ref = pRef + (x + iEdgedWidth*y)*16;
1510            Data.RefH = pRefH + (x + iEdgedWidth*y) * 16;
1511            Data.RefV = pRefV + (x + iEdgedWidth*y) * 16;
1512            Data.RefHV = pRefHV + (x + iEdgedWidth*y) * 16;
1513            Data.temp = temp;
1514            Data.iQuant = iQuant;
1515            Data.iFcode = iFcode;
1516    
1517          if (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */          if (!(MotionFlags & PMV_HALFPEL16)) {
1518                  if (MotionFlags & PMV_QUICKSTOP8)                  Data.min_dx = EVEN(Data.min_dx);
1519                          goto EPZS8_Terminate_without_Refine;                  Data.max_dx = EVEN(Data.max_dx);
1520                  if (MotionFlags & PMV_EARLYSTOP8)                  Data.min_dy = EVEN(Data.min_dy);
1521                          goto EPZS8_Terminate_with_Refine;                  Data.max_dy = EVEN(Data.max_dy);
1522          }          }
1523    
1524  /************ (Diamond Search)  **************/          for(i = 0; i < 5; i++) iMinSAD[i] = MV_MAX_ERROR;
1525    
1526          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          if (pMB->dquant != NO_CHANGE) inter4v = 0;
1527    
1528          if (!(MotionFlags & PMV_HALFPELDIAMOND8))          if (inter4v)
1529                  iDiamondSize *= 2;                  CheckCandidate = CheckCandidate16;
1530            else CheckCandidate = CheckCandidate16no4v;
1531    
 /* default: use best prediction as starting point for one call of EPZS_MainSearch */  
1532    
1533  // there is no EPZS^2 for inter4v at the moment          pMB->mvs[0].x = EVEN(pMB->mvs[0].x);
1534            pMB->mvs[0].y = EVEN(pMB->mvs[0].y);
1535            if (pMB->mvs[0].x > Data.max_dx) pMB->mvs[0].x = Data.max_dx; // this is in case iFcode changed
1536            if (pMB->mvs[0].x < Data.min_dx) pMB->mvs[0].x = Data.min_dx;
1537            if (pMB->mvs[0].y > Data.max_dy) pMB->mvs[0].y = Data.max_dy;
1538            if (pMB->mvs[0].y < Data.min_dy) pMB->mvs[0].y = Data.min_dy;
1539    
1540  //  if (MotionFlags & PMV_USESQUARES8)          CheckCandidate16(pMB->mvs[0].x, pMB->mvs[0].y, 0, &i, &Data);
 //      MainSearchPtr = Square8_MainSearch;  
 //  else  
1541    
1542          if (MotionFlags & PMV_ADVANCEDDIAMOND8)          if (pMB->mode == MODE_INTER4V)
1543                  MainSearchPtr = AdvDiamond8_MainSearch;                  for (i = 1; i < 4; i++) { // all four vectors will be used as four predictions for 16x16 search
1544          else                          pMB->mvs[i].x = EVEN(pMB->mvs[i].x);
1545                  MainSearchPtr = Diamond8_MainSearch;                          pMB->mvs[i].y = EVEN(pMB->mvs[i].y);
1546                            if (!(make_mask(pMB->mvs, i)))
1547                                    CheckCandidate16(pMB->mvs[i].x, pMB->mvs[i].y, 0, &i, &Data);
1548                    }
1549    
1550          iSAD =          if (MotionFlags & PMV_USESQUARES16)
1551                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,                  MainSearchPtr = SquareSearch;
1552                                                    currMV->y, iMinSAD, &newMV, pmv, min_dx, max_dx,          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
1553                                                    min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,                  MainSearchPtr = AdvDiamondSearch;
1554                                                    iQuant, 0);                  else MainSearchPtr = DiamondSearch;
1555    
1556            (*MainSearchPtr)(currentMV->x, currentMV->y, &Data, 255);
1557    
1558          if (iSAD < iMinSAD) {          if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(&Data);
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
1559    
1560          if (MotionFlags & PMV_EXTSEARCH8) {          if (inter4v)
1561  /* extended mode: search (up to) two more times: orignal prediction and (0,0) */                  for(i = 0; i < 4; i++)
1562                            Search8hinted(&Data, 2*x+(i&1), 2*y+(i>>1), MotionFlags, pParam, pMB, pMBs, i);
1563    
1564                  if (!(MVequal(pmv[0], backupMV))) {          if (!(inter4v) ||
1565                          iSAD =                  (iMinSAD[0] < iMinSAD[1] + iMinSAD[2] + iMinSAD[3] + iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {
1566                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  // INTER MODE
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, pmv,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, 0);  
1567    
1568                          if (iSAD < iMinSAD) {                  pMB->mode = MODE_INTER;
1569                                  *currMV = newMV;                  pMB->mvs[0] = pMB->mvs[1]
1570                                  iMinSAD = iSAD;                          = pMB->mvs[2] = pMB->mvs[3] = currentMV[0];
                         }  
                 }  
1571    
1572                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
1573                          iSAD =                          pMB->sad8[2] = pMB->sad8[3] =  iMinSAD[0];
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, pmv, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, 0);  
1574    
1575                          if (iSAD < iMinSAD) {                  pMB->pmvs[0].x = currentMV[0].x - Data.predMV.x;
1576                                  *currMV = newMV;                  pMB->pmvs[0].y = currentMV[0].y - Data.predMV.y;
1577                                  iMinSAD = iSAD;          } else {
1578                          }  // INTER4V MODE; all other things are already set in Search8hinted
1579                  }                  pMB->mode = MODE_INTER4V;
1580                    pMB->sad16 = iMinSAD[1] + iMinSAD[2] + iMinSAD[3] + iMinSAD[4] + IMV16X16 * iQuant;
1581          }          }
1582    
1583  /***************        Choose best MV found     **************/  }
1584    
1585    EPZS8_Terminate_with_Refine:  void
1586          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step  MotionEstimationHinted( MBParam * const pParam,
1587                  iMinSAD =                                                  FRAMEINFO * const current,
1588                          Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,                                                  FRAMEINFO * const reference,
1589                                                          iMinSAD, pmv, min_dx, max_dx, min_dy, max_dy,                                                  const IMAGE * const pRefH,
1590                                                          iFcode, iQuant, iEdgedWidth);                                                  const IMAGE * const pRefV,
1591                                                    const IMAGE * const pRefHV)
1592    {
1593            MACROBLOCK *const pMBs = current->mbs;
1594            const IMAGE *const pCurrent = &current->image;
1595            const IMAGE *const pRef = &reference->image;
1596    
1597    EPZS8_Terminate_without_Refine:          uint32_t x, y;
1598    
1599          currPMV->x = currMV->x - pmv[0].x;          if (sadInit) (*sadInit) ();
         currPMV->y = currMV->y - pmv[0].y;  
         return iMinSAD;  
 }  
1600    
1601            for (y = 0; y < pParam->mb_height; y++) {
1602                    for (x = 0; x < pParam->mb_width; x++)  {
1603    
1604                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1605    
1606    //intra mode is copied from the first pass. At least for the time being
1607                            if  ((pMB->mode == MODE_INTRA) || (pMB->mode == MODE_NOT_CODED) ) continue;
1608    
1609                            if (!(current->global_flags & XVID_LUMIMASKING)) {
1610                                    pMB->dquant = NO_CHANGE;
1611                                    pMB->quant = current->quant; }
1612    
1613  /* ***********************************************************                          SearchPhinted(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1614          bvop motion estimation                                                          y, current->motion_flags, pMB->quant,
1615  // TODO: need to incorporate prediction here (eg. sad += calc_delta_16)                                                          current->fcode, pParam, pMBs,
1616  ***************************************************************/                                                          current->global_flags & XVID_INTER4V, pMB);
1617    
1618                    }
1619            }
1620    }
1621    
1622  void  static __inline int
1623  MotionEstimationBVOP(MBParam * const pParam,  MEanalyzeMB (   const uint8_t * const pRef,
1624                                           FRAMEINFO * const frame,                                  const uint8_t * const pCur,
1625                                           // forward (past) reference                                  const int x,
1626                                           const MACROBLOCK * const f_mbs,                                  const int y,
1627                                           const IMAGE * const f_ref,                                  const uint32_t iFcode,
1628                                           const IMAGE * const f_refH,                                  const MBParam * const pParam,
1629                                           const IMAGE * const f_refV,                                  const MACROBLOCK * const pMBs,
1630                                           const IMAGE * const f_refHV,                                  MACROBLOCK * const pMB)
                                          // 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)  
1631  {  {
         const uint32_t mb_width = pParam->mb_width;  
         const uint32_t mb_height = pParam->mb_height;  
         const int32_t edged_width = pParam->edged_width;  
1632    
1633          uint32_t i, j;          const int32_t iEdgedWidth = pParam->edged_width;
1634            int i, mask;
1635            VECTOR currentMV, pmv[3];
1636            int32_t iMinSAD = MV_MAX_ERROR;
1637            SearchData Data;
1638    
1639            Data.predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1640            get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 16,
1641                                    pParam->width, pParam->height, iFcode);
1642    
1643            Data.Cur = pCur + (x + y * iEdgedWidth) * 16;
1644            Data.iEdgedWidth = iEdgedWidth;
1645            Data.currentMV = &currentMV;
1646            Data.iMinSAD = &iMinSAD;
1647            Data.Ref = pRef + (x + iEdgedWidth*y)*16;
1648            Data.iQuant = 2;
1649            Data.iFcode = iFcode;
1650    
1651            CheckCandidate = CheckCandidate16no4vI;
1652    
1653            pmv[1].x = EVEN(pMB->mvs[0].x);
1654            pmv[1].y = EVEN(pMB->mvs[0].y);
1655            pmv[0].x = EVEN(Data.predMV.x);
1656            pmv[0].y = EVEN(Data.predMV.y);
1657            pmv[2].x = pmv[2].y = 0;
1658    
1659            CheckCandidate16no4vI(pmv[0].x, pmv[0].y, 255, &i, &Data);
1660            if (!(mask = make_mask(pmv, 1)))
1661                    CheckCandidate16no4vI(pmv[1].x, pmv[1].y, mask, &i, &Data);
1662            if (!(mask = make_mask(pmv, 2)))
1663                    CheckCandidate16no4vI(0, 0, mask, &i, &Data);
1664    
1665          int32_t f_sad16;          DiamondSearch(currentMV.x, currentMV.y, &Data, i);
         int32_t b_sad16;  
         int32_t i_sad16;  
         int32_t d_sad16;  
         int32_t best_sad;  
1666    
1667          VECTOR pmv_dontcare;          pMB->mvs[0] = pMB->mvs[1]
1668                            = pMB->mvs[2] = pMB->mvs[3] = currentMV; // all, for future get_pmv()
1669    
1670          // note: i==horizontal, j==vertical          return iMinSAD;
         for (j = 0; j < mb_height; j++) {  
                 for (i = 0; i < mb_width; i++) {  
                         MACROBLOCK *mb = &frame->mbs[i + j * mb_width];  
                         const MACROBLOCK *f_mb = &f_mbs[i + j * mb_width];  
                         const MACROBLOCK *b_mb = &b_mbs[i + j * mb_width];  
   
                         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;  
1671                          }                          }
                 /* force F_SAD16  
                         f_sad16 = 100;  
                         b_sad16 = 65535;  
   
                         mb->mode = MODE_FORWARD;  
                         mb->mvs[0].x = 1;  
                         mb->mvs[0].y = 1;  
                         mb->b_mvs[0].x = 1;  
                         mb->b_mvs[0].y = 1;  
                         continue;  
                  ^^ force F_SAD16 */  
1672    
1673    #define INTRA_THRESH    1350
1674    #define INTER_THRESH    900
1675    
1676                          // forward search  int
1677                          f_sad16 =  MEanalysis(     const IMAGE * const pRef,
1678                                  SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,                          const IMAGE * const pCurrent,
1679                                                   &frame->image, i, j, frame->motion_flags,                          MBParam * const pParam,
1680                                                   frame->quant, frame->fcode, pParam,                          MACROBLOCK * const pMBs,
1681                                                   f_mbs,  f_mbs, /* todo */                          const uint32_t iFcode)
1682                                                   &mb->mvs[0], &pmv_dontcare);   // ignore pmv  {
1683            uint32_t x, y, intra = 0;
1684                          // backward search          int sSAD = 0;
                         b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 &frame->image, i, j, frame->motion_flags,  
                                                 frame->quant, frame->bcode, pParam,  
                                                 b_mbs, b_mbs,   /* todo */  
                                                 &mb->b_mvs[0], &pmv_dontcare);  // ignore pmv  
   
                         // interpolate search (simple, but effective)  
                         i_sad16 = 65535;  
1685    
1686                          /*          if (sadInit) (*sadInit) ();
                         x/y range somewhat buggy  
                         i_sad16 =  
                                 sad16bi_c(frame->image.y + i * 16 + j * 16 * edged_width,  
                                                   get_ref(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                   i, j, 16, mb->mvs[0].x, mb->mvs[0].y,  
                                                                   edged_width), get_ref(b_ref->y, b_refH->y,  
                                                                                                                 b_refV->y, b_refHV->y,  
                                                                                                                 i, j, 16,  
                                                                                                                 mb->b_mvs[0].x,  
                                                                                                                 mb->b_mvs[0].x,  
                                                                                                                 edged_width),  
                                                   edged_width);  
                         */  
1687    
1688                          // TODO: direct search          for (y = 0; y < pParam->mb_height-1; y++) {
1689                          // predictor + range of [-32,32]                  for (x = 0; x < pParam->mb_width; x++) {
1690                          d_sad16 = 65535;                          int sad, dev;
1691    
1692                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1693    
1694                          if (f_sad16 < b_sad16) {                          sad = MEanalyzeMB(pRef->y, pCurrent->y, x, y,
1695                                  best_sad = f_sad16;                                                                  iFcode, pParam, pMBs, pMB);
                                 mb->mode = MODE_FORWARD;  
                         } else {  
                                 best_sad = b_sad16;  
                                 mb->mode = MODE_BACKWARD;  
                         }  
1696    
1697                          if (i_sad16 < best_sad) {                          if ( x != 0 && y != 0 && x != pParam->mb_width-1 ) { //no edge macroblocks, they just don't work
1698                                  best_sad = i_sad16;                                  if (sad > INTRA_THRESH) {
1699                                  mb->mode = MODE_INTERPOLATE;                                          dev = dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,
1700                                                                      pParam->edged_width);
1701                                            if (dev + INTRA_THRESH < sad) intra++;
1702                                            if (intra > (pParam->mb_height-2)*(pParam->mb_width-2)/2) return 2;  // I frame
1703                          }                          }
1704                                    sSAD += sad;
                         if (d_sad16 < best_sad) {  
                                 best_sad = d_sad16;  
                                 mb->mode = MODE_DIRECT;  
1705                          }                          }
1706    
1707                  }                  }
1708          }          }
1709            sSAD /= (pParam->mb_height-2)*(pParam->mb_width-2);
1710            if (sSAD > INTER_THRESH ) return 1; //P frame
1711            emms();
1712            return 0; // B frame
1713    
1714  }  }

Legend:
Removed from v.1.26  
changed lines
  Added in v.1.44.2.2

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