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

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

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

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

Legend:
Removed from v.529  
changed lines
  Added in v.530

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