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

Legend:
Removed from v.1.44  
changed lines
  Added in v.1.44.2.5

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