[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.4, Sat Sep 28 17:28:18 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;
554    
555            // some pre-initialized thingies for SearchP
556            int32_t temp[5];
557            VECTOR currentMV[5];
558            int32_t iMinSAD[5];
559            SearchData Data;
560            Data.iEdgedWidth = pParam->edged_width;
561            Data.currentMV = currentMV;
562            Data.iMinSAD = iMinSAD;
563            Data.temp = temp;
564            Data.iFcode = current->fcode;
565    
566            if (sadInit) (*sadInit) ();
567    
568            for (y = 0; y < pParam->mb_height; y++) {
569                    for (x = 0; x < pParam->mb_width; x++)  {
570    
571                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
572                            int32_t sad00 =  pMB->sad16
573                                    = sad16v(pCurrent->y + (x + y * pParam->edged_width) * 16,
574                                                            pRef->y + (x + y * pParam->edged_width) * 16,
575                                                            pParam->edged_width, pMB->sad8 );
576    
577                            if (!(current->global_flags & XVID_LUMIMASKING)) {
578                                    pMB->dquant = NO_CHANGE;
579                                    pMB->quant = current->quant; }
580    
581    //initial skip decision
582    
583                            if ((pMB->dquant == NO_CHANGE) && (sad00 <= MAX_SAD00_FOR_SKIP * pMB->quant)
584                                    && (SkipDecisionP(pCurrent, pRef, x, y, pParam->edged_width, pMB->quant)) ) {
585                                    if (pMB->sad16 < pMB->quant * INITIAL_SKIP_THRESH) {
586                                                    SkipMacroblockP(pMB, sad00);
587                                                    continue;
588                                    }
589                            } else sad00 = 256*4096; // skip not allowed - for final skip decision
590    
591                          if (bDirection & 4)                          SearchP(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
592                                  CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);                                                  y, current->motion_flags, pMB->quant,
593                                                    &Data, pParam, pMBs, reference->mbs,
594                                                    current->global_flags & XVID_INTER4V, pMB);
595    
596    /* final skip decision, a.k.a. "the vector you found, really that good?" */
597                            if (sad00 < pMB->quant * MAX_SAD00_FOR_SKIP)
598                                    if ((100*pMB->sad16)/(sad00+1) > FINAL_SKIP_THRESH)
599                                    { SkipMacroblockP(pMB, sad00); continue; }
600    
601                          if (bDirection & 8)  /* finally, intra decision */
                                 CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
602    
603                          /* now we're doing diagonal checks near our candidate */                          InterBias = MV16_INTER_BIAS;
604                            if (pMB->quant > 8)  InterBias += 50 * (pMB->quant - 8); // to make high quants work
605                            if (y != 0)
606                                    if ((pMB - pParam->mb_width)->mode == MODE_INTER ) InterBias -= 50;
607                            if (x != 0)
608                                    if ((pMB - 1)->mode == MODE_INTER ) InterBias -= 50;
609    
610                          if (iDirection)         //checking if anything found                          if (InterBias < pMB->sad16)  {
611                          {                                  const int32_t deviation =
612                                  bDirection = iDirection;                                          dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,
613                                  iDirection = 0;                                                    pParam->edged_width);
                                 start_x = currMV->x;  
                                 start_y = currMV->y;  
                                 if (bDirection & 3)     //our candidate is left or right  
                                 {  
                                         CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);  
                                 } else                  // what remains here is up or down  
                                 {  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
                                 }  
614    
615                                  if (iDirection) {                                  if (deviation < (pMB->sad16 - InterBias)) {
616                                          bDirection += iDirection;                                          if (++iIntra >= iLimit) return 1;
617                                          start_x = currMV->x;                                          pMB->mode = MODE_INTRA;
618                                          start_y = currMV->y;                                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =
619                                  }                                                          pMB->mvs[3] = zeroMV;
620                          } else                          //about to quit, eh? not so fast....                                          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =
621                          {                                                  pMB->sad8[3] = 0;
                                 switch (bDirection) {  
                                 case 2:  
                                         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 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;  
622                                  }                                  }
623                          }                          }
624                  }                  }
                 while (1);                              //forever  
625          }          }
626          return iMinSAD;          return 0;
627  }  }
628    
629    
630  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);  
631    
632          return iMinSAD;  static __inline int
633    make_mask(const VECTOR * const pmv, const int i)
634    {
635            int mask = 255, j;
636            for (j = 0; j < i; j++) {
637                    if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already
638                    if (pmv[i].x == pmv[j].x) {
639                            if (pmv[i].y == pmv[j].y + iDiamondSize) { mask &= ~4; continue; }
640                            if (pmv[i].y == pmv[j].y - iDiamondSize) { mask &= ~8; continue; }
641                    } else
642                            if (pmv[i].y == pmv[j].y) {
643                                    if (pmv[i].x == pmv[j].x + iDiamondSize) { mask &= ~1; continue; }
644                                    if (pmv[i].x == pmv[j].x - iDiamondSize) { mask &= ~2; continue; }
645                            }
646            }
647            return mask;
648  }  }
649    
650  Halfpel8_RefineFuncPtr Halfpel8_Refine;  static __inline void
651    PreparePredictionsP(VECTOR * const pmv, int x, int y, const int iWcount,
652  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)  
653  {  {
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
654    
655          int32_t iSAD;  //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself
         VECTOR backupMV = *currMV;  
656    
657          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y - 1);          if ( (y != 0) && (x != (iWcount-1)) ) {         // [5] top-right neighbour
658          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y - 1);                  pmv[5].x = EVEN(pmv[3].x);
659          CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y - 1);                  pmv[5].y = EVEN(pmv[3].y);
660          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);  
661    
662          return iMinSAD;          if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }// pmv[3] is left neighbour
663  }          else pmv[3].x = pmv[3].y = 0;
664    
665  #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
666        else pmv[4].x = pmv[4].y = 0;
667    
668            // [1] median prediction
669            pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
670    
671            pmv[0].x = pmv[0].y = 0; // [0] is zero; not used in the loop (checked before) but needed here for make_mask
672    
673  int32_t          pmv[2].x = EVEN(prevMB->mvs[0].x); // [2] is last frame
674  PMVfastSearch16(const uint8_t * const pRef,          pmv[2].y = EVEN(prevMB->mvs[0].y);
                                 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;  
   
         VECTOR newMV;  
         VECTOR backupMV;                        /* just for PMVFAST */  
   
         VECTOR pmv[4];  
         int32_t psad[4];  
   
         MainSearch16FuncPtr MainSearchPtr;  
   
         const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;  
   
         int32_t threshA, threshB;  
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD;  
   
 /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
   
 /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  
   
         if (!(MotionFlags & PMV_HALFPEL16)) {  
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
         }  
   
         /* 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;  
   
         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_EXTSEARCH16) {  
 /* 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,  
                                                                   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;  
675    
676                          case 7:          if ((x != iWcount-1) && (y != iHcount-1)) {
677                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); //[6] right-down neighbour in last frame
678                                                                                     backupMV.y, 1);                  pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
679                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,          } else pmv[6].x = pmv[6].y = 0;
                                                                                  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;  
680  }  }
681    
682    static void
683    SearchP(const uint8_t * const pRef,
   
   
 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,  
684                           const uint8_t * const pRefH,                           const uint8_t * const pRefH,
685                           const uint8_t * const pRefV,                           const uint8_t * const pRefV,
686                           const uint8_t * const pRefHV,                           const uint8_t * const pRefHV,
687                           const IMAGE * const pCur,                           const IMAGE * const pCur,
688                           const int x,                           const int x,
689                           const int y,                           const int y,
                         const int start_x,  
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
690                           const uint32_t MotionFlags,                           const uint32_t MotionFlags,
691                           const uint32_t iQuant,                           const uint32_t iQuant,
692                           const uint32_t iFcode,                  SearchData * const Data,
693                           const MBParam * const pParam,                           const MBParam * const pParam,
694                           const MACROBLOCK * const pMBs,                           const MACROBLOCK * const pMBs,
695                           const MACROBLOCK * const prevMBs,                  const MACROBLOCK * const prevMBs,
696                           VECTOR * const currMV,                  int inter4v,
697                           VECTOR * const currPMV)                  MACROBLOCK * const pMB)
698  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const 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,  
                         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)  
 {  
 /* 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;  
699    
700          int32_t iDiamondSize = 1;          int i, iDirection = 255, mask, threshA;
701            VECTOR pmv[7];
702    
703          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)()
704          int32_t max_dx;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
705          int32_t min_dy;                                  pParam->width, pParam->height, Data->iFcode);
         int32_t max_dy;  
706    
707          VECTOR newMV;          Data->predMV = pmv[0];
708          VECTOR backupMV;          Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16;
709            Data->Ref = pRef + (x + Data->iEdgedWidth*y)*16;
710            Data->RefH = pRefH + (x + Data->iEdgedWidth*y) * 16;
711            Data->RefV = pRefV + (x + Data->iEdgedWidth*y) * 16;
712            Data->RefHV = pRefHV + (x + Data->iEdgedWidth*y) * 16;
713    
714          VECTOR pmv[4];          Data->iQuant = iQuant;
         int32_t psad[8];  
715    
716          const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);          if (!(MotionFlags & PMV_HALFPEL16)) {
717                    Data->min_dx = EVEN(Data->min_dx);
718                    Data->max_dx = EVEN(Data->max_dx);
719                    Data->min_dy = EVEN(Data->min_dy);
720                    Data->max_dy = EVEN(Data->max_dy); }
721    
722            if (pMB->dquant != NO_CHANGE) inter4v = 0;
723    
724            if (inter4v) CheckCandidate = CheckCandidate16;
725            else CheckCandidate = CheckCandidate16no4v;
726    
727            for(i = 0;  i < 5; i++) Data->currentMV[i].x = Data->currentMV[i].y = 0;
728    
729            i = d_mv_bits(Data->predMV.x, Data->predMV.y, Data->iFcode);
730            Data->iMinSAD[0] = pMB->sad16 + lambda_vec16[iQuant] * i;
731            Data->iMinSAD[1] = pMB->sad8[0] + lambda_vec8[iQuant] * i;
732            Data->iMinSAD[2] = pMB->sad8[1];
733            Data->iMinSAD[3] = pMB->sad8[2];
734            Data->iMinSAD[4] = pMB->sad8[3];
735    
736  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          if ((x == 0) && (y == 0)) threshA = 512;
737          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;          else {
738                    threshA = Data->temp[0]; // that's when we keep this SAD atm
739                    if (threshA < 512) threshA = 512;
740                    if (threshA > 1024) threshA = 1024; }
741    
742          int32_t bPredEq;          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
743          int32_t iMinSAD, iSAD = 9999;                                          prevMBs + x + y * pParam->mb_width);
744    
745          MainSearch8FuncPtr MainSearchPtr;          if (inter4v) CheckCandidate = CheckCandidate16;
746            else CheckCandidate = CheckCandidate16no4v;
747    
 /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,  
                           iFcode);  
748    
749  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  /* main loop. checking all predictions */
750    
751          if (!(MotionFlags & PMV_HALFPEL8)) {          for (i = 1; i < 7; i++) {
752                  min_dx = EVEN(min_dx);                  if (!(mask = make_mask(pmv, i)) ) continue;
753                  max_dx = EVEN(max_dx);                  (*CheckCandidate)(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
754                  min_dy = EVEN(min_dy);                  if (Data->iMinSAD[0] <= threshA) break;
                 max_dy = EVEN(max_dy);  
755          }          }
         /* 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);  
756    
757            if ((Data->iMinSAD[0] <= threshA) ||
758                            (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
759                            (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16))) {
760                    inter4v = 0;
761            } else {
762    
763  /* Step 4: Calculate SAD around the Median prediction.                  MainSearchFunc * MainSearchPtr;
764          MinSAD=SAD                  if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
765          If Motion Vector equal to Previous frame motion vector                  else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
766                  and MinSAD<PrevFrmSAD goto Step 10.                          else MainSearchPtr = DiamondSearch;
767          If SAD<=256 goto Step 10.  
768  */                  (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
769    
770  // Prepare for main loop  /* extended search, diamond starting in 0,0 and in prediction.
771            note that this search is/might be done in halfpel positions,
772            which makes it more different than the diamond above */
773    
774          if (!(MotionFlags & PMV_HALFPEL8)) {                  if (MotionFlags & PMV_EXTSEARCH16) {
775                  currMV->x = EVEN(currMV->x);                          int32_t bSAD;
776                  currMV->y = EVEN(currMV->y);                          VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
777                            if (!(MotionFlags & PMV_HALFPELREFINE16)) // who's gonna use extsearch and no halfpel?
778                                    startMV.x = EVEN(startMV.x); startMV.y = EVEN(startMV.y);
779                            if (!(MVequal(startMV, backupMV))) {
780                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
781    
782                                    CheckCandidate16(startMV.x, startMV.y, 255, &iDirection, Data);
783                                    (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
784                                    if (bSAD < Data->iMinSAD[0]) {
785                                            Data->currentMV[0] = backupMV;
786                                            Data->iMinSAD[0] = bSAD; }
787                            }
788    
789                            backupMV = Data->currentMV[0];
790                            if (MotionFlags & PMV_HALFPELREFINE16) startMV.x = startMV.y = 1;
791                            else startMV.x = startMV.y = 0;
792                            if (!(MVequal(startMV, backupMV))) {
793                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
794    
795                                    CheckCandidate16(startMV.x, startMV.y, 255, &iDirection, Data);
796                                    (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
797                                    if (bSAD < Data->iMinSAD[0]) {
798                                            Data->currentMV[0] = backupMV;
799                                            Data->iMinSAD[0] = bSAD; }
800                            }
801          }          }
   
         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;  
802          }          }
803    
804  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/          if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(Data);
805    
806            if (inter4v) {
807  // MV=(0,0) is often a good choice                  SearchData Data8;
808          CHECK_MV8_ZERO;                  Data8.iFcode = Data->iFcode;
809                    Data8.iQuant = Data->iQuant;
810                    Data8.iEdgedWidth = Data->iEdgedWidth;
811                    Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
812                    Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
813                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
814                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
815            }
816    
817            if (!(inter4v) ||
818                    (Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
819                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {
820    // INTER MODE
821                    pMB->mode = MODE_INTER;
822                    pMB->mvs[0] = pMB->mvs[1]
823                            = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
824    
825  // previous frame MV                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
826          CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x, prevMB->mvs[iSubBlock].y);                          pMB->sad8[2] = pMB->sad8[3] =  Data->iMinSAD[0];
827    
828  // left neighbour, if allowed                  pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
829          if (psad[1] != MV_MAX_ERROR) {                  pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
830                  if (!(MotionFlags & PMV_HALFPEL8)) {          } else {
831                          pmv[1].x = EVEN(pmv[1].x);  // INTER4V MODE; all other things are already set in Search8
832                          pmv[1].y = EVEN(pmv[1].y);                  pMB->mode = MODE_INTER4V;
833                  }                  pMB->sad16 = Data->iMinSAD[1] + Data->iMinSAD[2] +
834                  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);  
835                  }                  }
                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
836    
 // 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);  
                 }  
837          }          }
838    
839  /*  // this bias is zero anyway, at the moment!  static void
840    Search8(const SearchData * const OldData,
841                    const int x, const int y,
842                    const uint32_t MotionFlags,
843                    const MBParam * const pParam,
844                    MACROBLOCK * const pMB,
845                    const MACROBLOCK * const pMBs,
846                    const int block,
847                    SearchData * const Data)
848    {
849            Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2 , y/2, block);
850            Data->iMinSAD = OldData->iMinSAD + 1 + block;
851            Data->currentMV = OldData->currentMV + 1 + block;
852    
853          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)          if (block != 0)
854                  iMinSAD -= MV8_00_BIAS;                  *(Data->iMinSAD) += lambda_vec8[Data->iQuant] *
855                                                                    d_mv_bits(      Data->currentMV->x - Data->predMV.x,
856                                                                                            Data->currentMV->y - Data->predMV.y,
857                                                                                            Data->iFcode);
858    
859  */          if (MotionFlags & (PMV_EXTSEARCH8|PMV_HALFPELREFINE8)) {
860    
861  /* Terminate if MinSAD <= T_2                  Data->Ref = OldData->Ref + 8 * ((block&1) + pParam->edged_width*(block>>1));
862     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));
863  */                  Data->RefV = OldData->RefV + 8 * ((block&1) + pParam->edged_width*(block>>1));
864                    Data->RefHV = OldData->RefHV + 8 * ((block&1) + pParam->edged_width*(block>>1));
865    
866          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;  
         }  
867    
868  /************ (Diamond Search)  **************/                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
869                                    pParam->width, pParam->height, OldData->iFcode);
870    
871          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                  CheckCandidate = CheckCandidate8;
872    
873          if (!(MotionFlags & PMV_HALFPELDIAMOND8))                  if (MotionFlags & PMV_EXTSEARCH8) {
                 iDiamondSize *= 2;  
874    
875  /* default: use best prediction as starting point for one call of EPZS_MainSearch */                          MainSearchFunc *MainSearchPtr;
876                            if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
877                                    else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
878                                            else MainSearchPtr = DiamondSearch;
879    
880  // there is no EPZS^2 for inter4v at the moment                          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);    }
881    
882    if (MotionFlags & PMV_USESQUARES8)                  if (MotionFlags & PMV_HALFPELREFINE8) HalfpelRefine(Data);
883        MainSearchPtr = Square8_MainSearch;          }
   else  
884    
885          if (MotionFlags & PMV_ADVANCEDDIAMOND8)          pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
886                  MainSearchPtr = AdvDiamond8_MainSearch;          pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
887          else          pMB->mvs[block] = *(Data->currentMV);
888                  MainSearchPtr = Diamond8_MainSearch;          pMB->sad8[block] =  4 * (*Data->iMinSAD);
889    
890          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);  
891    
892    /* B-frames code starts here */
893    
894          if (iSAD < iMinSAD) {  static __inline VECTOR
895                  *currMV = newMV;  ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
896                  iMinSAD = iSAD;  {
897    /* the stupidiest function ever */
898            if (mode == MODE_FORWARD) return pMB->mvs[0];
899            else return pMB->b_mvs[0];
900          }          }
901    
902          if (MotionFlags & PMV_EXTSEARCH8) {  static void __inline
903  /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
904                                                            const uint32_t iWcount,
905                                                            const MACROBLOCK * const pMB,
906                                                            const uint32_t mode_curr)
907    {
908    
909                  if (!(MVequal(pmv[0], backupMV))) {          // [0] is prediction
910                          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);  
911    
912                          if (iSAD < iMinSAD) {          pmv[1].x = pmv[1].y = 0; // [1] is zero
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
                 }  
913    
914                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          pmv[2] = ChoosePred(pMB, mode_curr);
915                          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);  
916    
917                          if (iSAD < iMinSAD) {          if ((y != 0)&&(x != (int)(iWcount+1))) {                        // [3] top-right neighbour
918                                  *currMV = newMV;                  pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
919                                  iMinSAD = iSAD;                  pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
920                          }          } else pmv[3].x = pmv[3].y = 0;
                 }  
         }  
921    
922  /***************        Choose best MV found     **************/          if (y != 0) {
923                    pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
924                    pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
925            } else pmv[4].x = pmv[4].y = 0;
926    
927    EPZS8_Terminate_with_Refine:          if (x != 0) {
928          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step                  pmv[5] = ChoosePred(pMB-1, mode_curr);
929                  iMinSAD =                  pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
930                          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);  
931    
932    EPZS8_Terminate_without_Refine:          if ((x != 0)&&(y != 0)) {
933                    pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
934                    pmv[6].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
935            } else pmv[6].x = pmv[6].y = 0;
936    
937          currPMV->x = currMV->x - center_x;  // more?
         currPMV->y = currMV->y - center_y;  
         return iMinSAD;  
938  }  }
939    
940    
941    /* search backward or forward, for b-frames */
942  int32_t  static void
943  PMVfastIntSearch16(const uint8_t * const pRef,  SearchBF(       const uint8_t * const pRef,
944                                  const uint8_t * const pRefH,                                  const uint8_t * const pRefH,
945                                  const uint8_t * const pRefV,                                  const uint8_t * const pRefV,
946                                  const uint8_t * const pRefHV,                                  const uint8_t * const pRefHV,
947                                  const IMAGE * const pCur,                                  const IMAGE * const pCur,
948                                  const int x,                          const int x, const int y,
                                 const int y,  
                                 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,  
949                                  const uint32_t MotionFlags,                                  const uint32_t MotionFlags,
                                 const uint32_t iQuant,  
950                                  const uint32_t iFcode,                                  const uint32_t iFcode,
951                                  const MBParam * const pParam,                                  const MBParam * const pParam,
952                                  const MACROBLOCK * const pMBs,                          MACROBLOCK * const pMB,
953                                  const MACROBLOCK * const prevMBs,                          const VECTOR * const predMV,
954                                  VECTOR * const currMV,                          int32_t * const best_sad,
955                                  VECTOR * const currPMV)                          const int32_t mode_current,
956                            SearchData * const Data)
957  {  {
         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;  
958    
959          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;  
960    
961          VECTOR newMV;          int i, iDirection, mask;
962          VECTOR backupMV;          VECTOR pmv[7];
963            MainSearchFunc *MainSearchPtr;
964            *Data->iMinSAD = MV_MAX_ERROR;
965            Data->iFcode = iFcode;
966    
967          VECTOR pmv[4];          Data->Ref = pRef + (x + y * iEdgedWidth) * 16;
968          int32_t psad[4];          Data->RefH = pRefH + (x + y * iEdgedWidth) * 16;
969            Data->RefV = pRefV + (x + y * iEdgedWidth) * 16;
970            Data->RefHV = pRefHV + (x + y * iEdgedWidth) * 16;
971    
972          MainSearch16FuncPtr MainSearchPtr;          Data->predMV = *predMV;
973    
974          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,
975          MACROBLOCK *const pMB = pMBs + x + y * iWcount;                                  pParam->width, pParam->height, iFcode);
976    
977          int32_t threshA, threshB;          pmv[0] = Data->predMV;
978          int32_t bPredEq;          PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);
         int32_t iMinSAD, iSAD;  
979    
980            Data->currentMV->x = Data->currentMV->y = 0;
981    
982  /* Get maximum range */          CheckCandidate = CheckCandidate16no4v;
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
983    
984  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  // main loop. checking all predictions
985            for (i = 0; i < 8; i++) {
986                    if (!(mask = make_mask(pmv, i)) ) continue;
987                    CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
988            }
989    
990          if ((x == 0) && (y == 0)) {          if (MotionFlags & PMV_USESQUARES16)
991                  threshA = 512;                  MainSearchPtr = SquareSearch;
992                  threshB = 1024;          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
993                    MainSearchPtr = AdvDiamondSearch;
994                    else MainSearchPtr = DiamondSearch;
995    
996                  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;  
997    
998          } else {          HalfpelRefine(Data);
999    
1000                  bPredEq = get_ipmvdata(pMBs, iWcount, 0, x, y, 0, pmv, psad);  // three bits are needed to code backward mode. four for forward
1001    // we treat the bits just like they were vector's
1002            if (mode_current == MODE_FORWARD) *Data->iMinSAD +=  4 * lambda_vec16[Data->iQuant];
1003            else *Data->iMinSAD +=  3 * lambda_vec16[Data->iQuant];
1004    
                 threshA = psad[0];  
                 threshB = threshA + 256;  
                 if (threshA < 512)  
                         threshA = 512;  
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
1005    
1006                  *currMV = pmv[0];                       /* current best := prediction */          if (*Data->iMinSAD < *best_sad) {
1007                    *best_sad = *Data->iMinSAD;
1008                    pMB->mode = mode_current;
1009                    pMB->pmvs[0].x = Data->currentMV->x - predMV->x;
1010                    pMB->pmvs[0].y = Data->currentMV->y - predMV->y;
1011                    if (mode_current == MODE_FORWARD) pMB->mvs[0] = *Data->currentMV;
1012                    else pMB->b_mvs[0] = *Data->currentMV;
1013          }          }
1014    
         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.  
 */  
   
         if (currMV->x > max_dx) {  
                 currMV->x = EVEN(max_dx);  
         }  
         if (currMV->x < min_dx) {  
                 currMV->x = EVEN(min_dx);  
         }  
         if (currMV->y > max_dy) {  
                 currMV->y = EVEN(max_dy);  
         }  
         if (currMV->y < min_dy) {  
                 currMV->y = EVEN(min_dy);  
1015          }          }
1016    
1017          iMinSAD =  static int32_t
1018                  sad16(cur,  SearchDirect(const IMAGE * const f_Ref,
1019                            get_iref_mv(pRef, x, y, 16, currMV,                                  const uint8_t * const f_RefH,
1020                                                   iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);                                  const uint8_t * const f_RefV,
1021          iMinSAD +=                                  const uint8_t * const f_RefHV,
1022                  calc_delta_16(currMV->x - center_x, currMV->y - center_y,                                  const IMAGE * const b_Ref,
1023                                            (uint8_t) iFcode, iQuant);                                  const uint8_t * const b_RefH,
1024                                    const uint8_t * const b_RefV,
1025                                    const uint8_t * const b_RefHV,
1026                                    const IMAGE * const pCur,
1027                                    const int x, const int y,
1028                                    const uint32_t MotionFlags,
1029                                    const int32_t TRB, const int32_t TRD,
1030                                    const MBParam * const pParam,
1031                                    MACROBLOCK * const pMB,
1032                                    const MACROBLOCK * const b_mb,
1033                                    int32_t * const best_sad,
1034                                    SearchData * const Data)
1035    
1036    {
1037            int32_t skip_sad;
1038            int k;
1039    
1040            MainSearchFunc *MainSearchPtr;
1041    
1042            *Data->iMinSAD = 256*4096;
1043            Data->referencemv = b_mb->mvs;
1044    
1045            Data->Ref = f_Ref->y + (x + Data->iEdgedWidth*y) * 16;
1046            Data->RefH = f_RefH + (x + Data->iEdgedWidth*y) * 16;
1047            Data->RefV = f_RefV + (x + Data->iEdgedWidth*y) * 16;
1048            Data->RefHV = f_RefHV + (x + Data->iEdgedWidth*y) * 16;
1049            Data->bRef = b_Ref->y + (x + Data->iEdgedWidth*y) * 16;
1050            Data->bRefH = b_RefH + (x + Data->iEdgedWidth*y) * 16;
1051            Data->bRefV = b_RefV + (x + Data->iEdgedWidth*y) * 16;
1052            Data->bRefHV = b_RefHV + (x + Data->iEdgedWidth*y) * 16;
1053    
1054            Data->max_dx = 2 * pParam->width - 2 * (x) * 16;
1055            Data->max_dy = 2 * pParam->height - 2 * (y) * 16;
1056            Data->min_dx = -(2 * 16 + 2 * (x) * 16);
1057            Data->min_dy = -(2 * 16 + 2 * (y) * 16);
1058    
1059          if ((iMinSAD < 256) ||          for (k = 0; k < 4; k++) {
1060                  ((MVequal(*currMV, prevMB->i_mvs[0])) &&                  pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);
1061                   ((int32_t) iMinSAD < prevMB->i_sad16))) {                  pMB->b_mvs[k].x = Data->directmvB[k].x = ((TRB - TRD) * Data->referencemv[k].x) / TRD;
1062                  if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode                  pMB->mvs[k].y = Data->directmvF[k].y = ((TRB * Data->referencemv[k].y) / TRD);
1063                  {                  pMB->b_mvs[k].y = Data->directmvB[k].y = ((TRB - TRD) * Data->referencemv[k].y) / TRD;
1064                          if (!MVzero(*currMV)) {  
1065                                  iMinSAD += MV16_00_BIAS;                  if ( ( pMB->b_mvs[k].x > Data->max_dx ) || ( pMB->b_mvs[k].x < Data->min_dx )
1066                                  CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures                          || ( pMB->b_mvs[k].y > Data->max_dy ) || ( pMB->b_mvs[k].y < Data->min_dy )) {
1067                                  iMinSAD -= MV16_00_BIAS;  
1068                            *best_sad = 256*4096; // in that case, we won't use direct mode
1069                            pMB->mode = MODE_DIRECT; // just to make sure it doesn't say "MODE_DIRECT_NONE_MV"
1070                            pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;
1071                            return 0;
1072                          }                          }
1073                    if (b_mb->mode != MODE_INTER4V) {
1074                            pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mvs[0];
1075                            pMB->b_mvs[1] = pMB->b_mvs[2] = pMB->b_mvs[3] = pMB->b_mvs[0];
1076                            Data->directmvF[1] = Data->directmvF[2] = Data->directmvF[3] = Data->directmvF[0];
1077                            Data->directmvB[1] = Data->directmvB[2] = Data->directmvB[3] = Data->directmvB[0];
1078                            break;
1079                  }                  }
   
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfastInt16_Terminate_with_Refine;  
1080          }          }
1081    
1082            if (b_mb->mode == MODE_INTER4V)
1083                    CheckCandidate = CheckCandidateDirect;
1084            else CheckCandidate = CheckCandidateDirectno4v;
1085    
1086  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion          (*CheckCandidate)(0, 0, 255, &k, Data);
    vector of the median.  
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
   
         if ((bPredEq) && (MVequal(pmv[0], prevMB->i_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 = 2;               // halfpel units!  
         else  
                 iDiamondSize = 4;               // halfpel units!  
   
 /*  
    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.  
 */  
1087    
1088  // (0,0) is often a good choice  // skip decision
1089            if (*Data->iMinSAD - 2 * lambda_vec16[Data->iQuant] < (int32_t)Data->iQuant * SKIP_THRESH_B) {
1090                    //checking chroma. everything copied from MC
1091                    //this is not full chroma compensation, only it's fullpel approximation. should work though
1092                    int sum, dx, dy, b_dx, b_dy;
1093    
1094          if (!MVzero(pmv[0]))                  sum = pMB->mvs[0].x + pMB->mvs[1].x + pMB->mvs[2].x + pMB->mvs[3].x;
1095                  CHECK_MV16_ZERO;                  dx = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1096    
1097  // previous frame MV is always possible                  sum = pMB->mvs[0].y + pMB->mvs[1].y + pMB->mvs[2].y + pMB->mvs[3].y;
1098                    dy = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1099    
1100          if (!MVzero(prevMB->i_mvs[0]))                  sum = pMB->b_mvs[0].x + pMB->b_mvs[1].x + pMB->b_mvs[2].x + pMB->b_mvs[3].x;
1101                  if (!MVequal(prevMB->i_mvs[0], pmv[0]))                  b_dx = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
                         CHECK_MV16_CANDIDATE(prevMB->i_mvs[0].x, prevMB->i_mvs[0].y);  
1102    
1103  // left neighbour, if allowed                  sum = pMB->b_mvs[0].y + pMB->b_mvs[1].y + pMB->b_mvs[2].y + pMB->b_mvs[3].y;
1104                    b_dy = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1105    
1106          if (!MVzero(pmv[1]))                  sum = sad8bi(pCur->u + 8*x + 8*y*(Data->iEdgedWidth/2),
1107                  if (!MVequal(pmv[1], prevMB->i_mvs[0]))                                          f_Ref->u + (y*8 + dy/2) * (Data->iEdgedWidth/2) + x*8 + dx/2,
1108                          if (!MVequal(pmv[1], pmv[0]))                                          b_Ref->u + (y*8 + b_dy/2) * (Data->iEdgedWidth/2) + x*8 + b_dx/2,
1109                                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);                                          Data->iEdgedWidth/2);
1110                    sum += sad8bi(pCur->v + 8*x + 8*y*(Data->iEdgedWidth/2),
1111                                            f_Ref->v + (y*8 + dy/2) * (Data->iEdgedWidth/2) + x*8 + dx/2,
1112                                            b_Ref->v + (y*8 + b_dy/2) * (Data->iEdgedWidth/2) + x*8 + b_dx/2,
1113                                            Data->iEdgedWidth/2);
1114    
1115  // top neighbour, if allowed                  if ((uint32_t) sum < MAX_CHROMA_SAD_FOR_SKIP * Data->iQuant) {
1116          if (!MVzero(pmv[2]))                          pMB->mode = MODE_DIRECT_NONE_MV;
1117                  if (!MVequal(pmv[2], prevMB->i_mvs[0]))                          return *Data->iMinSAD;
1118                          if (!MVequal(pmv[2], pmv[0]))                  }
1119                                  if (!MVequal(pmv[2], pmv[1]))          }
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
1120    
1121  // top right neighbour, if allowed          skip_sad = *Data->iMinSAD;
                                         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);  
1122    
1123          if ((MVzero(*currMV)) &&  //  DIRECT MODE DELTA VECTOR SEARCH.
1124                  (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  //      This has to be made more effective, but at the moment I'm happy it's running at all
                 iMinSAD -= MV16_00_BIAS;  
1125    
1126            if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1127                    else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1128                            else MainSearchPtr = DiamondSearch;
1129    
1130  /* Step 6: If MinSAD <= thresa goto Step 10.          (*MainSearchPtr)(0, 0, Data, 255);
    If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
 */  
1131    
1132          if ((iMinSAD <= threshA) ||          HalfpelRefine(Data);
                 (MVequal(*currMV, prevMB->i_mvs[0]) &&  
                  ((int32_t) iMinSAD < prevMB->i_sad16))) {  
1133    
1134                  if (MotionFlags & PMV_EARLYSTOP16)          *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
1135                          goto PMVfastInt16_Terminate_with_Refine;          *best_sad = *Data->iMinSAD;
         }  
1136    
1137            if (b_mb->mode == MODE_INTER4V)
1138                    pMB->mode = MODE_DIRECT;
1139            else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation
1140    
1141  /************ (Diamond Search)  **************/          pMB->pmvs[3] = *Data->currentMV;
 /*  
    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.  
 */  
1142    
1143          if (MotionFlags & PMV_USESQUARES16)          for (k = 0; k < 4; k++) {
1144                  MainSearchPtr = Square16_MainSearch;                  pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
1145          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)                  pMB->b_mvs[k].x = ((Data->currentMV->x == 0)
1146                  MainSearchPtr = AdvDiamond16_MainSearch;                                                          ? Data->directmvB[k].x
1147          else                                                          : pMB->mvs[k].x - Data->referencemv[k].x);
1148                  MainSearchPtr = Diamond16_MainSearch;                  pMB->mvs[k].y = (Data->directmvF[k].y + Data->currentMV->y);
1149                    pMB->b_mvs[k].y = ((Data->currentMV->y == 0)
1150          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                                                          ? Data->directmvB[k].y
1151                                                            : pMB->mvs[k].y - Data->referencemv[k].y);
1152                    if (b_mb->mode != MODE_INTER4V) {
1153  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                          pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1154          iSAD =                          pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1155                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,                          break;
                                                   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;  
1156          }          }
   
         if (MotionFlags & PMV_EXTSEARCH16) {  
 /* 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;  
1157                          }                          }
1158            return skip_sad;
1159                  }                  }
1160    
                 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;  
                         }  
                 }  
         }  
1161    
1162  /*  static __inline void
1163     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  SearchInterpolate(const uint8_t * const f_Ref,
1164  */                                  const uint8_t * const f_RefH,
1165                                    const uint8_t * const f_RefV,
1166                                    const uint8_t * const f_RefHV,
1167                                    const uint8_t * const b_Ref,
1168                                    const uint8_t * const b_RefH,
1169                                    const uint8_t * const b_RefV,
1170                                    const uint8_t * const b_RefHV,
1171                                    const IMAGE * const pCur,
1172                                    const int x, const int y,
1173                                    const uint32_t fcode,
1174                                    const uint32_t bcode,
1175                                    const uint32_t MotionFlags,
1176                                    const MBParam * const pParam,
1177                                    const VECTOR * const f_predMV,
1178                                    const VECTOR * const b_predMV,
1179                                    MACROBLOCK * const pMB,
1180                                    int32_t * const best_sad,
1181                                    SearchData * const fData)
1182    
1183  PMVfastInt16_Terminate_with_Refine:  {
1184    
1185          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;  
1186    
1187          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step          int iDirection, i, j;
1188                  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);  
1189    
1190          pmv[0] = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          // get _REAL_ prediction (halfpel possible)          bData.iMinSAD = fData->iMinSAD;
1191            *bData.iMinSAD = 4096*256;
1192            bData.Cur = fData->Cur;
1193            fData->iEdgedWidth = bData.iEdgedWidth = iEdgedWidth;
1194            bData.currentMV = fData->currentMV + 1;
1195            bData.iQuant = fData->iQuant;
1196            fData->iFcode = bData.bFcode = fcode; fData->bFcode = bData.iFcode = bcode;
1197    
1198            bData.bRef = fData->Ref = f_Ref + (x + y * iEdgedWidth) * 16;
1199            bData.bRefH = fData->RefH = f_RefH + (x + y * iEdgedWidth) * 16;
1200            bData.bRefV = fData->RefV = f_RefV + (x + y * iEdgedWidth) * 16;
1201            bData.bRefHV = fData->RefHV = f_RefHV + (x + y * iEdgedWidth) * 16;
1202            bData.Ref = fData->bRef = b_Ref + (x + y * iEdgedWidth) * 16;
1203            bData.RefH = fData->bRefH = b_RefH + (x + y * iEdgedWidth) * 16;
1204            bData.RefV = fData->bRefV = b_RefV + (x + y * iEdgedWidth) * 16;
1205            bData.RefHV = fData->bRefHV = b_RefHV + (x + y * iEdgedWidth) * 16;
1206    
1207            bData.bpredMV = fData->predMV = *f_predMV;
1208            fData->bpredMV = bData.predMV = *b_predMV;
1209    
1210            fData->currentMV[0] = pMB->mvs[0];
1211            fData->currentMV[1] = pMB->b_mvs[0];
1212            get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode);
1213            get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode);
1214    
1215            if (fData->currentMV[0].x > fData->max_dx) fData->currentMV[0].x = fData->max_dx;
1216            if (fData->currentMV[0].x < fData->min_dx) fData->currentMV[0].x = fData->min_dy;
1217            if (fData->currentMV[0].y > fData->max_dy) fData->currentMV[0].y = fData->max_dx;
1218            if (fData->currentMV[0].y > fData->min_dy) fData->currentMV[0].y = fData->min_dy;
1219    
1220            if (fData->currentMV[1].x > bData.max_dx) fData->currentMV[1].x = bData.max_dx;
1221            if (fData->currentMV[1].x < bData.min_dx) fData->currentMV[1].x = bData.min_dy;
1222            if (fData->currentMV[1].y > bData.max_dy) fData->currentMV[1].y = bData.max_dx;
1223            if (fData->currentMV[1].y > bData.min_dy) fData->currentMV[1].y = bData.min_dy;
1224    
1225  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;  
 }  
1226    
1227    //diamond. I wish we could use normal mainsearch functions (square, advdiamond)
1228    
1229            do {
1230                    iDirection = 255;
1231                    // forward MV moves
1232                    i = fData->currentMV[0].x; j = fData->currentMV[0].y;
1233    
1234                    CheckCandidateInt(i + 1, j, 0, &iDirection, fData);
1235                    CheckCandidateInt(i, j + 1, 0, &iDirection, fData);
1236                    CheckCandidateInt(i - 1, j, 0, &iDirection, fData);
1237                    CheckCandidateInt(i, j - 1, 0, &iDirection, fData);
1238    
1239                    // backward MV moves
1240                    i = fData->currentMV[1].x; j = fData->currentMV[1].y;
1241                    fData->currentMV[2] = fData->currentMV[0];
1242    
1243                    CheckCandidateInt(i + 1, j, 0, &iDirection, &bData);
1244                    CheckCandidateInt(i, j + 1, 0, &iDirection, &bData);
1245                    CheckCandidateInt(i - 1, j, 0, &iDirection, &bData);
1246                    CheckCandidateInt(i, j - 1, 0, &iDirection, &bData);
1247    
1248            } while (!(iDirection));
1249    
1250    // two bits are needed to code interpolate mode. we treat the bits just like they were vector's
1251            *fData->iMinSAD +=  2 * lambda_vec16[fData->iQuant];
1252            if (*fData->iMinSAD < *best_sad) {
1253                    *best_sad = *fData->iMinSAD;
1254                    pMB->mvs[0] = fData->currentMV[0];
1255                    pMB->b_mvs[0] = fData->currentMV[1];
1256                    pMB->mode = MODE_INTERPOLATE;
1257    
1258                    pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;
1259                    pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;
1260                    pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;
1261                    pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;
1262            }
1263    }
1264    
 /* ***********************************************************  
         bvop motion estimation  
 ***************************************************************/  
1265    
1266  void  void
1267  MotionEstimationBVOP(MBParam * const pParam,  MotionEstimationBVOP(MBParam * const pParam,
# Line 3138  Line 1281 
1281                                           const IMAGE * const b_refV,                                           const IMAGE * const b_refV,
1282                                           const IMAGE * const b_refHV)                                           const IMAGE * const b_refHV)
1283  {  {
1284          const int mb_width = pParam->mb_width;          uint32_t i, j;
1285          const int mb_height = pParam->mb_height;          int32_t best_sad, skip_sad;
1286          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;  
   
1287          static const VECTOR zeroMV={0,0};          static const VECTOR zeroMV={0,0};
1288    
         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;  
   
1289          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;  
1290    
1291          int min_dx, max_dx, min_dy, max_dy;          const int32_t TRB = time_pp - time_bp;
1292          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;  
1293    
1294          const int64_t TRB = (int32_t)time_pp - (int32_t)time_bp;  // some pre-inintialized data for the rest of the search
1295      const int64_t TRD = (int32_t)time_pp;  
1296            SearchData Data;
1297            int32_t iMinSAD;
1298            VECTOR currentMV[3];
1299            Data.iEdgedWidth = pParam->edged_width;
1300            Data.currentMV = currentMV;
1301            Data.iMinSAD = &iMinSAD;
1302            Data.iQuant = frame->quant;
1303    
         // fprintf(stderr,"TRB = %lld  TRD = %lld  time_bp =%d time_pp =%d\n\n",TRB,TRD,time_bp,time_pp);  
1304          // note: i==horizontal, j==vertical          // note: i==horizontal, j==vertical
         for (j = 0; j < mb_height; j++) {  
1305    
1306                  f_predMV = zeroMV;      /* prediction is reset at left boundary */          for (j = 0; j < pParam->mb_height; j++) {
                 b_predMV = zeroMV;  
1307    
1308                  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];  
1309    
1310                          mb->deltamv=zeroMV;                  for (i = 0; i < pParam->mb_width; i++) {
1311                            MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
1312                            const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
1313    
1314  /* 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 */
1315                            if (b_mb->mode == MODE_NOT_CODED) {
1316                          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;  
1317                                  continue;                                  continue;
1318                          }                          }
1319    
1320                          if (b_mb->mode == MODE_INTER4V)                          Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
1321                          {  /* direct search comes first, because it (1) checks for SKIP-mode
1322                                  d_sad16 = 0;          and (2) sets very good predictions for forward and backward search */
1323                          /* same method of scaling as in decoder.c, so we copy from there */  
1324                      for (k = 0; k < 4; k++) {                          skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
1325                                                                            b_ref, b_refH->y, b_refV->y, b_refHV->y,
1326                                          mb->directmv[k] = b_mb->mvs[k];                                                                          &frame->image,
1327                                                                            i, j,
1328                                                                            frame->motion_flags,
1329                                                                            TRB, TRD,
1330                                                                            pParam,
1331                                                                            pMB, b_mb,
1332                                                                            &best_sad,
1333                                                                            &Data);
1334    
1335                                          mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);                          if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
                     mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)  
                                                                                 ? ((TRB - TRD) * mb->directmv[k].x) / TRD  
                                             : mb->mvs[k].x - mb->directmv[k].x);  
   
                     mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);  
                         mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)  
                                                                                 ? ((TRB - TRD) * mb->directmv[k].y) / TRD  
                                             : mb->mvs[k].y - mb->directmv[k].y);  
   
                                         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];  
   
                                 mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);  
                     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);  
1336    
1337              }  //                      best_sad = 256*4096; //uncomment to disable Directsearch.
1338                      d_sad16 += calc_delta_16(mb->deltamv.x, mb->deltamv.y, 1, frame->quant);  //      To disable any other mode, just comment the function call
1339    
1340                          // forward search                          // forward search
1341                          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,
1342                                                  &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 */  
1343                                                  frame->motion_flags,                                                  frame->motion_flags,
1344                                                  frame->quant, frame->fcode, pParam,                                                  frame->fcode, pParam,
1345                                                  f_mbs, f_mbs,                                                  pMB, &f_predMV, &best_sad,
1346                                                  &mb->mvs[0], &pmv_dontcare);                                                  MODE_FORWARD, &Data);
   
1347    
1348                          // backward search                          // backward search
1349                          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,
1350                                                  &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 */  
1351                                                  frame->motion_flags,                                                  frame->motion_flags,
1352                                                  frame->quant, frame->bcode, pParam,                                                  frame->bcode, pParam,
1353                                                  b_mbs, b_mbs,                                                  pMB, &b_predMV, &best_sad,
1354                                                  &mb->b_mvs[0], &pmv_dontcare);                                                  MODE_BACKWARD, &Data);
1355    
1356                          i_sad16 =                          // interpolate search comes last, because it uses data from forward and backward as prediction
1357                                  sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,  
1358                                                    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,  
1359                                                  b_ref->y, b_refH->y, b_refV->y, b_refHV->y,                                                  b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
1360                                                    &frame->image,
1361                                                  i, j,                                                  i, j,
1362                                                  TRB,TRD,                                                  frame->fcode, frame->bcode,
1363                                                  mb->deltamv.x, mb->deltamv.y,                                                  frame->motion_flags,
1364                                                  d_sad16,                                                  pParam,
1365                                                  &mb->deltamv,                                                  &f_predMV, &b_predMV,
1366                                                  mb->directmv, // this has to be pre-initialized with b_mb->mvs[]                                                  pMB, &best_sad,
1367                                          min_dx, max_dx, min_dy, max_dy,                                                  &Data);
1368                                                  edged_width, 1, frame->quant, 0);               // equiv to halfpel refine  
1369                            switch (pMB->mode) {
1370                                    case MODE_FORWARD:
1371  //                      i_sad16 = 65535;                /* remove the comment to disable any of the MODEs */                                          f_count++;
1372  //                      f_sad16 = 65535;                                          f_predMV = pMB->mvs[0];
1373  //                      b_sad16 = 65535;                                          break;
1374  //                      d_sad16 = 65535;                                  case MODE_BACKWARD:
1375                                            b_count++;
1376                          if (f_sad16 < b_sad16) {                                          b_predMV = pMB->b_mvs[0];
1377                                  best_sad = f_sad16;                                          break;
1378                                  mb->mode = MODE_FORWARD;                                  case MODE_INTERPOLATE:
1379                          } else {                                          i_count++;
1380                                  best_sad = b_sad16;                                          f_predMV = pMB->mvs[0];
1381                                  mb->mode = MODE_BACKWARD;                                          b_predMV = pMB->b_mvs[0];
1382                                            break;
1383                                    case MODE_DIRECT:
1384                                    case MODE_DIRECT_NO4V:
1385                                            d_count++;
1386                                            break;
1387                                    default:
1388                                            break;
1389                            }
1390                    }
1391                          }                          }
1392    
1393                          if (i_sad16 < best_sad) {  //      fprintf(debug,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d, N: %04d\n",
1394                                  best_sad = i_sad16;  //                              f_count,b_count,i_count,d_count,n_count);
1395                                  mb->mode = MODE_INTERPOLATE;  
1396                          }                          }
1397    
1398                          if (d_sad16 < best_sad) {  /* Hinted ME starts here */
1399    
1400                                  if (b_mb->mode == MODE_INTER4V)  static __inline void
1401    Search8hinted(  const SearchData * const OldData,
1402                                    const int x, const int y,
1403                                    const uint32_t MotionFlags,
1404                                    const MBParam * const pParam,
1405                                    MACROBLOCK * const pMB,
1406                                    const MACROBLOCK * const pMBs,
1407                                    const int block)
1408                                  {                                  {
1409            SearchData Data;
1410            MainSearchFunc *MainSearchPtr;
1411    
1412                                  /* 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);
1413                                  /* for the bitstream, the value mb->deltamv is read directly */          Data.iMinSAD = OldData->iMinSAD + 1 + block;
1414            Data.currentMV = OldData->currentMV+1+block;
1415            Data.iFcode = OldData->iFcode;
1416            Data.iQuant = OldData->iQuant;
1417    
1418                              for (k = 0; k < 4; k++) {          Data.Ref = OldData->Ref + 8 * ((block&1) + pParam->edged_width*(block>>1));
1419            Data.RefH = OldData->RefH + 8 * ((block&1) + pParam->edged_width*(block>>1));
1420            Data.RefV = OldData->RefV + 8 * ((block&1) + pParam->edged_width*(block>>1));
1421            Data.RefHV = OldData->RefHV + 8 * ((block&1) + pParam->edged_width*(block>>1));
1422            Data.iEdgedWidth = pParam->edged_width;
1423            Data.Cur = OldData->Cur + 8 * ((block&1) + pParam->edged_width*(block>>1));
1424    
1425                                                  mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);          CheckCandidate = CheckCandidate8;
                             mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)  
                                                                                         ? ((TRB - TRD) * mb->directmv[k].x) / TRD  
                                                     : mb->mvs[k].x - mb->directmv[k].x);  
1426    
1427                              mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);          if (block != 0)
1428                          mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)                  *(Data.iMinSAD) += lambda_vec8[Data.iQuant] *
1429                                                                                          ? ((TRB - TRD) * mb->directmv[k].y) / TRD                                                                  d_mv_bits(      Data.currentMV->x - Data.predMV.x,
1430                                              : mb->mvs[k].y - mb->directmv[k].y);                                                                                          Data.currentMV->y - Data.predMV.y,
1431                                          }                                                                                          Data.iFcode);
1432    
1433    
1434            get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 8,
1435                                    pParam->width, pParam->height, OldData->iFcode);
1436    
1437            if (pMB->mode == MODE_INTER4V) {
1438                    int dummy;
1439                    CheckCandidate8(pMB->mvs[block].x, pMB->mvs[block].y, 0, &dummy, &Data); }
1440    
1441            if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
1442                    else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1443                            else MainSearchPtr = DiamondSearch;
1444    
1445            (*MainSearchPtr)(Data.currentMV->x, Data.currentMV->y, &Data, 255);
1446    
1447            if (MotionFlags & PMV_HALFPELREFINE8) HalfpelRefine(&Data);
1448    
1449            pMB->pmvs[block].x = Data.currentMV->x - Data.predMV.x;
1450            pMB->pmvs[block].y = Data.currentMV->y - Data.predMV.y;
1451            pMB->mvs[block] = *(Data.currentMV);
1452            pMB->sad8[block] =  4 * (*(Data.iMinSAD));
1453                                  }                                  }
1454                                  else  
1455    
1456    static void
1457    SearchPhinted ( const uint8_t * const pRef,
1458                                    const uint8_t * const pRefH,
1459                                    const uint8_t * const pRefV,
1460                                    const uint8_t * const pRefHV,
1461                                    const IMAGE * const pCur,
1462                                    const int x,
1463                                    const int y,
1464                                    const uint32_t MotionFlags,
1465                                    const uint32_t iQuant,
1466                                    const MBParam * const pParam,
1467                                    const MACROBLOCK * const pMBs,
1468                                    int inter4v,
1469                                    MACROBLOCK * const pMB,
1470                                    SearchData * const Data)
1471                                  {                                  {
                                         mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);  
1472    
1473                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)          const int32_t iEdgedWidth = pParam->edged_width;
1474                                                                                  ? ((TRB - TRD) * mb->directmv[0].x) / TRD  
1475                                          : mb->mvs[0].x - mb->directmv[0].x);          int i, t;
1476            MainSearchFunc * MainSearchPtr;
1477    
1478            Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1479            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1480                                    pParam->width, pParam->height, Data->iFcode);
1481    
1482            Data->Cur = pCur->y + (x + y * iEdgedWidth) * 16;
1483            Data->Ref = pRef + (x + iEdgedWidth*y)*16;
1484            Data->RefH = pRefH + (x + iEdgedWidth*y) * 16;
1485            Data->RefV = pRefV + (x + iEdgedWidth*y) * 16;
1486            Data->RefHV = pRefHV + (x + iEdgedWidth*y) * 16;
1487            Data->iQuant = iQuant;
1488    
1489            if (!(MotionFlags & PMV_HALFPEL16)) {
1490                    Data->min_dx = EVEN(Data->min_dx);
1491                    Data->max_dx = EVEN(Data->max_dx);
1492                    Data->min_dy = EVEN(Data->min_dy);
1493                    Data->max_dy = EVEN(Data->max_dy);
1494            }
1495    
1496            for(i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;
1497    
1498            if (pMB->dquant != NO_CHANGE) inter4v = 0;
1499    
1500            if (inter4v)
1501                    CheckCandidate = CheckCandidate16;
1502            else CheckCandidate = CheckCandidate16no4v;
1503    
1504    
1505            pMB->mvs[0].x = EVEN(pMB->mvs[0].x);
1506            pMB->mvs[0].y = EVEN(pMB->mvs[0].y);
1507            if (pMB->mvs[0].x > Data->max_dx) pMB->mvs[0].x = Data->max_dx; // this is in case iFcode changed
1508            if (pMB->mvs[0].x < Data->min_dx) pMB->mvs[0].x = Data->min_dx;
1509            if (pMB->mvs[0].y > Data->max_dy) pMB->mvs[0].y = Data->max_dy;
1510            if (pMB->mvs[0].y < Data->min_dy) pMB->mvs[0].y = Data->min_dy;
1511    
1512            (*CheckCandidate)(pMB->mvs[0].x, pMB->mvs[0].y, 0, &t, Data);
1513    
1514            if (pMB->mode == MODE_INTER4V)
1515                    for (i = 1; i < 4; i++) { // all four vectors will be used as four predictions for 16x16 search
1516                            pMB->mvs[i].x = EVEN(pMB->mvs[i].x);
1517                            pMB->mvs[i].y = EVEN(pMB->mvs[i].y);
1518                            if (!(make_mask(pMB->mvs, i)))
1519                                    (*CheckCandidate)(pMB->mvs[i].x, pMB->mvs[i].y, 0, &t, Data);
1520                    }
1521    
1522            if (MotionFlags & PMV_USESQUARES16)
1523                    MainSearchPtr = SquareSearch;
1524            else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
1525                    MainSearchPtr = AdvDiamondSearch;
1526                    else MainSearchPtr = DiamondSearch;
1527    
1528            (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);
1529    
1530            if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(Data);
1531    
1532                              mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);          if (inter4v)
1533                    for(i = 0; i < 4; i++)
1534                            Search8hinted(Data, 2*x+(i&1), 2*y+(i>>1), MotionFlags, pParam, pMB, pMBs, i);
1535    
1536                          mb->b_mvs[0].y = (int32_t) ((mb->deltamv.y == 0)          if (!(inter4v) ||
1537                                                                                  ? ((TRB - TRD) * mb->directmv[0].y) / TRD                  (Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] + Data->iMinSAD[3] +
1538                                              : mb->mvs[0].y - mb->directmv[0].y);                                                          Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {
1539    // INTER MODE
1540    
1541                                          mb->mvs[3] = mb->mvs[2] = mb->mvs[1] = mb->mvs[0];                  pMB->mode = MODE_INTER;
1542                                          mb->b_mvs[3] = mb->b_mvs[2] = mb->b_mvs[1] = mb->b_mvs[0];                  pMB->mvs[0] = pMB->mvs[1]
1543                            = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
1544    
1545                    pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
1546                            pMB->sad8[2] = pMB->sad8[3] =  Data->iMinSAD[0];
1547    
1548                    pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1549                    pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
1550            } else {
1551    // INTER4V MODE; all other things are already set in Search8hinted
1552                    pMB->mode = MODE_INTER4V;
1553                    pMB->sad16 = Data->iMinSAD[1] + Data->iMinSAD[2] + Data->iMinSAD[3]
1554                                                    + Data->iMinSAD[4] + IMV16X16 * iQuant;
1555                  }                  }
1556    
                                 best_sad = d_sad16;  
                                 mb->mode = MODE_DIRECT;  
1557                          }                          }
1558    
1559                          switch (mb->mode)  void
1560    MotionEstimationHinted( MBParam * const pParam,
1561                                                    FRAMEINFO * const current,
1562                                                    FRAMEINFO * const reference,
1563                                                    const IMAGE * const pRefH,
1564                                                    const IMAGE * const pRefV,
1565                                                    const IMAGE * const pRefHV)
1566                          {                          {
1567                                  case MODE_FORWARD:          MACROBLOCK *const pMBs = current->mbs;
1568                                          f_count++;          const IMAGE *const pCurrent = &current->image;
1569                                          f_predMV = mb->mvs[0];          const IMAGE *const pRef = &reference->image;
                                         break;  
                                 case MODE_BACKWARD:  
                                         b_count++;  
                                         b_predMV = mb->b_mvs[0];  
1570    
1571                                          break;          uint32_t x, y;
1572                                  case MODE_INTERPOLATE:          int32_t temp[5];
1573                                          i_count++;          int32_t iMinSAD[5];
1574                                          mb->mvs[0] = f_interpolMV;          VECTOR currentMV[5];
1575                                          mb->b_mvs[0] = b_interpolMV;          SearchData Data;
1576                                          f_predMV = mb->mvs[0];          Data.iEdgedWidth = pParam->edged_width;
1577                                          b_predMV = mb->b_mvs[0];          Data.currentMV = currentMV;
1578                                          break;          Data.iMinSAD = iMinSAD;
1579                                  case MODE_DIRECT:          Data.temp = temp;
1580                                          d_count++;          Data.iFcode = current->fcode;
1581                                          break;  
1582                                  default:          if (sadInit) (*sadInit) ();
1583                                          break;  
1584            for (y = 0; y < pParam->mb_height; y++) {
1585                    for (x = 0; x < pParam->mb_width; x++)  {
1586    
1587                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1588    
1589    //intra mode is copied from the first pass. At least for the time being
1590                            if  ((pMB->mode == MODE_INTRA) || (pMB->mode == MODE_NOT_CODED) ) continue;
1591    
1592                            if (!(current->global_flags & XVID_LUMIMASKING)) {
1593                                    pMB->dquant = NO_CHANGE;
1594                                    pMB->quant = current->quant; }
1595    
1596                            SearchPhinted(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1597                                                            y, current->motion_flags, pMB->quant,
1598                                                            pParam, pMBs, current->global_flags & XVID_INTER4V, pMB,
1599                                                            &Data);
1600    
1601                    }
1602            }
1603    }
1604    
1605    static __inline int
1606    MEanalyzeMB (   const uint8_t * const pRef,
1607                                    const uint8_t * const pCur,
1608                                    const int x,
1609                                    const int y,
1610                                    const MBParam * const pParam,
1611                                    const MACROBLOCK * const pMBs,
1612                                    MACROBLOCK * const pMB,
1613                                    SearchData * const Data)
1614    {
1615    
1616            int i, mask;
1617            VECTOR pmv[3];
1618    
1619            *(Data->iMinSAD) = MV_MAX_ERROR;
1620            Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1621            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1622                                    pParam->width, pParam->height, Data->iFcode);
1623    
1624            Data->Cur = pCur + (x + y * pParam->edged_width) * 16;
1625            Data->Ref = pRef + (x + y * pParam->edged_width) * 16;
1626    
1627            CheckCandidate = CheckCandidate16no4vI;
1628    
1629            pmv[1].x = EVEN(pMB->mvs[0].x);
1630            pmv[1].y = EVEN(pMB->mvs[0].y);
1631            pmv[0].x = EVEN(Data->predMV.x);
1632            pmv[0].y = EVEN(Data->predMV.y);
1633            pmv[2].x = pmv[2].y = 0;
1634    
1635            CheckCandidate16no4vI(pmv[0].x, pmv[0].y, 255, &i, Data);
1636            if (!(mask = make_mask(pmv, 1)))
1637                    CheckCandidate16no4vI(pmv[1].x, pmv[1].y, mask, &i, Data);
1638            if (!(mask = make_mask(pmv, 2)))
1639                    CheckCandidate16no4vI(0, 0, mask, &i, Data);
1640    
1641            DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, i);
1642    
1643            pMB->mvs[0] = pMB->mvs[1]
1644                            = pMB->mvs[2] = pMB->mvs[3] = *Data->currentMV; // all, for future get_pmv()
1645    
1646            return *(Data->iMinSAD);
1647                          }                          }
1648    
1649    #define INTRA_THRESH    1350
1650    #define INTER_THRESH    900
1651    
1652    int
1653    MEanalysis(     const IMAGE * const pRef,
1654                            const IMAGE * const pCurrent,
1655                            MBParam * const pParam,
1656                            MACROBLOCK * const pMBs,
1657                            const uint32_t iFcode)
1658    {
1659            uint32_t x, y, intra = 0;
1660            int sSAD = 0;
1661    
1662            VECTOR currentMV;
1663            int32_t iMinSAD;
1664            SearchData Data;
1665            Data.iEdgedWidth = pParam->edged_width;
1666            Data.currentMV = &currentMV;
1667            Data.iMinSAD = &iMinSAD;
1668            Data.iFcode = iFcode;
1669            Data.iQuant = 2;
1670    
1671            if (sadInit) (*sadInit) ();
1672    
1673            for (y = 0; y < pParam->mb_height-1; y++) {
1674                    for (x = 0; x < pParam->mb_width; x++) {
1675                            int sad, dev;
1676                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1677    
1678                            sad = MEanalyzeMB(pRef->y, pCurrent->y, x, y,
1679                                                                    pParam, pMBs, pMB, &Data);
1680    
1681                            if ( x != 0 && y != 0 && x != pParam->mb_width-1 ) { //no edge macroblocks, they just don't work
1682                                    if (sad > INTRA_THRESH) {
1683                                            dev = dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,
1684                                                                      pParam->edged_width);
1685                                            if (dev + INTRA_THRESH < sad) intra++;
1686                                            if (intra > (pParam->mb_height-2)*(pParam->mb_width-2)/2) return 2;  // I frame
1687                  }                  }
1688                                    sSAD += sad;
1689          }          }
1690    
1691  #ifdef _DEBUG_BFRAME_STAT                  }
1692          fprintf(stderr,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d\n",          }
1693                                  f_count,b_count,i_count,d_count);          sSAD /= (pParam->mb_height-2)*(pParam->mb_width-2);
1694  #endif          if (sSAD > INTER_THRESH ) return 1; //P frame
1695            emms();
1696            return 0; // B frame
1697    
1698  }  }

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

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