[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

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

Legend:
Removed from v.337  
changed lines
  Added in v.662

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