[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 300, Tue Jul 16 12:02:27 2002 UTC branches/dev-api-3/xvidcore/src/motion/motion_est.c revision 661, Tue Nov 19 13:43:00 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                    x >>= (iFcode - 1);
88                    if (x > 32) x = 32;
89                    xb = mvtab[x] + iFcode;
90            }
91    
92                  return mvtab[component] + 1;          if (y == 0) yb = 1;
93            else {
94                    if (y < 0) y = -y;
95                    y += (1 << (iFcode - 1)) - 1;
96                    y >>= (iFcode - 1);
97                    if (y > 32) y = 32;
98                    yb = mvtab[y] + iFcode;
99            }
100            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;
138    }
139    
140    
141    /* CHECK_CANDIATE FUNCTIONS START */
142    
143    
144          component += (1 << (iFcode - 1)) - 1;  static void
145          component >>= (iFcode - 1);  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          if (component > 32)          if (( x > data->max_dx) || ( x < data->min_dx)
151                  component = 32;                  || ( y > data->max_dy) || (y < data->min_dy)) return;
152    
153          return mvtab[component] + 1 + iFcode - 1;          switch ( ((x&1)<<1) + (y&1) ) {
154                    case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
155                    case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;
156                    case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;
157                    default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
158  }  }
159    
160            data->temp[0] = sad16v(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
161    
162            if (data->qpel) t = d_mv_bits(2*x - data->predQMV.x, 2*y - data->predQMV.y, data->iFcode);
163            else t = d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
164    
165            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            if (data->temp[0] < data->iMinSAD[0]) {
171                    data->iMinSAD[0] = data->temp[0];
172                    data->currentMV[0].x = x; data->currentMV[0].y = y;
173                    *dir = Direction; }
174    
175            if (data->temp[1] < data->iMinSAD[1]) {
176                    data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
177            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            if (data->temp[3] < data->iMinSAD[3]) {
180                    data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
181            if (data->temp[4] < data->iMinSAD[4]) {
182                    data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
183    
 static __inline uint32_t  
 calc_delta_16(const int32_t dx,  
                           const int32_t dy,  
                           const uint32_t iFcode,  
                           const uint32_t iQuant)  
 {  
         return NEIGH_TEND_16X16 * lambda_vec16[iQuant] * (mv_bits(dx, iFcode) +  
                                                                                                           mv_bits(dy, iFcode));  
184  }  }
185    
186  static __inline uint32_t  static void
187  calc_delta_8(const int32_t dx,  CheckCandidate16no4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                          const int32_t dy,  
                          const uint32_t iFcode,  
                          const uint32_t iQuant)  
188  {  {
189          return NEIGH_TEND_8X8 * lambda_vec8[iQuant] * (mv_bits(dx, iFcode) +          int32_t sad;
190                                                                                                     mv_bits(dy, iFcode));          const uint8_t * Reference;
 }  
191    
192  bool          if (( x > data->max_dx) || ( x < data->min_dx)
193  MotionEstimation(MBParam * const pParam,                  || ( y > data->max_dy) || (y < data->min_dy)) return;
194                                   FRAMEINFO * const current,  
195                                   FRAMEINFO * const reference,          switch ( ((x&1)<<1) + (y&1) )
                                  const IMAGE * const pRefH,  
                                  const IMAGE * const pRefV,  
                                  const IMAGE * const pRefHV,  
                                  const uint32_t iLimit)  
196  {  {
197          const uint32_t iWcount = pParam->mb_width;                  case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
198          const uint32_t iHcount = pParam->mb_height;                  case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;
199          MACROBLOCK *const pMBs = current->mbs;                  case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;
200          MACROBLOCK *const prevMBs = reference->mbs;                  default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
201          const IMAGE *const pCurrent = &current->image;          }
         const IMAGE *const pRef = &reference->image;  
202    
203          const VECTOR zeroMV = { 0, 0 };          sad = sad16(data->Cur, Reference, data->iEdgedWidth, MV_MAX_ERROR);
204            if (data->qpel) //only to be used in b-frames' ME
205                    sad += (data->lambda16 * d_mv_bits(2*x - data->predMV.x, 2*y - data->predMV.y, data->iFcode) * sad)/1000;
206            else
207                    sad += (data->lambda16 * d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode) * sad)/1000;
208    
209          int32_t x, y;          if (sad < *(data->iMinSAD)) {
210          int32_t iIntra = 0;                  *(data->iMinSAD) = sad;
211          VECTOR pmv;                  data->currentMV[0].x = x; data->currentMV[0].y = y;
212                    *dir = Direction; }
213    }
214    
215          if (sadInit)  static void
216                  (*sadInit) ();  CheckCandidate16_qpel(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
217    
218          for (y = 0; y < iHcount; y++)   {  // CheckCandidate16 variant which expects x and y in quarter pixel resolution
219                  for (x = 0; x < iWcount; x ++)  {  // Important: This is no general usable routine! x and y must be +/-1 (qpel resolution!)
220    // around currentMV!
221    {
222            int t;
223            uint8_t * Reference = (uint8_t *)data->RefQ;
224            const uint8_t *ref1, *ref2, *ref3, *ref4;
225            VECTOR halfpelMV = *(data->currentMV);
226    
227                          MACROBLOCK *const pMB = &pMBs[x + y * iWcount];          int32_t iEdgedWidth = data->iEdgedWidth;
228            uint32_t rounding = data->rounding;
229    
230                          pMB->sad16 =          if (( x > data->max_dx) || ( x < data->min_dx)
231                                  SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,                  || ( y > data->max_dy) || (y < data->min_dy)) return;
                                                  y, current->motion_flags, current->quant,  
                                                  current->fcode, pParam, pMBs, prevMBs, &pMB->mv16,  
                                                  &pMB->pmvs[0]);  
232    
233                          if (0 < (pMB->sad16 - MV16_INTER_BIAS)) {          GET_REFERENCE(halfpelMV.x, halfpelMV.y, ref1); // this refenrence is used in all cases
234                                  int32_t deviation;          switch( ((x&1)<<1) + (y&1) )
235            {
236            case 0: // pure halfpel position - shouldn't happen during a refinement step
237                    GET_REFERENCE(halfpelMV.x, halfpelMV.y, Reference);
238                    break;
239    
240                                  deviation =          case 1: // x halfpel, y qpel - top or bottom during qpel refinement
241                                          dev16(pCurrent->y + x * 16 + y * 16 * pParam->edged_width,                  GET_REFERENCE(halfpelMV.x, y - halfpelMV.y, ref2);
242                                                    pParam->edged_width);                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding);
243                    interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding);
244                    interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding);
245                    interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding);
246                    break;
247    
248                                  if (deviation < (pMB->sad16 - MV16_INTER_BIAS)) {          case 2: // x qpel, y halfpel - left or right during qpel refinement
249                                          pMB->mode = MODE_INTRA;                  GET_REFERENCE(x - halfpelMV.x, halfpelMV.y, ref2);
250                                          pMB->mv16 = pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding);
251                                                  pMB->mvs[3] = zeroMV;                  interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding);
252                                          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =                  interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding);
253                                                  pMB->sad8[3] = 0;                  interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding);
254                    break;
255    
256                                          iIntra++;          default: // x and y in qpel resolution - the "corners" (top left/right and
257                                          if (iIntra >= iLimit)                           // bottom left/right) during qpel refinement
258                                                  return 1;                  GET_REFERENCE(halfpelMV.x, y - halfpelMV.y, ref2);
259                    GET_REFERENCE(x - halfpelMV.x, halfpelMV.y, ref3);
260                    GET_REFERENCE(x - halfpelMV.x, y - halfpelMV.y, ref4);
261    
262                                          continue;                  interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
263                                  }                  interpolate8x8_avg4(Reference+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, rounding);
264                    interpolate8x8_avg4(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, rounding);
265                    interpolate8x8_avg4(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, rounding);
266                    break;
267                          }                          }
268    
269                          pmv = pMB->pmvs[0];          data->temp[0] = sad16v(data->Cur, Reference, data->iEdgedWidth, data->temp+1);
                         if (current->global_flags & XVID_INTER4V)  
                                 if ((!(current->global_flags & XVID_LUMIMASKING) ||  
                                          pMB->dquant == NO_CHANGE)) {  
                                         int32_t sad8 = IMV16X16 * current->quant;  
   
                                         if (sad8 < pMB->sad16)  
   
                                                 sad8 += pMB->sad8[0] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x, 2 * y, pMB->mv16.x,  
                                                                         pMB->mv16.y, current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[0],  
                                                                         &pMB->pmvs[0]);  
   
                                         if (sad8 < pMB->sad16)  
                                                 sad8 += pMB->sad8[1] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x + 1, 2 * y, pMB->mv16.x,  
                                                                         pMB->mv16.y, current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[1],  
                                                                         &pMB->pmvs[1]);  
   
                                         if (sad8 < pMB->sad16)  
                                                 sad8 += pMB->sad8[2] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x, 2 * y + 1, pMB->mv16.x,  
                                                                         pMB->mv16.y, current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[2],  
                                                                         &pMB->pmvs[2]);  
   
                                         if (sad8 < pMB->sad16)  
                                                 sad8 += pMB->sad8[3] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x + 1, 2 * y + 1,  
                                                                         pMB->mv16.x, pMB->mv16.y,  
                                                                         current->motion_flags, current->quant,  
                                                                         current->fcode, pParam, pMBs, prevMBs,  
                                                                         &pMB->mvs[3], &pMB->pmvs[3]);  
270    
271                                          /* decide: MODE_INTER or MODE_INTER4V          t = d_mv_bits(x - data->predQMV.x, y - data->predQMV.y, data->iFcode);
272                                             mpeg4:   if (sad8 < pMB->sad16 - nb/2+1) use_inter4v          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                                          if (sad8 < pMB->sad16) {          if (data->chroma)
276                                                  pMB->mode = MODE_INTER4V;                  data->temp[0] += ChromaSAD(x/2, y/2, data);
                                                 pMB->sad8[0] *= 4;  
                                                 pMB->sad8[1] *= 4;  
                                                 pMB->sad8[2] *= 4;  
                                                 pMB->sad8[3] *= 4;  
                                                 continue;  
                                         }  
277    
278                                  }          if (data->temp[0] < data->iMinSAD[0]) {
279                    data->iMinSAD[0] = data->temp[0];
280                    data->currentQMV[0].x = x; data->currentQMV[0].y = y;
281            /*      *dir = Direction;*/ }
282    
283                          pMB->mode = MODE_INTER;          if (data->temp[1] < data->iMinSAD[1]) {
284                          pMB->pmvs[0] = pmv;     /* pMB->pmvs[1] = pMB->pmvs[2] = pMB->pmvs[3]  are not needed for INTER */                  data->iMinSAD[1] = data->temp[1]; data->currentQMV[1].x = x; data->currentQMV[1].y = y; }
285                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mv16;          if (data->temp[2] < data->iMinSAD[2]) {
286                          pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] =                  data->iMinSAD[2] = data->temp[2]; data->currentQMV[2].x = x; data->currentQMV[2].y = y; }
287                                  pMB->sad16;          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          return 0;  static void
294  }  CheckCandidate16no4v_qpel(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
295    
296  #define CHECK_MV16_ZERO {\  // CheckCandidate16no4v variant which expects x and y in quarter pixel resolution
297    if ( (0 <= max_dx) && (0 >= min_dx) \  // Important: This is no general usable routine! x and y must be +/-1 (qpel resolution!)
298      && (0 <= max_dy) && (0 >= min_dy) ) \  // around currentMV!
299    { \  // this function is for B-frames' search only
300      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \  {
301      iSAD += calc_delta_16(-pmv[0].x, -pmv[0].y, (uint8_t)iFcode, iQuant);\          uint8_t * Reference = (uint8_t *)data->RefQ;
302      if (iSAD < iMinSAD) \          const uint8_t *ref1, *ref2, *ref3, *ref4;
303      {  iMinSAD=iSAD; currMV->x=0; currMV->y=0; }  }     \          VECTOR halfpelMV = *(data->currentMV);
 }  
   
 #define NOCHECK_MV16_CANDIDATE(X,Y) { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \  
 }  
   
 #define CHECK_MV16_CANDIDATE(X,Y) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \  
 }  
304    
305  #define CHECK_MV16_CANDIDATE_DIR(X,Y,D) { \          int32_t iEdgedWidth = data->iEdgedWidth;
306    if ( ((X) <= max_dx) && ((X) >= min_dx) \          int32_t sad;
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \  
 }  
307    
308  #define CHECK_MV16_CANDIDATE_FOUND(X,Y,D) { \          if (( x > data->max_dx) || ( x < data->min_dx)
309    if ( ((X) <= max_dx) && ((X) >= min_dx) \                  || ( y > data->max_dy) || (y < data->min_dy)) return;
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
 }  
310    
311            GET_REFERENCE(halfpelMV.x, halfpelMV.y, ref1); // this refenrence is used in all cases
312            switch( ((x&1)<<1) + (y&1) )
313            {
314            case 0: // pure halfpel position - shouldn't happen during a refinement step
315                    GET_REFERENCE(halfpelMV.x, halfpelMV.y, Reference);
316                    break;
317    
318  #define CHECK_MV8_ZERO {\          case 1: // x halfpel, y qpel - top or bottom during qpel refinement
319    iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, 0, 0 , iEdgedWidth), iEdgedWidth); \                  GET_REFERENCE(halfpelMV.x, y - halfpelMV.y, ref2);
320    iSAD += calc_delta_8(-pmv[0].x, -pmv[0].y, (uint8_t)iFcode, iQuant);\                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, 0);
321    if (iSAD < iMinSAD) \                  interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, 0);
322    { iMinSAD=iSAD; currMV->x=0; currMV->y=0; } \                  interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, 0);
323  }                  interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, 0);
324                    break;
325    
326  #define NOCHECK_MV8_CANDIDATE(X,Y) \          case 2: // x qpel, y halfpel - left or right during qpel refinement
327    { \                  GET_REFERENCE(x - halfpelMV.x, halfpelMV.y, ref2);
328      iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, 0);
329      iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode, iQuant);\                  interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, 0);
330      if (iSAD < iMinSAD) \                  interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, 0);
331      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \                  interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, 0);
332  }                  break;
333    
334  #define CHECK_MV8_CANDIDATE(X,Y) { \          default: // x and y in qpel resolution - the "corners" (top left/right and
335    if ( ((X) <= max_dx) && ((X) >= min_dx) \                           // bottom left/right) during qpel refinement
336      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \                  GET_REFERENCE(halfpelMV.x, y - halfpelMV.y, ref2);
337    { \                  GET_REFERENCE(x - halfpelMV.x, halfpelMV.y, ref3);
338      iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \                  GET_REFERENCE(x - halfpelMV.x, y - halfpelMV.y, ref4);
     iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \  
 }  
339    
340  #define CHECK_MV8_CANDIDATE_DIR(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 = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \                  break;
     iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \  
345  }  }
346    
347  #define CHECK_MV8_CANDIDATE_FOUND(X,Y,D) { \          sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
348    if ( ((X) <= max_dx) && ((X) >= min_dx) \          sad += (data->lambda16 * d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode) * sad)/1000;
349      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
350    { \          if (sad < data->iMinSAD[0]) {
351      iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \                  data->iMinSAD[0] = sad;
352      iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode, iQuant);\                  data->currentQMV[0].x = x; data->currentQMV[0].y = y;
353      if (iSAD < iMinSAD) \          /*      *dir = Direction;*/ }
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
354  }  }
355    
356  /* too slow and not fully functional at the moment */  static void
357  /*  CheckCandidate16no4vI(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
 int32_t ZeroSearch16(  
                                         const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const IMAGE * const pCur,  
                                         const int x, const int y,  
                                         const uint32_t MotionFlags,  
                                         const uint32_t iQuant,  
                                         const uint32_t iFcode,  
                                         MBParam * const pParam,  
                                         const MACROBLOCK * const pMBs,  
                                         const MACROBLOCK * const prevMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
358  {  {
359          const int32_t iEdgedWidth = pParam->edged_width;  // maximum speed - for P/B/I decision
360          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;          int32_t sad;
361          int32_t iSAD;  
362          VECTOR pred;          if (( x > data->max_dx) || ( x < data->min_dx)
363                    || ( y > data->max_dy) || (y < data->min_dy)) return;
364    
365            sad = sad16(data->Cur, data->Ref + x/2 + (y/2)*(data->iEdgedWidth),
366                                            data->iEdgedWidth, 256*4096);
367    
368          pred = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          if (sad < *(data->iMinSAD)) {
369                    *(data->iMinSAD) = sad;
370                    data->currentMV[0].x = x; data->currentMV[0].y = y;
371                    *dir = Direction; }
372    }
373    
         iSAD = sad16( cur,  
                 get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth),  
                 iEdgedWidth, MV_MAX_ERROR);  
         if (iSAD <= iQuant * 96)  
                 iSAD -= MV16_00_BIAS;  
374    
375          currMV->x = 0;  static void
376          currMV->y = 0;  CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)
377          currPMV->x = -pred.x;  {
378          currPMV->y = -pred.y;          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          return iSAD;          if (( xf > data->max_dx) || ( xf < data->min_dx)
384                    || ( yf > data->max_dy) || (yf < data->min_dy)) return;
385    
386            switch ( ((xf&1)<<1) + (yf&1) ) {
387                    case 0 : ReferenceF = data->Ref + xf/2 + (yf/2)*(data->iEdgedWidth); break;
388                    case 1 : ReferenceF = data->RefV + xf/2 + ((yf-1)/2)*(data->iEdgedWidth); break;
389                    case 2 : ReferenceF = data->RefH + (xf-1)/2 + (yf/2)*(data->iEdgedWidth); break;
390                    default : ReferenceF = data->RefHV + (xf-1)/2 + ((yf-1)/2)*(data->iEdgedWidth); break;
391  }  }
 */  
392    
393  int32_t          switch ( ((xb&1)<<1) + (yb&1) ) {
394  Diamond16_MainSearch(const uint8_t * const pRef,                  case 0 : ReferenceB = data->bRef + xb/2 + (yb/2)*(data->iEdgedWidth); break;
395                                           const uint8_t * const pRefH,                  case 1 : ReferenceB = data->bRefV + xb/2 + ((yb-1)/2)*(data->iEdgedWidth); break;
396                                           const uint8_t * const pRefV,                  case 2 : ReferenceB = data->bRefH + (xb-1)/2 + (yb/2)*(data->iEdgedWidth); break;
397                                           const uint8_t * const pRefHV,                  default : ReferenceB = data->bRefHV + (xb-1)/2 + ((yb-1)/2)*(data->iEdgedWidth); break;
                                          const uint8_t * const cur,  
                                          const int x,  
                                          const int y,  
                                          int32_t startx,  
                                          int32_t starty,  
                                          int32_t iMinSAD,  
                                          VECTOR * const currMV,  
                                          const VECTOR * const pmv,  
                                          const int32_t min_dx,  
                                          const int32_t max_dx,  
                                          const int32_t min_dy,  
                                          const int32_t max_dy,  
                                          const int32_t iEdgedWidth,  
                                          const int32_t iDiamondSize,  
                                          const int32_t iFcode,  
                                          const int32_t iQuant,  
                                          int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = startx;  
         backupMV.y = starty;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
   
         if (iDirection)  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;  
   
                         if (iDirection != 2)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                    backupMV.y, 1);  
                         if (iDirection != 1)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                    backupMV.y, 2);  
                         if (iDirection != 4)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,  
                                                                                    backupMV.y - iDiamondSize, 3);  
                         if (iDirection != 3)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,  
                                                                                    backupMV.y + iDiamondSize, 4);  
         } else {  
                 currMV->x = startx;  
                 currMV->y = starty;  
398          }          }
399          return iMinSAD;  
400            sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
401    
402            if (data->qpel)
403                    sad += (data->lambda16 *
404                            ( d_mv_bits(2*xf - data->predMV.x, 2*yf - data->predMV.y, data->iFcode) +
405                              d_mv_bits(2*xb - data->bpredMV.x, 2*yb - data->bpredMV.y, data->iFcode)) * sad)/1000;
406            else
407                    sad += (data->lambda16 *
408                            ( d_mv_bits(xf - data->predMV.x, yf - data->predMV.y, data->iFcode) +
409                              d_mv_bits(xb - data->bpredMV.x, yb - data->bpredMV.y, data->iFcode)) * sad)/1000;
410    
411            if (sad < *(data->iMinSAD)) {
412                    *(data->iMinSAD) = sad;
413                    data->currentMV->x = xf; data->currentMV->y = yf;
414                    *dir = Direction; }
415  }  }
416    
 int32_t  
 Square16_MainSearch(const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x,  
                                         const int y,  
                                         int32_t startx,  
                                         int32_t starty,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                         const VECTOR * const pmv,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a square search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = startx;  
         backupMV.y = starty;  
   
 /* It's one search with full square pattern, and new parts for all following diamonds */  
   
 /*   new direction are extra, so 1-4 is normal diamond  
       537  
       1*2  
       648  
 */  
417    
418          CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);  static void
419          CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  CheckCandidateInt_qpel(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)
420          CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  {
421          CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  // CheckCandidateInt variant which expects x and y in quarter pixel resolution
   
         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;  
422    
423                          switch (iDirection) {          int32_t sad;
424                          case 1:          const int xb = data->currentQMV[1].x;
425                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          const int yb = data->currentQMV[1].y;
426                                                                                     backupMV.y, 1);          uint8_t * ReferenceF = (uint8_t *)data->RefQ;
427                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,          uint8_t * ReferenceB = (uint8_t *)data->RefQ + 16;
428                                                                                   backupMV.y - iDiamondSize, 5);          const uint8_t *ref1, *ref2, *ref3, *ref4;
429                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,          VECTOR halfpelMV;
430                                                                                   backupMV.y - iDiamondSize, 7);          const int32_t iEdgedWidth = data->iEdgedWidth;
431    
432            if (( xf > data->max_dx) || ( xf < data->min_dx)
433                    || ( yf > data->max_dy) || (yf < data->min_dy)) return;
434    
435            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            switch( ((xf&1)<<1) + (yf&1) )
439            {
440            case 0: // pure halfpel position - shouldn't happen during a refinement step
441                    GET_REFERENCE(halfpelMV.x, halfpelMV.y, ReferenceF);
442                                  break;                                  break;
443                          case 2:  
444                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y,          case 1: // x halfpel, y qpel - top or bottom during qpel refinement
445                                                                                   2);                  GET_REFERENCE(halfpelMV.x, yf - halfpelMV.y, ref2);
446                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,                  interpolate8x8_avg2(ReferenceF, ref1, ref2, iEdgedWidth, 0);
447                                                                                   backupMV.y + iDiamondSize, 6);                  interpolate8x8_avg2(ReferenceF+8, ref1+8, ref2+8, iEdgedWidth, 0);
448                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,                  interpolate8x8_avg2(ReferenceF+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, 0);
449                                                                                   backupMV.y + iDiamondSize, 8);                  interpolate8x8_avg2(ReferenceF+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, 0);
450                                  break;                                  break;
451    
452                          case 3:          case 2: // x qpel, y halfpel - left or right during qpel refinement
453                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize,                  GET_REFERENCE(xf - halfpelMV.x, halfpelMV.y, ref2);
454                                                                                   4);                  interpolate8x8_avg2(ReferenceF, ref1, ref2, iEdgedWidth, 0);
455                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,                  interpolate8x8_avg2(ReferenceF+8, ref1+8, ref2+8, iEdgedWidth, 0);
456                                                                                   backupMV.y - iDiamondSize, 7);                  interpolate8x8_avg2(ReferenceF+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, 0);
457                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,                  interpolate8x8_avg2(ReferenceF+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, 0);
                                                                                  backupMV.y + iDiamondSize, 8);  
458                                  break;                                  break;
459    
460                          case 4:          default: // x and y in qpel resolution - the "corners" (top left/right and
461                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize,                           // bottom left/right) during qpel refinement
462                                                                                   3);                  GET_REFERENCE(halfpelMV.x, yf - halfpelMV.y, ref2);
463                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,                  GET_REFERENCE(xf - halfpelMV.x, halfpelMV.y, ref3);
464                                                                                   backupMV.y - iDiamondSize, 5);                  GET_REFERENCE(xf - halfpelMV.x, yf - halfpelMV.y, ref4);
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  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);  
465    
466                    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;                                  break;
471            }
472    
473                          case 7:          halfpelMV.x = xb/2; //backward
474                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          halfpelMV.y = yb/2;
475                                                                                     backupMV.y, 1);          GET_REFERENCE2(halfpelMV.x, halfpelMV.y, ref1); // this reference is used in all cases
476                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize,          switch( ((xb&1)<<1) + (yb&1) )
477                                                                                   4);          {
478                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,          case 0: // pure halfpel position - shouldn't happen during a refinement step
479                                                                                   backupMV.y - iDiamondSize, 5);                  GET_REFERENCE2(halfpelMV.x, halfpelMV.y, ReferenceB);
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
480                                  break;                                  break;
481    
482                          case 8:          case 1: // x halfpel, y qpel - top or bottom during qpel refinement
483                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y,                  GET_REFERENCE2(halfpelMV.x, yb - halfpelMV.y, ref2);
484                                                                                   2);                  interpolate8x8_avg2(ReferenceB, ref1, ref2, iEdgedWidth, 0);
485                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize,                  interpolate8x8_avg2(ReferenceB+8, ref1+8, ref2+8, iEdgedWidth, 0);
486                                                                                   4);                  interpolate8x8_avg2(ReferenceB+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, 0);
487                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,                  interpolate8x8_avg2(ReferenceB+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, 0);
                                                                                  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);  
488                                  break;                                  break;
489                          default:  
490                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y,          case 2: // x qpel, y halfpel - left or right during qpel refinement
491                                                                                   1);                  GET_REFERENCE2(xb - halfpelMV.x, halfpelMV.y, ref2);
492                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y,                  interpolate8x8_avg2(ReferenceB, ref1, ref2, iEdgedWidth, 0);
493                                                                                   2);                  interpolate8x8_avg2(ReferenceB+8, ref1+8, ref2+8, iEdgedWidth, 0);
494                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize,                  interpolate8x8_avg2(ReferenceB+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, 0);
495                                                                                   3);                  interpolate8x8_avg2(ReferenceB+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, 0);
496                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize,                  break;
497                                                                                   4);  
498            default: // x and y in qpel resolution - the "corners" (top left/right and
499                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,                           // bottom left/right) during qpel refinement
500                                                                                   backupMV.y - iDiamondSize, 5);                  GET_REFERENCE2(halfpelMV.x, yb - halfpelMV.y, ref2);
501                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,                  GET_REFERENCE2(xb - halfpelMV.x, halfpelMV.y, ref3);
502                                                                                   backupMV.y + iDiamondSize, 6);                  GET_REFERENCE2(xb - halfpelMV.x, yb - halfpelMV.y, ref4);
503                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
504                                                                                   backupMV.y - iDiamondSize, 7);                  interpolate8x8_avg4(ReferenceB, ref1, ref2, ref3, ref4, iEdgedWidth, 0);
505                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,                  interpolate8x8_avg4(ReferenceB+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, 0);
506                                                                                   backupMV.y + iDiamondSize, 8);                  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;                                  break;
                         }  
         } else {  
                 currMV->x = startx;  
                 currMV->y = starty;  
         }  
         return iMinSAD;  
509  }  }
510    
511            sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
512    
513  int32_t          sad += (data->lambda16 *
514  Full16_MainSearch(const uint8_t * const pRef,                          ( d_mv_bits(xf - data->predMV.x, yf - data->predMV.y, data->iFcode) +
515                                    const uint8_t * const pRefH,                            d_mv_bits(xb - data->bpredMV.x, yb - data->bpredMV.y, data->iFcode)) * sad)/1000;
                                   const uint8_t * const pRefV,  
                                   const uint8_t * const pRefHV,  
                                   const uint8_t * const cur,  
                                   const int x,  
                                   const int y,  
                                   int32_t startx,  
                                   int32_t starty,  
                                   int32_t iMinSAD,  
                                   VECTOR * const currMV,  
                                   const VECTOR * const pmv,  
                                   const int32_t min_dx,  
                                   const int32_t max_dx,  
                                   const int32_t min_dy,  
                                   const int32_t max_dy,  
                                   const int32_t iEdgedWidth,  
                                   const int32_t iDiamondSize,  
                                   const int32_t iFcode,  
                                   const int32_t iQuant,  
                                   int iFound)  
 {  
         int32_t iSAD;  
         int32_t dx, dy;  
         VECTOR backupMV;  
   
         backupMV.x = startx;  
         backupMV.y = starty;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV16_CANDIDATE(dx, dy);  
516    
517          return iMinSAD;          if (sad < *(data->iMinSAD)) {
518                    *(data->iMinSAD) = sad;
519                    data->currentQMV->x = xf; data->currentQMV->y = yf;
520                    *dir = Direction; }
521  }  }
522    
523  int32_t  static void
524  AdvDiamond16_MainSearch(const uint8_t * const pRef,  CheckCandidateDirect(const int x, const int y, 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,  
                                                 int32_t startx,  
                                                 int32_t starty,  
                                                 int32_t iMinSAD,  
                                                 VECTOR * const currMV,  
                                                 const VECTOR * const pmv,  
                                                 const int32_t min_dx,  
                                                 const int32_t max_dx,  
                                                 const int32_t min_dy,  
                                                 const int32_t max_dy,  
                                                 const int32_t iEdgedWidth,  
                                                 const int32_t iDiamondSize,  
                                                 const int32_t iFcode,  
                                                 const int32_t iQuant,  
                                                 int iDirection)  
525  {  {
526            int32_t sad = 0;
527            int k;
528            const uint8_t *ReferenceF;
529            const uint8_t *ReferenceB;
530            VECTOR mvs, b_mvs;
531    
532          int32_t iSAD;          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
533    
534  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */          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          if (iDirection) {                  mvs.y = data->directmvF[k].y + y;
541                  CHECK_MV16_CANDIDATE(startx - iDiamondSize, starty);                  b_mvs.y = ((y == 0) ?
542                  CHECK_MV16_CANDIDATE(startx + iDiamondSize, starty);                          data->directmvB[k].y
543                  CHECK_MV16_CANDIDATE(startx, starty - iDiamondSize);                          : mvs.y - data->referencemv[k].y);
                 CHECK_MV16_CANDIDATE(startx, starty + iDiamondSize);  
         } else {  
                 int bDirection = 1 + 2 + 4 + 8;  
544    
545                  do {                  if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
546                          iDirection = 0;                          || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
547                          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)                          || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
548                                  CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);                          || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
549    
550                          if (bDirection & 2)                  switch ( ((mvs.x&1)<<1) + (mvs.y&1) ) {
551                                  CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);                          case 0 : ReferenceF = data->Ref + mvs.x/2 + (mvs.y/2)*(data->iEdgedWidth); break;
552                            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 (bDirection & 4)                  switch ( ((b_mvs.x&1)<<1) + (b_mvs.y&1) ) {
558                                  CHECK_MV16_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);                          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                            case 2 : ReferenceB = data->bRefH + (b_mvs.x-1)/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
561                            default : ReferenceB = data->bRefHV + (b_mvs.x-1)/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
562                    }
563    
564                          if (bDirection & 8)                  sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
565                                  CHECK_MV16_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);                                                  ReferenceF + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
566                                                    ReferenceB + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
567                                                    data->iEdgedWidth);
568                    if (sad > *(data->iMinSAD)) return;
569            }
570    
571                          /* now we're doing diagonal checks near our candidate */          sad += (data->lambda16 * d_mv_bits(x, y, 1) * sad)/1000;
572    
573                          if (iDirection)         //checking if anything found          if (sad < *(data->iMinSAD)) {
574                          {                  *(data->iMinSAD) = sad;
575                                  bDirection = iDirection;                  data->currentMV->x = x; data->currentMV->y = y;
576                                  iDirection = 0;                  *dir = Direction; }
                                 startx = currMV->x;  
                                 starty = currMV->y;  
                                 if (bDirection & 3)     //our candidate is left or right  
                                 {  
                                         CHECK_MV16_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);  
                                         CHECK_MV16_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);  
                                 } else                  // what remains here is up or down  
                                 {  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);  
577                                  }                                  }
578    
                                 if (iDirection) {  
                                         bDirection += iDirection;  
                                         startx = currMV->x;  
                                         starty = currMV->y;  
                                 }  
                         } else                          //about to quit, eh? not so fast....  
                         {  
                                 switch (bDirection) {  
                                 case 2:  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1:  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 2 + 4:  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 4:  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty - iDiamondSize, 1 + 4);  
                                         break;  
                                 case 8:  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 1 + 4:  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty - iDiamondSize, 2 + 4);  
                                         break;  
                                 case 2 + 8:  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1 + 8:  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty + iDiamondSize, 1 + 8);  
                                         break;  
                                 default:                //1+2+4+8 == we didn't find anything at all  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
                                         break;  
                                 }  
                                 if (!iDirection)  
                                         break;          //ok, the end. really  
                                 else {  
                                         bDirection = iDirection;  
                                         startx = currMV->x;  
                                         starty = currMV->y;  
                                 }  
                         }  
                 }  
                 while (1);                              //forever  
         }  
         return iMinSAD;  
 }  
579    
580  int32_t  static void
581  AdvDiamond8_MainSearch(const uint8_t * const pRef,  CheckCandidateDirect_qpel(const int x, const int y, 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,  
                                            int32_t startx,  
                                            int32_t starty,  
                                            int32_t iMinSAD,  
                                            VECTOR * const currMV,  
                                            const VECTOR * const pmv,  
                                            const int32_t min_dx,  
                                            const int32_t max_dx,  
                                            const int32_t min_dy,  
                                            const int32_t max_dy,  
                                            const int32_t iEdgedWidth,  
                                            const int32_t iDiamondSize,  
                                            const int32_t iFcode,  
                                            const int32_t iQuant,  
                                            int iDirection)  
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          int32_t iSAD;          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
591    
592  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */          for (k = 0; k < 4; k++) {
593                    ReferenceF = (uint8_t *)data->RefQ;
594                    ReferenceB = (uint8_t *)data->RefQ + 64;
595    
596          if (iDirection) {                  mvs.x = data->directmvF[k].x + x;
597                  CHECK_MV8_CANDIDATE(startx - iDiamondSize, starty);                  b_mvs.x = ((x == 0) ?
598                  CHECK_MV8_CANDIDATE(startx + iDiamondSize, starty);                          data->directmvB[k].x
599                  CHECK_MV8_CANDIDATE(startx, starty - iDiamondSize);                          : mvs.x - data->referencemv[k].x);
                 CHECK_MV8_CANDIDATE(startx, starty + iDiamondSize);  
         } else {  
                 int bDirection = 1 + 2 + 4 + 8;  
600    
601                  do {                  mvs.y = data->directmvF[k].y + y;
602                          iDirection = 0;                  b_mvs.y = ((y == 0) ?
603                          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)                          data->directmvB[k].y
604                                  CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);                          : mvs.y - data->referencemv[k].y);
605    
606                          if (bDirection & 2)                  if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
607                                  CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize, starty, 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                          if (bDirection & 4)                  halfpelMV.x = mvs.x/2; //forward first
612                                  CHECK_MV8_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);                  halfpelMV.y = mvs.y/2;
613                    GET_REFERENCE(halfpelMV.x, halfpelMV.y, ref1); // this reference is used in all cases
614                    switch( ((mvs.x&1)<<1) + (mvs.y&1) ) {
615                    case 0: // pure halfpel position
616                            GET_REFERENCE(halfpelMV.x + 16*(k&1), halfpelMV.y + 16*(k>>1), ReferenceF);
617                            break;
618    
619                          if (bDirection & 8)                  case 1: // x halfpel, y qpel - top or bottom during qpel refinement
620                                  CHECK_MV8_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);                          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                          /* now we're doing diagonal checks near our candidate */                  case 2: // x qpel, y halfpel - left or right during qpel refinement
626                            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                          if (iDirection)         //checking if anything found                  default: // x and y in qpel resolution - the "corners" (top left/right and
632                          {                                   // bottom left/right) during qpel refinement
633                                  bDirection = iDirection;                          GET_REFERENCE(halfpelMV.x, mvs.y - halfpelMV.y, ref2);
634                                  iDirection = 0;                          GET_REFERENCE(mvs.x - halfpelMV.x, halfpelMV.y, ref3);
635                                  startx = currMV->x;                          GET_REFERENCE(mvs.x - halfpelMV.x, mvs.y - halfpelMV.y, ref4);
636                                  starty = currMV->y;                          interpolate8x8_avg4(ReferenceF, ref1 + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
637                                  if (bDirection & 3)     //our candidate is left or right                                                                  ref2 + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
638                                  {                                                                  ref3 + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
639                                          CHECK_MV8_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);                                                                  ref4 + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth), iEdgedWidth, 0);
640                                          CHECK_MV8_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);                          break;
                                 } else                  // what remains here is up or down  
                                 {  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);  
641                                  }                                  }
642    
643                                  if (iDirection) {                  halfpelMV.x = b_mvs.x/2;
644                                          bDirection += iDirection;                  halfpelMV.y = b_mvs.y/2;
645                                          startx = currMV->x;                  GET_REFERENCE2(halfpelMV.x, halfpelMV.y, ref1); // this reference is used in most cases
646                                          starty = currMV->y;                  switch( ((b_mvs.x&1)<<1) + (b_mvs.y&1) ) {
647                                  }                  case 0: // pure halfpel position
648                          } else                          //about to quit, eh? not so fast....                          GET_REFERENCE2(halfpelMV.x + 16*(k&1), halfpelMV.y + 16*(k>>1), ReferenceB);
                         {  
                                 switch (bDirection) {  
                                 case 2:  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1:  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 2 + 4:  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
649                                          break;                                          break;
650                                  case 4:  
651                                          CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,                  case 1: // x halfpel, y qpel - top or bottom during qpel refinement
652                                                                                          starty - iDiamondSize, 2 + 4);                          GET_REFERENCE2(halfpelMV.x, b_mvs.y - halfpelMV.y, ref2);
653                                          CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,                          interpolate8x8_avg2(ReferenceB, ref1+8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
654                                                                                          starty - iDiamondSize, 1 + 4);                                                                  ref2+ 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth), iEdgedWidth, 0);
                                         break;  
                                 case 8:  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 1 + 4:  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         break;  
                                 case 2 + 8:  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
655                                          break;                                          break;
656                                  case 1 + 8:  
657                                          CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,                  case 2: // x qpel, y halfpel - left or right during qpel refinement
658                                                                                          starty - iDiamondSize, 2 + 4);                          GET_REFERENCE2(b_mvs.x - halfpelMV.x, halfpelMV.y, ref2);
659                                          CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,                          interpolate8x8_avg2(ReferenceB, ref1 + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
660                                                                                          starty + iDiamondSize, 2 + 8);                                                                  ref2 + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth), iEdgedWidth, 0);
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
661                                          break;                                          break;
662                                  default:                //1+2+4+8 == we didn't find anything at all  
663                                          CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,                  default: // x and y in qpel resolution - the "corners" (top left/right and
664                                                                                          starty - iDiamondSize, 1 + 4);                                   // bottom left/right) during qpel refinement
665                                          CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,                          GET_REFERENCE2(halfpelMV.x, b_mvs.y - halfpelMV.y, ref2);
666                                                                                          starty + iDiamondSize, 1 + 8);                          GET_REFERENCE2(b_mvs.x - halfpelMV.x, halfpelMV.y, ref3);
667                                          CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,                          GET_REFERENCE2(b_mvs.x - halfpelMV.x, b_mvs.y - halfpelMV.y, ref4);
668                                                                                          starty - iDiamondSize, 2 + 4);                          interpolate8x8_avg4(ReferenceB, ref1 + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
669                                          CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,                                                                  ref2 + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
670                                                                                          starty + iDiamondSize, 2 + 8);                                                                  ref3 + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
671                                                                    ref4 + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth), iEdgedWidth, 0);
672                                          break;                                          break;
673                                  }                                  }
                                 if (!(iDirection))  
                                         break;          //ok, the end. really  
                                 else {  
                                         bDirection = iDirection;  
                                         startx = currMV->x;  
                                         starty = currMV->y;  
                                 }  
                         }  
                 }  
                 while (1);                              //forever  
         }  
         return iMinSAD;  
 }  
674    
675                    sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
676                                                    ReferenceF,
677                                                    ReferenceB,
678                                                    data->iEdgedWidth);
679                    if (sad > *(data->iMinSAD)) return;
680            }
681    
682  int32_t          sad += (data->lambda16 * d_mv_bits(x, y, 1) * sad)/1000;
 Full8_MainSearch(const uint8_t * const pRef,  
                                  const uint8_t * const pRefH,  
                                  const uint8_t * const pRefV,  
                                  const uint8_t * const pRefHV,  
                                  const uint8_t * const cur,  
                                  const int x,  
                                  const int y,  
                                  int32_t startx,  
                                  int32_t starty,  
                                  int32_t iMinSAD,  
                                  VECTOR * const currMV,  
                                  const VECTOR * const pmv,  
                                  const int32_t min_dx,  
                                  const int32_t max_dx,  
                                  const int32_t min_dy,  
                                  const int32_t max_dy,  
                                  const int32_t iEdgedWidth,  
                                  const int32_t iDiamondSize,  
                                  const int32_t iFcode,  
                                  const int32_t iQuant,  
                                  int iFound)  
 {  
         int32_t iSAD;  
         int32_t dx, dy;  
         VECTOR backupMV;  
   
         backupMV.x = startx;  
         backupMV.y = starty;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV8_CANDIDATE(dx, dy);  
683    
684          return iMinSAD;          if (sad < *(data->iMinSAD)) {
685                    *(data->iMinSAD) = sad;
686                    data->currentMV->x = x; data->currentMV->y = y;
687                    *dir = Direction; }
688  }  }
689    
690  Halfpel8_RefineFuncPtr Halfpel8_Refine;  static void
691    CheckCandidateDirectno4v_qpel(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
 int32_t  
 Halfpel16_Refine(const uint8_t * const pRef,  
                                  const uint8_t * const pRefH,  
                                  const uint8_t * const pRefV,  
                                  const uint8_t * const pRefHV,  
                                  const uint8_t * const cur,  
                                  const int x,  
                                  const int y,  
                                  VECTOR * const currMV,  
                                  int32_t iMinSAD,  
                                  const VECTOR * const pmv,  
                                  const int32_t min_dx,  
                                  const int32_t max_dx,  
                                  const int32_t min_dy,  
                                  const int32_t max_dy,  
                                  const int32_t iFcode,  
                                  const int32_t iQuant,  
                                  const int32_t iEdgedWidth)  
692  {  {
693  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */          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          int32_t iSAD;          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
         VECTOR backupMV = *currMV;  
701    
702          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y - 1);          mvs.x = data->directmvF[0].x + x;
703          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y - 1);          b_mvs.x = ((x == 0) ?
704          CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y - 1);                          data->directmvB[0].x
705          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y);                          : mvs.x - data->referencemv[0].x);
         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);  
706    
707          return iMinSAD;          mvs.y = data->directmvF[0].y + y;
708  }          b_mvs.y = ((y == 0) ?
709                            data->directmvB[0].y
710                            : mvs.y - data->referencemv[0].y);
711    
712  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)          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            halfpelMV.x = mvs.x/2; //forward first
718            halfpelMV.y = mvs.y/2;
719            GET_REFERENCE(halfpelMV.x, halfpelMV.y, ref1); // this reference is used in all cases
720            switch( ((mvs.x&1)<<1) + (mvs.y&1) ) {
721            case 0: // pure halfpel position
722                    GET_REFERENCE(halfpelMV.x, halfpelMV.y, ReferenceF);
723                    break;
724    
725  int32_t          case 1: // x halfpel, y qpel - top or bottom during qpel refinement
726  PMVfastSearch16(const uint8_t * const pRef,                  GET_REFERENCE(halfpelMV.x, mvs.y - halfpelMV.y, ref2);
727                                  const uint8_t * const pRefH,                  interpolate8x8_avg2(ReferenceF, ref1, ref2, iEdgedWidth, 0);
728                                  const uint8_t * const pRefV,                  interpolate8x8_avg2(ReferenceF+8, ref1+8, ref2+8, iEdgedWidth, 0);
729                                  const uint8_t * const pRefHV,                  interpolate8x8_avg2(ReferenceF+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, 0);
730                                  const IMAGE * const pCur,                  interpolate8x8_avg2(ReferenceF+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, 0);
731                                  const int x,                  break;
                                 const int y,  
                                 const uint32_t MotionFlags,  
                                 const uint32_t iQuant,  
                                 const uint32_t iFcode,  
                                 const MBParam * const pParam,  
                                 const MACROBLOCK * const pMBs,  
                                 const MACROBLOCK * const prevMBs,  
                                 VECTOR * const currMV,  
                                 VECTOR * const currPMV)  
 {  
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
732    
733          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          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          int32_t iDiamondSize;          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          int32_t min_dx;                  interpolate8x8_avg4(ReferenceF, ref1, ref2, ref3, ref4, iEdgedWidth, 0);
747          int32_t max_dx;                  interpolate8x8_avg4(ReferenceF+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, 0);
748          int32_t min_dy;                  interpolate8x8_avg4(ReferenceF+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, 0);
749          int32_t max_dy;                  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                    break;
751            }
752    
753          int32_t iFound;          halfpelMV.x = b_mvs.x/2; //backward
754            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          VECTOR newMV;          case 1: // x halfpel, y qpel - top or bottom during qpel refinement
763          VECTOR backupMV;                        /* just for PMVFAST */                  GET_REFERENCE2(halfpelMV.x, b_mvs.y - halfpelMV.y, ref2);
764                    interpolate8x8_avg2(ReferenceB, ref1, ref2, iEdgedWidth, 0);
765                    interpolate8x8_avg2(ReferenceB+8, ref1+8, ref2+8, iEdgedWidth, 0);
766                    interpolate8x8_avg2(ReferenceB+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, 0);
767                    interpolate8x8_avg2(ReferenceB+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, 0);
768                    break;
769    
770          VECTOR pmv[4];          case 2: // x qpel, y halfpel - left or right during qpel refinement
771          int32_t psad[4];                  GET_REFERENCE2(b_mvs.x - halfpelMV.x, halfpelMV.y, ref2);
772                    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          MainSearch16FuncPtr MainSearchPtr;          default: // x and y in qpel resolution - the "corners" (top left/right and
779                             // bottom left/right) during qpel refinement
780                    GET_REFERENCE2(halfpelMV.x, b_mvs.y - halfpelMV.y, ref2);
781                    GET_REFERENCE2(b_mvs.x - halfpelMV.x, halfpelMV.y, ref3);
782                    GET_REFERENCE2(b_mvs.x - halfpelMV.x, b_mvs.y - halfpelMV.y, ref4);
783    
784          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;                  interpolate8x8_avg4(ReferenceB, ref1, ref2, ref3, ref4, iEdgedWidth, 0);
785                    interpolate8x8_avg4(ReferenceB+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, 0);
786                    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          int32_t threshA, threshB;          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
792          int32_t bPredEq;          sad += (data->lambda16 * d_mv_bits(x, y, 1) * sad)/1000;
         int32_t iMinSAD, iSAD;  
793    
794  /* Get maximum range */          if (sad < *(data->iMinSAD)) {
795          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,                  *(data->iMinSAD) = sad;
796                            iFcode);                  data->currentMV->x = x; data->currentMV->y = y;
797                    *dir = Direction; }
798    }
799    
 /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  
800    
801          if (!(MotionFlags & PMV_HALFPEL16)) {  static void
802                  min_dx = EVEN(min_dx);  CheckCandidateDirectno4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
803                  max_dx = EVEN(max_dx);  {
804                  min_dy = EVEN(min_dy);          int32_t sad;
805                  max_dy = EVEN(max_dy);          const uint8_t *ReferenceF;
806          }          const uint8_t *ReferenceB;
807            VECTOR mvs, b_mvs;
808    
809          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
         //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);  
   
 /*      fprintf(stderr,"pmv: %d %d / %d --- %d %d   %d %d   %d %d - %d %d %d\n",  
                 pmv[0].x,pmv[0].y,psad[0],  
                 pmv[1].x,pmv[1].y,pmv[2].x,pmv[2].y,pmv[3].x,pmv[3].y,  
                 psad[1],psad[2],psad[3]);  
 */  
         if ((x == 0) && (y == 0)) {  
                 threshA = 512;  
                 threshB = 1024;  
         } else {  
                 threshA = psad[0];  
                 threshB = threshA + 256;  
                 if (threshA < 512)  
                         threshA = 512;  
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
         }  
   
         iFound = 0;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
810    
811          *currMV = pmv[0];                       /* current best := prediction */          mvs.x = data->directmvF[0].x + x;
812          if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */          b_mvs.x = ((x == 0) ?
813                  currMV->x = EVEN(currMV->x);                  data->directmvB[0].x
814                  currMV->y = EVEN(currMV->y);                  : mvs.x - data->referencemv[0].x);
         }  
815    
816          if (currMV->x > max_dx) {          mvs.y = data->directmvF[0].y + y;
817                  currMV->x = max_dx;          b_mvs.y = ((y == 0) ?
818          }                  data->directmvB[0].y
819          if (currMV->x < min_dx) {                  : mvs.y - data->referencemv[0].y);
                 currMV->x = min_dx;  
         }  
         if (currMV->y > max_dy) {  
                 currMV->y = max_dy;  
         }  
         if (currMV->y < min_dy) {  
                 currMV->y = min_dy;  
         }  
820    
821          iMinSAD =          if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
822                  sad16(cur,                  || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
823                            get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,                  || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
824                                                   iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);                  || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
         iMinSAD +=  
                 calc_delta_16(currMV->x - pmv[0].x, currMV->y - pmv[0].y,  
                                           (uint8_t) iFcode, iQuant);  
825    
826          if ((iMinSAD < 256) ||          switch ( ((mvs.x&1)<<1) + (mvs.y&1) ) {
827                  ((MVequal(*currMV, prevMB->mvs[0])) &&                  case 0 : ReferenceF = data->Ref + mvs.x/2 + (mvs.y/2)*(data->iEdgedWidth); break;
828                   ((int32_t) iMinSAD < prevMB->sad16))) {                  case 1 : ReferenceF = data->RefV + mvs.x/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
829                  if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode                  case 2 : ReferenceF = data->RefH + (mvs.x-1)/2 + (mvs.y/2)*(data->iEdgedWidth); break;
830                  {                  default : ReferenceF = data->RefHV + (mvs.x-1)/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
                         if (!MVzero(*currMV)) {  
                                 iMinSAD += MV16_00_BIAS;  
                                 CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures  
                                 iMinSAD -= MV16_00_BIAS;  
                         }  
831                  }                  }
832    
833                  if (MotionFlags & PMV_QUICKSTOP16)          switch ( ((b_mvs.x&1)<<1) + (b_mvs.y&1) ) {
834                          goto PMVfast16_Terminate_without_Refine;                  case 0 : ReferenceB = data->bRef + b_mvs.x/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
835                  if (MotionFlags & PMV_EARLYSTOP16)                  case 1 : ReferenceB = data->bRefV + b_mvs.x/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
836                          goto PMVfast16_Terminate_with_Refine;                  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            sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
841            sad += (data->lambda16 * d_mv_bits(x, y, 1) * sad)/1000;
842    
843  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion          if (sad < *(data->iMinSAD)) {
844     vector of the median.                  *(data->iMinSAD) = sad;
845     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2                  data->currentMV->x = x; data->currentMV->y = y;
846  */                  *dir = Direction; }
847    }
848    
849          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[0])))  static void
850                  iFound = 2;  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  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          if (( x > data->max_dx) || ( x < data->min_dx)
856     Otherwise select large Diamond Search.                  || ( y > data->max_dy) || (y < data->min_dy)) return;
 */  
857    
858          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))          switch ( ((x&1)<<1) + (y&1) )
859                  iDiamondSize = 1;               // halfpel!          {
860          else                  case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
861                  iDiamondSize = 2;               // halfpel!                  case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;
862                    case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;
863                    default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
864            }
865    
866          if (!(MotionFlags & PMV_HALFPELDIAMOND16))          sad = sad8(data->Cur, Reference, data->iEdgedWidth);
867                  iDiamondSize *= 2;          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  /*          sad += (data->lambda8 * t * (sad+NEIGH_8X8_BIAS))/100;
    Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  
    Also calculate (0,0) but do not subtract offset.  
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset.  
 */  
871    
872  // (0,0) is always possible          if (sad < *(data->iMinSAD)) {
873                    *(data->iMinSAD) = sad;
874                    data->currentMV->x = x; data->currentMV->y = y;
875                    *dir = Direction; }
876    }
877    
878          if (!MVzero(pmv[0]))  static void
879                  CHECK_MV16_ZERO;  CheckCandidate8_qpel(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
880    // CheckCandidate8 variant which expects x and y in quarter pixel resolution
881    // Important: This is no general usable routine! x and y must be +/-1 (qpel resolution!)
882    // around currentMV!
883    
884  // previous frame MV is always possible  {
885            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          if (!MVzero(prevMB->mvs[0]))          int32_t iEdgedWidth = data->iEdgedWidth;
891                  if (!MVequal(prevMB->mvs[0], pmv[0]))          uint32_t rounding = data->rounding;
                         CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);  
892    
893  // left neighbour, if allowed          if (( x > data->max_dx) || ( x < data->min_dx)
894                    || ( y > data->max_dy) || (y < data->min_dy)) return;
895    
896          if (!MVzero(pmv[1]))          GET_REFERENCE(halfpelMV.x, halfpelMV.y, ref1);
897                  if (!MVequal(pmv[1], prevMB->mvs[0]))          switch( ((x&1)<<1) + (y&1) )
898                          if (!MVequal(pmv[1], pmv[0])) {          {
899                                  if (!(MotionFlags & PMV_HALFPEL16)) {          case 0: // pure halfpel position - shouldn't happen during a refinement step
900                                          pmv[1].x = EVEN(pmv[1].x);                  GET_REFERENCE(halfpelMV.x, halfpelMV.y, Reference);
901                                          pmv[1].y = EVEN(pmv[1].y);                  break;
                                 }  
902    
903                                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);          case 1: // x halfpel, y qpel - top or bottom during qpel refinement
904                          }                  GET_REFERENCE(halfpelMV.x, y - halfpelMV.y, ref2);
 // top neighbour, if allowed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], prevMB->mvs[0]))  
                         if (!MVequal(pmv[2], pmv[0]))  
                                 if (!MVequal(pmv[2], pmv[1])) {  
                                         if (!(MotionFlags & PMV_HALFPEL16)) {  
                                                 pmv[2].x = EVEN(pmv[2].x);  
                                                 pmv[2].y = EVEN(pmv[2].y);  
                                         }  
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
905    
906  // top right neighbour, if allowed                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding);
907                                          if (!MVzero(pmv[3]))                  break;
                                                 if (!MVequal(pmv[3], prevMB->mvs[0]))  
                                                         if (!MVequal(pmv[3], pmv[0]))  
                                                                 if (!MVequal(pmv[3], pmv[1]))  
                                                                         if (!MVequal(pmv[3], pmv[2])) {  
                                                                                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                                                                                         pmv[3].x = EVEN(pmv[3].x);  
                                                                                         pmv[3].y = EVEN(pmv[3].y);  
                                                                                 }  
                                                                                 CHECK_MV16_CANDIDATE(pmv[3].x,  
                                                                                                                          pmv[3].y);  
                                                                         }  
                                 }  
908    
909          if ((MVzero(*currMV)) &&          case 2: // x qpel, y halfpel - left or right during qpel refinement
910                  (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )                  GET_REFERENCE(x - halfpelMV.x, halfpelMV.y, ref2);
                 iMinSAD -= MV16_00_BIAS;  
911    
912                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding);
913                    break;
914    
915  /* Step 6: If MinSAD <= thresa goto Step 10.          default: // x and y in qpel resolution - the "corners" (top left/right and
916     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.                           // bottom left/right) during qpel refinement
917  */                  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          if ((iMinSAD <= threshA) ||                  interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
922                  (MVequal(*currMV, prevMB->mvs[0]) &&                  break;
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
923          }          }
924    
925            sad = sad8(data->Cur, Reference, data->iEdgedWidth);
926            sad += (data->lambda8 * d_mv_bits(x - data->predQMV.x, y - data->predQMV.y, data->iFcode) * (sad+NEIGH_8X8_BIAS))/100;
927    
928  /************ (Diamond Search)  **************/          if (sad < *(data->iMinSAD)) {
929  /*                  *(data->iMinSAD) = sad;
930     Step 7: Perform Diamond search, with either the small or large diamond.                  data->currentQMV->x = x; data->currentQMV->y = y;
931     If Found=2 only examine one Diamond pattern, and afterwards goto step 10                  *dir = Direction; }
932     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.  
 */  
933    
934          if (MotionFlags & PMV_USESQUARES16)  /* CHECK_CANDIATE FUNCTIONS END */
                 MainSearchPtr = Square16_MainSearch;  
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
935    
936          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  /* MAINSEARCH FUNCTIONS START */
937    
938    static void
939    AdvDiamondSearch(int x, int y, const SearchData * const data, int bDirection)
940    {
941    
942  //      fprintf(stderr,"Entering Diamond %d %d (%d):\n",x,y,iMinSAD);  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
943    
944  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                  int iDirection;
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  
                                                   currMV->y, iMinSAD, &newMV, pmv, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
945    
946          if (iSAD < iMinSAD) {                  do {
947                  *currMV = newMV;                          iDirection = 0;
948                  iMinSAD = iSAD;                          if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
949          }                          if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
950                            if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
951                            if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
952    
953          if (MotionFlags & PMV_EXTSEARCH16) {                          /* 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, pmv,                                  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                          if (iSAD < iMinSAD) {                                  } else {                        // what remains here is up or down
963                                  *currMV = newMV;                                          CHECK_CANDIDATE(x + iDiamondSize, y, 2);
964                                  iMinSAD = iSAD;                                          CHECK_CANDIDATE(x - iDiamondSize, y, 1); }
                         }  
                 }  
965    
966                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                                  if (iDirection) {
967                          iSAD =                                          bDirection += iDirection;
968                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                                          x = data->currentMV->x; y = data->currentMV->y; }
969                                                                    iMinSAD, &newMV, pmv, min_dx, max_dx, min_dy,                          } else {                                //about to quit, eh? not so fast....
970                                                                    max_dy, iEdgedWidth, iDiamondSize, iFcode,                                  switch (bDirection) {
971                                                                    iQuant, iFound);                                  case 2:
972                                            CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
973                          if (iSAD < iMinSAD) {                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
974                                  *currMV = newMV;                                          break;
975                                  iMinSAD = iSAD;                                  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                                    bDirection = iDirection;
1016                                    x = data->currentMV->x; y = data->currentMV->y;
1017                          }                          }
1018                  }                  }
1019                    while (1);                              //forever
1020          }          }
1021    
1022  /*  static void
1023     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  SquareSearch(int x, int y, const SearchData * const data, int bDirection)
1024  */  {
1025            int iDirection;
1026    
1027    PMVfast16_Terminate_with_Refine:          do {
1028          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step                  iDirection = 0;
1029                  iMinSAD =                  if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);
1030                          Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,                  if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);
1031                                                           iMinSAD, pmv, min_dx, max_dx, min_dy, max_dy,                  if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);
1032                                                           iFcode, iQuant, iEdgedWidth);                  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  /*fprintf(stderr,"Chosen for %d %d: %d %d - %d %d\n",x,y,currMV->x,currMV->y,pmv[0].x,pmv[0].y);                  bDirection = iDirection;
1039  */                  x = data->currentMV->x; y = data->currentMV->y;
1040    PMVfast16_Terminate_without_Refine:          } while (iDirection);
         currPMV->x = currMV->x - pmv[0].x;  
         currPMV->y = currMV->y - pmv[0].y;  
         return iMinSAD;  
1041  }  }
1042    
1043    static void
1044    DiamondSearch(int x, int y, const SearchData * const data, int bDirection)
1045    {
1046    
1047    /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
1048    
1049                    int iDirection;
1050    
1051                    do {
1052                            iDirection = 0;
1053                            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                            /* now we're doing diagonal checks near our candidate */
1059    
1060  int32_t                          if (iDirection) {               //checking if anything found
1061  Diamond8_MainSearch(const uint8_t * const pRef,                                  bDirection = iDirection;
1062                                          const uint8_t * const pRefH,                                  iDirection = 0;
1063                                          const uint8_t * const pRefV,                                  x = data->currentMV->x; y = data->currentMV->y;
1064                                          const uint8_t * const pRefHV,                                  if (bDirection & 3) {   //our candidate is left or right
1065                                          const uint8_t * const cur,                                          CHECK_CANDIDATE(x, y + iDiamondSize, 8);
1066                                          const int x,                                          CHECK_CANDIDATE(x, y - iDiamondSize, 4);
1067                                          const int y,                                  } else {                        // what remains here is up or down
1068                                          int32_t startx,                                          CHECK_CANDIDATE(x + iDiamondSize, y, 2);
1069                                          int32_t starty,                                          CHECK_CANDIDATE(x - iDiamondSize, y, 1); }
1070                                          int32_t iMinSAD,  
1071                                          VECTOR * const currMV,                                  bDirection += iDirection;
1072                                          const VECTOR * const pmv,                                  x = data->currentMV->x; y = data->currentMV->y;
1073                                          const int32_t min_dx,                          }
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = startx;  
         backupMV.y = starty;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
   
         if (iDirection)  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;     // since iDirection!=0, this is well defined!  
   
                         if (iDirection != 2)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                   backupMV.y, 1);  
                         if (iDirection != 1)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                   backupMV.y, 2);  
                         if (iDirection != 4)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y - iDiamondSize, 3);  
                         if (iDirection != 3)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y + iDiamondSize, 4);  
         } else {  
                 currMV->x = startx;  
                 currMV->y = starty;  
1074          }          }
1075          return iMinSAD;                  while (iDirection);
1076  }  }
1077    
1078  int32_t  /* MAINSEARCH FUNCTIONS END */
1079  Halfpel8_Refine_c(const uint8_t * const pRef,  
1080                                  const uint8_t * const pRefH,  /* HALFPELREFINE COULD BE A MAINSEARCH FUNCTION, BUT THERE IS NO NEED FOR IT */
1081                                  const uint8_t * const pRefV,  
1082                                  const uint8_t * const pRefHV,  static void
1083                                  const uint8_t * const cur,  HalfpelRefine(const SearchData * const data)
                                 const int x,  
                                 const int y,  
                                 VECTOR * const currMV,  
                                 int32_t iMinSAD,  
                                 const VECTOR * const pmv,  
                                 const int32_t min_dx,  
                                 const int32_t max_dx,  
                                 const int32_t min_dy,  
                                 const int32_t max_dy,  
                                 const int32_t iFcode,  
                                 const int32_t iQuant,  
                                 const int32_t iEdgedWidth)  
1084  {  {
1085  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */
1086    
1087          int32_t iSAD;          VECTOR backupMV = *(data->currentMV);
1088          VECTOR backupMV = *currMV;          int iDirection; //not needed
1089    
1090          CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y - 1);          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y - 1, 0);
1091          CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y - 1);          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y - 1, 0);
1092          CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y - 1);          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y + 1, 0);
1093          CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y);          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y + 1, 0);
         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);  
1094    
1095          return iMinSAD;          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y, 0);
1096  }          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y, 0);
1097    
1098            CHECK_CANDIDATE(backupMV.x, backupMV.y + 1, 0);
1099            CHECK_CANDIDATE(backupMV.x, backupMV.y - 1, 0);
1100    }
1101    
 #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)  
1102    
1103  int32_t  static void
1104  PMVfastSearch8(const uint8_t * const pRef,  QuarterpelRefine(const SearchData * const data)
                            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 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)  
1105  {  {
1106          const uint32_t iWcount = pParam->mb_width;  /* Perform quarter pixel refinement*/
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
1107    
1108          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;          VECTOR backupMV = *(data->currentQMV);
1109            int iDirection; //not needed
1110    
1111          int32_t iDiamondSize;          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          int32_t min_dx;          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y, 0);
1117          int32_t max_dx;          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y, 0);
         int32_t min_dy;  
         int32_t max_dy;  
1118    
1119          VECTOR pmv[4];          CHECK_CANDIDATE(backupMV.x, backupMV.y + 1, 0);
1120          int32_t psad[4];          CHECK_CANDIDATE(backupMV.x, backupMV.y - 1, 0);
         VECTOR newMV;  
         VECTOR backupMV;  
         VECTOR startMV;  
1121    
1122  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;  }
         const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;  
1123    
1124           int32_t threshA, threshB;  static __inline int
1125          int32_t iFound, bPredEq;  SkipDecisionP(const IMAGE * current, const IMAGE * reference,
1126          int32_t iMinSAD, iSAD;                                                          const int x, const int y,
1127                                                            const uint32_t iEdgedWidth, const uint32_t iQuant)
1128    
1129          int32_t iSubBlock = (y & 1) + (y & 1) + (x & 1);  {
1130    /*      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          MainSearch8FuncPtr MainSearchPtr;          return 1;
1142    }
1143    
1144          /* Init variables */  static __inline void
1145          startMV.x = start_x;  SkipMacroblockP(MACROBLOCK *pMB, const int32_t sad)
1146          startMV.y = start_y;  {
1147            pMB->mode = MODE_NOT_CODED;
1148            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          /* Get maximum range */          pMB->qmvs[0].x = pMB->qmvs[1].x = pMB->qmvs[2].x = pMB->qmvs[3].x = 0;
1152          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,          pMB->qmvs[0].y = pMB->qmvs[1].y = pMB->qmvs[2].y = pMB->qmvs[3].y = 0;
                           iFcode);  
1153    
1154          if (!(MotionFlags & PMV_HALFPELDIAMOND8)) {          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
1155          }          }
1156    
1157          /* because we might use IF (dx>max_dx) THEN dx=max_dx; */  bool
1158          //bPredEq = get_pmvdata(pMBs, (x >> 1), (y >> 1), iWcount, iSubBlock, pmv, psad);  MotionEstimation(MBParam * const pParam,
1159          bPredEq = get_pmvdata2(pMBs, iWcount, 0, (x >> 1), (y >> 1), iSubBlock, pmv, psad);                                   FRAMEINFO * const current,
1160                                     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          if ((x == 0) && (y == 0)) {          const VECTOR zeroMV = { 0, 0 };
                 threshA = 512 / 4;  
                 threshB = 1024 / 4;  
1171    
1172            uint32_t x, y;
1173            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 {          } else {
1223                  threshA = psad[0] / 4;  /* good estimate */                                  if (pMB->dquant != NO_CHANGE) {
1224                  threshB = threshA + 256 / 4;                                          quant += DQtab[pMB->dquant];
1225                  if (threshA < 512 / 4)                                          if (quant > 31) quant = 31;
1226                          threshA = 512 / 4;                                          else if (quant < 1) quant = 1;
1227                  if (threshA > 1024 / 4)                                  }
1228                          threshA = 1024 / 4;                                  pMB->quant = quant;
1229                  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  
1230    
1231  //  if (MotionFlags & PMV_USESQUARES8)  //initial skip decision
1232  //      MainSearchPtr = Square8_MainSearch;  /* no early skip for GMC (global vector = skip vector is unknown!)  */
1233  //  else                          if (current->coding_type == P_VOP)      { /* no fast SKIP for S(GMC)-VOPs */
1234                                    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          if (MotionFlags & PMV_ADVANCEDDIAMOND8)                          SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1242                  MainSearchPtr = AdvDiamond8_MainSearch;                                                  y, current->motion_flags, pMB->quant,
1243          else                                                  &Data, pParam, pMBs, reference->mbs,
1244                  MainSearchPtr = Diamond8_MainSearch;                                                  current->global_flags & XVID_INTER4V, pMB);
1245    
1246    /* 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    /* finally, intra decision */
1257    
1258          *currMV = startMV;                          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          iMinSAD =                          if (Data.chroma) InterBias += 50; // to compensate bigger SAD
                 sad8(cur,  
                          get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  
                                                 iEdgedWidth), iEdgedWidth);  
         iMinSAD +=  
                 calc_delta_8(currMV->x - pmv[0].x, currMV->y - pmv[0].y,  
                                          (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256 / 4) || ((MVequal(*currMV, prevMB->mvs[iSubBlock]))  
                                                                 && ((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  
 */  
1266    
1267          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[iSubBlock])))                          if (InterBias < pMB->sad16)  {
1268                  iFound = 2;                                  const int32_t deviation =
1269                                            dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,
1270                                                      pParam->edged_width);
1271    
1272  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.                                  if (deviation < (pMB->sad16 - InterBias)) {
1273     Otherwise select large Diamond Search.                                          if (++iIntra >= iLimit) { free(qimage); return 1; }
1274  */                                          pMB->mode = MODE_INTRA;
1275                                            pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =
1276                                                            pMB->mvs[3] = zeroMV;
1277                                            pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] =
1278                                                            pMB->qmvs[3] = zeroMV;
1279                                            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 ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))          if (current->coding_type == S_VOP)      /* first GMC step only for S(GMC)-VOPs */
1288                  iDiamondSize = 1;               // 1 halfpel!                  current->GMC_MV = GlobalMotionEst( pMBs, pParam, current->fcode );
1289          else          else
1290                  iDiamondSize = 2;               // 2 halfpel = 1 full pixel!                  current->GMC_MV = zeroMV;
1291    
1292          if (!(MotionFlags & PMV_HALFPELDIAMOND8))          return 0;
                 iDiamondSize *= 2;  
   
   
 /*  
    Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  
    Also calculate (0,0) but do not subtract offset.  
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset.  
 */  
   
 // the median prediction might be even better than mv16  
   
         if (!MVequal(pmv[0], startMV))  
                 CHECK_MV8_CANDIDATE(pmv[0].x, pmv[0].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;  
1293          }          }
1294    
 /************ (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.  
 */  
1295    
1296          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)
1297    
1298  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  static __inline int
1299          iSAD =  make_mask(const VECTOR * const pmv, const int i)
1300                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  {
1301                                                    currMV->y, iMinSAD, &newMV, pmv, min_dx, max_dx,          int mask = 255, j;
1302                                                    min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,          for (j = 0; j < i; j++) {
1303                                                    iQuant, iFound);                  if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already
1304                    if (pmv[i].x == pmv[j].x) {
1305          if (iSAD < iMinSAD) {                          if (pmv[i].y == pmv[j].y + iDiamondSize) { mask &= ~4; continue; }
1306                  *currMV = newMV;                          if (pmv[i].y == pmv[j].y - iDiamondSize) { mask &= ~8; continue; }
1307                  iMinSAD = iSAD;                  } 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          }          }
   
         if (MotionFlags & PMV_EXTSEARCH8) {  
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
   
                 if (!(MVequal(pmv[0], backupMV))) {  
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, pmv,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
1312                          }                          }
1313            return mask;
1314                  }                  }
1315    
1316                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {  static __inline void
1317                          iSAD =  PreparePredictionsP(VECTOR * const pmv, int x, int y, const int iWcount,
1318                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                          const int iHcount, const MACROBLOCK * const prevMB)
1319                                                                    iMinSAD, &newMV, pmv, min_dx, max_dx, min_dy,  {
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
1320    
1321                          if (iSAD < iMinSAD) {  //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
                 }  
         }  
1322    
1323  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.          if ( (y != 0) && (x != (iWcount-1)) ) {         // [5] top-right neighbour
1324     By performing an optional local half-pixel search, we can refine this result even further.                  pmv[5].x = EVEN(pmv[3].x);
1325  */                  pmv[5].y = EVEN(pmv[3].y);
1326            } else pmv[5].x = pmv[5].y = 0;
1327    
1328            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    PMVfast8_Terminate_with_Refine:          if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }// [4] top neighbour
1332          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step      else pmv[4].x = pmv[4].y = 0;
                 iMinSAD =  
                         Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                         iMinSAD, pmv, min_dx, max_dx, min_dy, max_dy,  
                                                         iFcode, iQuant, iEdgedWidth);  
1333    
1334            // [1] median prediction
1335            pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
1336    
1337    PMVfast8_Terminate_without_Refine:          pmv[0].x = pmv[0].y = 0; // [0] is zero; not used in the loop (checked before) but needed here for make_mask
         currPMV->x = currMV->x - pmv[0].x;  
         currPMV->y = currMV->y - pmv[0].y;  
1338    
1339          return iMinSAD;          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  EPZSSearch16(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,
# Line 1831  Line 1355 
1355                           const int y,                           const int 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  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const uint32_t iHcount = pParam->mb_height;  
1365    
1366          const int32_t iWidth = pParam->width;          int i, iDirection = 255, mask, threshA;
1367          const int32_t iHeight = pParam->height;          VECTOR pmv[7];
1368          const int32_t iEdgedWidth = pParam->edged_width;  
1369            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          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          Data->predMV = pmv[0];
1374    
1375          int32_t min_dx;          Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16;
1376          int32_t max_dx;          Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8;
1377          int32_t min_dy;          Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8;
         int32_t max_dy;  
1378    
1379          VECTOR newMV;          Data->Ref = pRef->y + (x + Data->iEdgedWidth*y) * 16;
1380          VECTOR backupMV;          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          VECTOR pmv[4];          Data->lambda16 = lambda_vec16[iQuant];
1387          int32_t psad[8];          Data->lambda8 = lambda_vec8[iQuant];
1388    
1389          static MACROBLOCK *oldMBs = NULL;          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  //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;          if ((x == 0) && (y == 0)) threshA = 512;
1412          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;          else {
1413          MACROBLOCK *oldMB = NULL;                  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 thresh2;          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
1418          int32_t bPredEq;                                          prevMBs + x + y * pParam->mb_width);
         int32_t iMinSAD, iSAD = 9999;  
1419    
1420          MainSearch16FuncPtr MainSearchPtr;          if (inter4v || pParam->m_quarterpel || Data->chroma) CheckCandidate = CheckCandidate16;
1421            else CheckCandidate = CheckCandidate16no4v;
1422    
1423          if (oldMBs == NULL) {  /* main loop. checking all predictions */
1424                  oldMBs = (MACROBLOCK *) calloc(iWcount * iHcount, sizeof(MACROBLOCK));  
1425  //      fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));          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            if ((Data->iMinSAD[0] <= threshA) ||
1432                            (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                    MainSearchFunc * MainSearchPtr;
1438                    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                    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                                    (*CheckCandidate)(startMV.x, startMV.y, 255, &iDirection, Data);
1457                                    (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
1458                                    if (bSAD < Data->iMinSAD[0]) {
1459                                            Data->currentMV[0] = backupMV;
1460                                            Data->iMinSAD[0] = bSAD; }
1461          }          }
         oldMB = oldMBs + x + y * iWcount;  
1462    
1463  /* Get maximum range */                          backupMV = Data->currentMV[0];
1464          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,                          if (MotionFlags & PMV_HALFPELREFINE16) startMV.x = startMV.y = 1;
1465                            iFcode);                          else startMV.x = startMV.y = 0;
1466                            if (!(MVequal(startMV, backupMV))) {
1467                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1468    
1469                                    (*CheckCandidate)(startMV.x, startMV.y, 255, &iDirection, Data);
1470                                    (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
1471                                    if (bSAD < Data->iMinSAD[0]) {
1472                                            Data->currentMV[0] = backupMV;
1473                                            Data->iMinSAD[0] = bSAD; }
1474                            }
1475                    }
1476            }
1477    
1478            if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(Data);
1479    
1480            for(i = 0; i < 5; i++) {
1481                    Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // initialize qpel vectors
1482                    Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
1483            }
1484    
1485          if (!(MotionFlags & PMV_HALFPEL16)) {          if((pParam->m_quarterpel) && (MotionFlags & PMV_QUARTERPELREFINE16)) {
                 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.  
 */  
1486    
1487  // Prepare for main loop                  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          *currMV = pmv[0];                       /* current best := median prediction */                  QuarterpelRefine(Data);
         if (!(MotionFlags & PMV_HALFPEL16)) {  
                 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          iMinSAD =                  Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
                 sad16(cur,  
                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - pmv[0].x, currMV->y - pmv[0].y,  
                                           (uint8_t) iFcode, iQuant);  
   
 // thresh1 is fixed to 256  
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->mvs[0])) &&  
                  ((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 **************/  
1506    
1507  // previous frame MV                  if (Data->chroma) {
1508          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);                          int sum, dx, dy;
1509    
1510  // set threshhold based on Min of Prediction and SAD of collocated block                          if(pParam->m_quarterpel) {
1511  // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want                                  sum = pMB->qmvs[0].y/2 + pMB->qmvs[1].y/2 + pMB->qmvs[2].y/2 + pMB->qmvs[3].y/2;
1512                            } else sum = pMB->mvs[0].y + pMB->mvs[1].y + pMB->mvs[2].y + pMB->mvs[3].y;
1513                            dy = (sum >> 3) + roundtab_76[sum & 0xf];
1514    
1515          if ((x == 0) && (y == 0)) {                          if(pParam->m_quarterpel) {
1516                  thresh2 = 512;                                  sum = pMB->qmvs[0].x/2 + pMB->qmvs[1].x/2 + pMB->qmvs[2].x/2 + pMB->qmvs[3].x/2;
1517          } else {                          } else sum = pMB->mvs[0].x + pMB->mvs[1].x + pMB->mvs[2].x + pMB->mvs[3].x;
1518  /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */                          dx = (sum >> 3) + roundtab_76[sum & 0xf];
1519    
1520                  thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;                          Data->iMinSAD[1] += ChromaSAD(dx, dy, Data);
1521                    }
1522          }          }
1523    
1524  // MV=(0,0) is often a good choice          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          CHECK_MV16_ZERO;                  pMB->qmvs[0] = pMB->qmvs[1]
1533                            = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1534    
1535                    pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
1536                            pMB->sad8[2] = pMB->sad8[3] =  Data->iMinSAD[0];
1537    
1538  // left neighbour, if allowed                  if(pParam->m_quarterpel) {
1539          if (x != 0) {                          pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predQMV.x;
1540                  if (!(MotionFlags & PMV_HALFPEL16)) {                          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_MV16_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 (y != 0) {  
                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                         pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
1551                  }                  }
                 CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
1552    
1553  // top right neighbour, if allowed  static void
1554                  if ((uint32_t) x != (iWcount - 1)) {  Search8(const SearchData * const OldData,
1555                          if (!(MotionFlags & PMV_HALFPEL16)) {                  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_MV16_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  /* Terminate if MinSAD <= T_2          if (MotionFlags & (PMV_EXTSEARCH8|PMV_HALFPELREFINE8)) {
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
1582    
1583          if ((iMinSAD <= thresh2)                  Data->Ref = OldData->Ref + 8 * ((block&1) + pParam->edged_width*(block>>1));
1584                  || (MVequal(*currMV, prevMB->mvs[0]) &&                  Data->RefH = OldData->RefH + 8 * ((block&1) + pParam->edged_width*(block>>1));
1585                          ((int32_t) iMinSAD <= prevMB->sad16))) {                  Data->RefV = OldData->RefV + 8 * ((block&1) + pParam->edged_width*(block>>1));
1586                  if (MotionFlags & PMV_QUICKSTOP16)                  Data->RefHV = OldData->RefHV + 8 * ((block&1) + pParam->edged_width*(block>>1));
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
         }  
1587    
1588  /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/                  Data->Cur = OldData->Cur + 8 * ((block&1) + pParam->edged_width*(block>>1));
1589    
1590          backupMV = prevMB->mvs[0];      // collocated MV                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1591          backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x);     // acceleration X                                  pParam->width, pParam->height, OldData->iFcode, pParam->m_quarterpel);
1592          backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y);     // acceleration Y                  CheckCandidate = CheckCandidate8;
1593    
1594          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y);                  if (MotionFlags & PMV_EXTSEARCH8) {
1595                            int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
1596    
1597  // left neighbour                          MainSearchFunc *MainSearchPtr;
1598          if (x != 0)                          if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
1599                  CHECK_MV16_CANDIDATE((prevMB - 1)->mvs[0].x, (prevMB - 1)->mvs[0].y);                                  else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1600                                            else MainSearchPtr = DiamondSearch;
1601    
1602  // top neighbour                          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);
         if (y != 0)  
                 CHECK_MV16_CANDIDATE((prevMB - iWcount)->mvs[0].x,  
                                                          (prevMB - iWcount)->mvs[0].y);  
1603    
1604  // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs                          if(*(Data->iMinSAD) < temp_sad) {
1605                                            Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1606                                            Data->currentQMV->y = 2 * Data->currentMV->y;
1607                            }
1608                    }
1609    
1610          if ((uint32_t) x != iWcount - 1)                  if (MotionFlags & PMV_HALFPELREFINE8) {
1611                  CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);                          int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
1612    
1613  // bottom neighbour, dito                          HalfpelRefine(Data); // perform halfpel refine of current best vector
         if ((uint32_t) y != iHcount - 1)  
                 CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,  
                                                          (prevMB + iWcount)->mvs[0].y);  
1614    
1615  /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */                          if(*(Data->iMinSAD) < temp_sad) { // we have found a better match
1616          if (iMinSAD <= thresh2) {                                  Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1617                  if (MotionFlags & PMV_QUICKSTOP16)                                  Data->currentQMV->y = 2 * Data->currentMV->y;
1618                          goto EPZS16_Terminate_without_Refine;                          }
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
1619          }          }
1620    
1621  /************ (if Diamond Search)  **************/                  if(pParam->m_quarterpel) {
1622                            if((!(Data->currentQMV->x & 1)) && (!(Data->currentQMV->y & 1)) &&
1623          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                                  (MotionFlags & PMV_QUARTERPELREFINE8)) {
1624                            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          if (MotionFlags & PMV_USESQUARES16)          if(pParam->m_quarterpel) {
1633                  MainSearchPtr = Square16_MainSearch;                  pMB->pmvs[block].x = Data->currentQMV->x - Data->predQMV.x;
1634          else                  pMB->pmvs[block].y = Data->currentQMV->y - Data->predQMV.y;
1635           if (MotionFlags & PMV_ADVANCEDDIAMOND16)          }
1636                  MainSearchPtr = AdvDiamond16_MainSearch;          else {
1637          else                  pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1638                  MainSearchPtr = Diamond16_MainSearch;                  pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
1639            }
1640    
1641  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          pMB->mvs[block] = *(Data->currentMV);
1642            pMB->qmvs[block] = *(Data->currentQMV);
1643    
1644          iSAD =          pMB->sad8[block] =  4 * (*Data->iMinSAD);
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  
                                                   currMV->y, iMinSAD, &newMV, pmv, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);  
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
1645          }          }
1646    
1647    /* B-frames code starts here */
1648    
1649          if (MotionFlags & PMV_EXTSEARCH16) {  static __inline VECTOR
1650  /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1651    {
1652                  if (!(MVequal(pmv[0], backupMV))) {  /* the stupidiest function ever */
1653                          iSAD =          if (mode == MODE_FORWARD) return pMB->mvs[0];
1654                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,          else return pMB->b_mvs[0];
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, pmv,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   2, iFcode, iQuant, 0);  
1655                  }                  }
1656    
1657                  if (iSAD < iMinSAD) {  static void __inline
1658                          *currMV = newMV;  PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
1659                          iMinSAD = iSAD;                                                          const uint32_t iWcount,
1660                  }                                                          const MACROBLOCK * const pMB,
1661                                                            const uint32_t mode_curr)
1662    {
1663    
1664                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          // [0] is prediction
1665                          iSAD =          pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, pmv, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);  
1666    
1667                          if (iSAD < iMinSAD) {          pmv[1].x = pmv[1].y = 0; // [1] is zero
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
                 }  
         }  
1668    
1669  /***************        Choose best MV found     **************/          pmv[2] = ChoosePred(pMB, mode_curr);
1670            pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
1671    
1672    EPZS16_Terminate_with_Refine:          if ((y != 0)&&(x != (int)(iWcount+1))) {                        // [3] top-right neighbour
1673          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step                  pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
1674                  iMinSAD =                  pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
1675                          Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,          } else pmv[3].x = pmv[3].y = 0;
                                                          iMinSAD, pmv, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
1676    
1677    EPZS16_Terminate_without_Refine:          if (y != 0) {
1678                    pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
1679                    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          *oldMB = *prevMB;          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          currPMV->x = currMV->x - pmv[0].x;  // more?
         currPMV->y = currMV->y - pmv[0].y;  
         return iMinSAD;  
1693  }  }
1694    
1695    
1696  int32_t  /* search backward or forward, for b-frames */
1697  EPZSSearch8(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,  
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  {  {
 /* Please not that EPZS might not be a good choice for 8x8-block motion search ! */  
1713    
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
1714          const int32_t iEdgedWidth = pParam->edged_width;          const int32_t iEdgedWidth = pParam->edged_width;
1715    
1716          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;          int i, iDirection, mask;
1717            VECTOR pmv[7];
1718          int32_t iDiamondSize = 1;          MainSearchFunc *MainSearchPtr;
1719            *Data->iMinSAD = MV_MAX_ERROR;
1720          int32_t min_dx;          Data->iFcode = iFcode;
1721          int32_t max_dx;  
1722          int32_t min_dy;          Data->Ref = pRef + (x + y * iEdgedWidth) * 16;
1723          int32_t max_dy;          Data->RefH = pRefH + (x + y * iEdgedWidth) * 16;
1724            Data->RefV = pRefV + (x + y * iEdgedWidth) * 16;
1725          VECTOR newMV;          Data->RefHV = pRefHV + (x + y * iEdgedWidth) * 16;
1726          VECTOR backupMV;  
1727            Data->predMV = *predMV;
1728          VECTOR pmv[4];  
1729          int32_t psad[8];          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          const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);          if (MotionFlags & PMV_USESQUARES16)
1747                    MainSearchPtr = SquareSearch;
1748            else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
1749                    MainSearchPtr = AdvDiamondSearch;
1750                    else MainSearchPtr = DiamondSearch;
1751    
1752  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);
         const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;  
1753    
1754          int32_t bPredEq;          HalfpelRefine(Data);
         int32_t iMinSAD, iSAD = 9999;  
1755    
1756          MainSearch8FuncPtr MainSearchPtr;          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 {
1781                            pMB->pmvs[0].x = Data->currentMV->x - predMV->x;
1782                            pMB->pmvs[0].y = Data->currentMV->y - predMV->y;
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    
1789  /* Get maximum range */          }
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,  
                           iFcode);  
1790    
1791  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  }
1792    
1793          if (!(MotionFlags & PMV_HALFPEL8)) {  static int32_t
1794                  min_dx = EVEN(min_dx);  SearchDirect(const IMAGE * const f_Ref,
1795                  max_dx = EVEN(max_dx);                                  const uint8_t * const f_RefH,
1796                  min_dy = EVEN(min_dy);                                  const uint8_t * const f_RefV,
1797                  max_dy = EVEN(max_dy);                                  const uint8_t * const f_RefHV,
1798                                    const IMAGE * const b_Ref,
1799                                    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            for (k = 0; k < 4; k++) {
1842                    pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);
1843                    pMB->b_mvs[k].x = Data->directmvB[k].x = ((TRB - TRD) * Data->referencemv[k].x) / TRD;
1844                    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    
1847                    if ( ( pMB->b_mvs[k].x > Data->max_dx ) || ( pMB->b_mvs[k].x < Data->min_dx )
1848                            || ( pMB->b_mvs[k].y > Data->max_dy ) || ( pMB->b_mvs[k].y < Data->min_dy )) {
1849    
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          }          }
         /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
         //bPredEq = get_pmvdata(pMBs, x >> 1, y >> 1, iWcount, iSubBlock, pmv, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, x >> 1, y >> 1, iSubBlock, pmv, psad);  
1863    
1864            if (Data->qpel) {
1865                            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  /* Step 4: Calculate SAD around the Median prediction.          (*CheckCandidate)(0, 0, 255, &k, Data);
         MinSAD=SAD  
         If Motion Vector equal to Previous frame motion vector  
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
 */  
1874    
1875  // Prepare for main loop  // skip decision
1876            if (*Data->iMinSAD < pMB->quant * SKIP_THRESH_B) {
1877                    //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    
1881                    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                    } else {
1893                            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                            dy = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1897    
1898          if (!(MotionFlags & PMV_HALFPEL8)) {                          sum = pMB->b_mvs[0].x + pMB->b_mvs[1].x + pMB->b_mvs[2].x + pMB->b_mvs[3].x;
1899                  currMV->x = EVEN(currMV->x);                          b_dx = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1900                  currMV->y = EVEN(currMV->y);                          sum = pMB->b_mvs[0].y + pMB->b_mvs[1].y + pMB->b_mvs[2].y + pMB->b_mvs[3].y;
1901                            b_dy = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1902          }          }
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                                            b_Ref->u + (y*8 + b_dy/2) * (Data->iEdgedWidth/2) + x*8 + b_dx/2,
1906                                            Data->iEdgedWidth/2);
1907                    sum += sad8bi(pCur->v + 8*x + 8*y*(Data->iEdgedWidth/2),
1908                                            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                                            Data->iEdgedWidth/2);
1911    
1912          if (currMV->x > max_dx)                  if (sum < MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) {
1913                  currMV->x = max_dx;                          pMB->mode = MODE_DIRECT_NONE_MV;
1914          if (currMV->x < min_dx)                          return *Data->iMinSAD;
1915                  currMV->x = min_dx;                  }
1916          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 ******************/  
1917    
1918            skip_sad = *Data->iMinSAD;
1919    
1920          iMinSAD =  //  DIRECT MODE DELTA VECTOR SEARCH.
1921                  sad8(cur,  //      This has to be made more effective, but at the moment I'm happy it's running at all
                          get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  
                                                 iEdgedWidth), iEdgedWidth);  
         iMinSAD +=  
                 calc_delta_8(currMV->x - pmv[0].x, currMV->y - pmv[0].y,  
                                          (uint8_t) iFcode, iQuant);  
1922    
1923            if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1924                    else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1925                            else MainSearchPtr = DiamondSearch;
1926    
1927  // thresh1 is fixed to 256          (*MainSearchPtr)(0, 0, Data, 255);
         if (iMinSAD < 256 / 4) {  
                 if (MotionFlags & PMV_QUICKSTOP8)  
                         goto EPZS8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
         }  
1928    
1929  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/          HalfpelRefine(Data); //or qpel refine, if we're in qpel mode
1930    
1931            *Data->iMinSAD +=  1 * Data->lambda16; // one bit is needed to code direct mode
1932            *best_sad = *Data->iMinSAD;
1933    
1934  // MV=(0,0) is often a good choice          if (b_mb->mode == MODE_INTER4V)
1935          CHECK_MV8_ZERO;                  pMB->mode = MODE_DIRECT;
1936            else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation
1937    
1938  // previous frame MV          pMB->pmvs[3] = *Data->currentMV;
         CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x, prevMB->mvs[iSubBlock].y);  
1939    
1940  // left neighbour, if allowed          for (k = 0; k < 4; k++) {
1941          if (psad[1] != MV_MAX_ERROR) {                  pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
1942                  if (!(MotionFlags & PMV_HALFPEL8)) {                  pMB->b_mvs[k].x = (     (Data->currentMV->x == 0)
1943                          pmv[1].x = EVEN(pmv[1].x);                                                          ? Data->directmvB[k].x
1944                          pmv[1].y = EVEN(pmv[1].y);                                                          :pMB->mvs[k].x - Data->referencemv[k].x);
1945                  }                  pMB->mvs[k].y = (Data->directmvF[k].y + Data->currentMV->y);
1946                  CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);                  pMB->b_mvs[k].y = ((Data->currentMV->y == 0)
1947          }                                                          ? Data->directmvB[k].y
1948  // top neighbour, if allowed                                                          : pMB->mvs[k].y - Data->referencemv[k].y);
1949          if (psad[2] != MV_MAX_ERROR) {                  if (Data->qpel) {
1950                  if (!(MotionFlags & PMV_HALFPEL8)) {                          pMB->qmvs[k].x = pMB->mvs[k].x; pMB->mvs[k].x /= 2;
1951                          pmv[2].x = EVEN(pmv[2].x);                          pMB->b_qmvs[k].x = pMB->b_mvs[k].x; pMB->b_mvs[k].x /= 2;
1952                          pmv[2].y = EVEN(pmv[2].y);                          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                  }                  }
                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
1955    
1956  // top right neighbour, if allowed                  if (b_mb->mode != MODE_INTER4V) {
1957                  if (psad[3] != MV_MAX_ERROR) {                          pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1958                          if (!(MotionFlags & PMV_HALFPEL8)) {                          pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1959                                  pmv[3].x = EVEN(pmv[3].x);                          pMB->qmvs[3] = pMB->qmvs[2] = pMB->qmvs[1] = pMB->qmvs[0];
1960                                  pmv[3].y = EVEN(pmv[3].y);                          pMB->b_qmvs[3] = pMB->b_qmvs[2] = pMB->b_qmvs[1] = pMB->b_qmvs[0];
1961                            break;
1962                          }                          }
                         CHECK_MV8_CANDIDATE(pmv[3].x, pmv[3].y);  
1963                  }                  }
1964            return skip_sad;
1965          }          }
1966    
 /*  // this bias is zero anyway, at the moment!  
1967    
1968          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)  static __inline void
1969                  iMinSAD -= MV8_00_BIAS;  SearchInterpolate(const uint8_t * const f_Ref,
1970                                    const uint8_t * const f_RefH,
1971                                    const uint8_t * const f_RefV,
1972                                    const uint8_t * const f_RefHV,
1973                                    const uint8_t * const b_Ref,
1974                                    const uint8_t * const b_RefH,
1975                                    const uint8_t * const b_RefV,
1976                                    const uint8_t * const b_RefHV,
1977                                    const IMAGE * const pCur,
1978                                    const int x, const int y,
1979                                    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  */  {
1990    
1991  /* Terminate if MinSAD <= T_2          const int32_t iEdgedWidth = pParam->edged_width;
1992     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]          int iDirection, i, j;
1993  */          SearchData bData;
1994    
1995          if (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */          *(bData.iMinSAD = fData->iMinSAD) = 4096*256;
1996                  if (MotionFlags & PMV_QUICKSTOP8)          bData.Cur = fData->Cur;
1997                          goto EPZS8_Terminate_without_Refine;          fData->iEdgedWidth = bData.iEdgedWidth = iEdgedWidth;
1998                  if (MotionFlags & PMV_EARLYSTOP8)          bData.currentMV = fData->currentMV + 1; bData.currentQMV = fData->currentQMV + 1;
1999                          goto EPZS8_Terminate_with_Refine;          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  /************ (Diamond Search)  **************/          CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, 255, &iDirection, fData);
2030    
2031          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  //diamond. I wish we could use normal mainsearch functions (square, advdiamond)
2032    
2033          if (!(MotionFlags & PMV_HALFPELDIAMOND8))          do {
2034                  iDiamondSize *= 2;                  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  /* default: use best prediction as starting point for one call of EPZS_MainSearch */  void
2090    MotionEstimationBVOP(MBParam * const pParam,
2091                                             FRAMEINFO * const frame,
2092                                             const int32_t time_bp,
2093                                             const int32_t time_pp,
2094                                             // forward (past) reference
2095                                             const MACROBLOCK * const f_mbs,
2096                                             const IMAGE * const f_ref,
2097                                             const IMAGE * const f_refH,
2098                                             const IMAGE * const f_refV,
2099                                             const IMAGE * const f_refHV,
2100                                             // backward (future) reference
2101                                             const FRAMEINFO * const b_reference,
2102                                             const IMAGE * const b_ref,
2103                                             const IMAGE * const b_refH,
2104                                             const IMAGE * const b_refV,
2105                                             const IMAGE * const b_refHV)
2106    {
2107            uint32_t i, j;
2108            int32_t best_sad, skip_sad;
2109            int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;
2110            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            const int32_t TRB = time_pp - time_bp;
2116            const int32_t TRD = time_pp;
2117            uint8_t * qimage;
2118    
2119    // some pre-inintialized data for the rest of the search
2120    
2121            SearchData Data;
2122            int32_t iMinSAD;
2123            VECTOR currentMV[3];
2124            VECTOR currentQMV[3];
2125            Data.iEdgedWidth = pParam->edged_width;
2126            Data.currentMV = currentMV; Data.currentQMV = currentQMV;
2127            Data.iMinSAD = &iMinSAD;
2128            Data.lambda16 = lambda_vec16[frame->quant];
2129            Data.qpel = pParam->m_quarterpel;
2130    
2131            if((qimage = (uint8_t *) malloc(32 * pParam->edged_width)) == NULL)
2132                    return; // allocate some mem for qpel interpolated blocks
2133                                      // 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    
2137  // there is no EPZS^2 for inter4v at the moment          // note: i==horizontal, j==vertical
2138            for (j = 0; j < pParam->mb_height; j++) {
2139    
2140  //  if (MotionFlags & PMV_USESQUARES8)                  f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
 //      MainSearchPtr = Square8_MainSearch;  
 //  else  
2141    
2142          if (MotionFlags & PMV_ADVANCEDDIAMOND8)                  for (i = 0; i < pParam->mb_width; i++) {
2143                  MainSearchPtr = AdvDiamond8_MainSearch;                          MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
2144          else                          const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
2145                  MainSearchPtr = Diamond8_MainSearch;  
2146    /* special case, if collocated block is SKIPed in P-VOP: encoding is forward (0,0), cpb=0 without further ado */
2147                            if (b_reference->coding_type != S_VOP)
2148                                    if (b_mb->mode == MODE_NOT_CODED) {
2149                                            pMB->mode = MODE_NOT_CODED;
2150                                            continue;
2151                                    }
2152    
2153          iSAD =                          Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
2154                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,                          pMB->quant = frame->quant;
                                                   currMV->y, iMinSAD, &newMV, pmv, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, 0);  
2155    
2156    /* 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          if (iSAD < iMinSAD) {                          if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
2170    
2171          if (MotionFlags & PMV_EXTSEARCH8) {                          // forward search
2172  /* extended mode: search (up to) two more times: orignal prediction and (0,0) */                          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                  if (!(MVequal(pmv[0], backupMV))) {                          // backward search
2180                          iSAD =                          SearchBF(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
2181                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                                  &frame->image, i, j,
2182                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, pmv,                                                  frame->motion_flags,
2183                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,                                                  frame->bcode, pParam,
2184                                                                    iDiamondSize, iFcode, iQuant, 0);                                                  pMB, &b_predMV, &best_sad,
2185                                                    MODE_BACKWARD, &Data);
2186    
2187                          if (iSAD < iMinSAD) {                          // interpolate search comes last, because it uses data from forward and backward as prediction
2188                                  *currMV = newMV;  /*
2189                                  iMinSAD = iSAD;                          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                            switch (pMB->mode) {
2201                                    case MODE_FORWARD:
2202                                            f_count++;
2203                                            if (pParam->m_quarterpel) f_predMV = pMB->qmvs[0];
2204                                            else f_predMV = pMB->mvs[0];
2205                                            break;
2206                                    case MODE_BACKWARD:
2207                                            b_count++;
2208                                            if (pParam->m_quarterpel) b_predMV = pMB->b_qmvs[0];
2209                                            else b_predMV = pMB->b_mvs[0];
2210                                            break;
2211                                    case MODE_INTERPOLATE:
2212                                            i_count++;
2213                                            if (pParam->m_quarterpel) {
2214                                                    f_predMV = pMB->qmvs[0];
2215                                                    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                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                                  case MODE_DIRECT:
2222                          iSAD =                                  case MODE_DIRECT_NO4V:
2223                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                                          d_count++;
2224                                                                    iMinSAD, &newMV, pmv, min_dx, max_dx, min_dy,                                          break;
2225                                                                    max_dy, iEdgedWidth, iDiamondSize, iFcode,                                  default:
2226                                                                    iQuant, 0);                                          break;
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
2227                          }                          }
2228                  }                  }
2229          }          }
2230            free(qimage);
 /***************        Choose best MV found     **************/  
   
   EPZS8_Terminate_with_Refine:  
         if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step  
                 iMinSAD =  
                         Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                         iMinSAD, pmv, min_dx, max_dx, min_dy, max_dy,  
                                                         iFcode, iQuant, iEdgedWidth);  
   
   EPZS8_Terminate_without_Refine:  
   
         currPMV->x = currMV->x - pmv[0].x;  
         currPMV->y = currMV->y - pmv[0].y;  
         return iMinSAD;  
2231  }  }
2232    
2233    /* Hinted ME starts here */
2234    
2235    static void
2236  int32_t  SearchPhinted ( const IMAGE * const pRef,
 PMVfastIntSearch16(const uint8_t * const pRef,  
2237                                  const uint8_t * const pRefH,                                  const uint8_t * const pRefH,
2238                                  const uint8_t * const pRefV,                                  const uint8_t * const pRefV,
2239                                  const uint8_t * const pRefHV,                                  const uint8_t * const pRefHV,
# Line 2357  Line 2242 
2242                                  const int y,                                  const int y,
2243                                  const uint32_t MotionFlags,                                  const uint32_t MotionFlags,
2244                                  const uint32_t iQuant,                                  const uint32_t iQuant,
                                 const uint32_t iFcode,  
2245                                  const MBParam * const pParam,                                  const MBParam * const pParam,
2246                                  const MACROBLOCK * const pMBs,                                  const MACROBLOCK * const pMBs,
2247                                  const MACROBLOCK * const prevMBs,                                  int inter4v,
2248                                  VECTOR * const currMV,                                  MACROBLOCK * const pMB,
2249                                  VECTOR * const currPMV)                                  SearchData * const Data)
2250  {  {
2251          const uint32_t iWcount = pParam->mb_width;  
2252          const int32_t iWidth = pParam->width;          int i, t;
2253          const int32_t iHeight = pParam->height;          MainSearchFunc * MainSearchPtr;
2254          const int32_t iEdgedWidth = pParam->edged_width;  
2255            Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
2256          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          Data->predQMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
2257          const VECTOR zeroMV = { 0, 0 };          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          int32_t iDiamondSize;  
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          int32_t min_dx;          if (!(MotionFlags & PMV_HALFPEL16)) {
2272          int32_t max_dx;                  Data->min_dx = EVEN(Data->min_dx);
2273          int32_t min_dy;                  Data->max_dx = EVEN(Data->max_dx);
2274          int32_t max_dy;                  Data->min_dy = EVEN(Data->min_dy);
2275                    Data->max_dy = EVEN(Data->max_dy);
2276          int32_t iFound;          }
2277    
2278          VECTOR newMV;          for(i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;
2279          VECTOR backupMV;                        /* just for PMVFAST */  
2280            if (pMB->dquant != NO_CHANGE) inter4v = 0;
2281          VECTOR pmv[4];  
2282          int32_t psad[4];          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          MainSearch16FuncPtr MainSearchPtr;          if (MotionFlags & PMV_USESQUARES16)
2303                    MainSearchPtr = SquareSearch;
2304            else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
2305                    MainSearchPtr = AdvDiamondSearch;
2306                    else MainSearchPtr = DiamondSearch;
2307    
2308          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);
         MACROBLOCK *const pMB = pMBs + x + y * iWcount;  
2309    
2310          int32_t threshA, threshB;          if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(Data);
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD;  
2311    
2312  /* Get maximum range */          for(i = 0; i < 5; i++) {
2313          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // initialize qpel vectors
2314                            iFcode);                  Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
2315            }
2316    
2317            if((pParam->m_quarterpel) && (MotionFlags & PMV_QUARTERPELREFINE16)) {
2318                    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                    CheckCandidate = CheckCandidate16_qpel;
2321                    QuarterpelRefine(Data);
2322            }
2323    
2324            if (inter4v) {
2325                    SearchData Data8;
2326                    Data8.iFcode = Data->iFcode;
2327                    Data8.lambda8 = Data->lambda8;
2328                    Data8.iEdgedWidth = Data->iEdgedWidth;
2329                    Data8.RefQ = Data->RefQ;
2330                    Data8.qpel = Data->qpel;
2331                    Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
2332                    Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
2333                    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    
2336                    if (Data->chroma) {
2337                            int sum, dx, dy;
2338    
2339                            if(pParam->m_quarterpel)
2340                                    sum = (pMB->qmvs[0].y/2 + pMB->qmvs[1].y/2 + pMB->qmvs[2].y/2 + pMB->qmvs[3].y/2);
2341                            else sum = pMB->mvs[0].y + pMB->mvs[1].y + pMB->mvs[2].y + pMB->mvs[3].y;
2342                            dy = (sum ? SIGN(sum) *
2343                                      (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2) : 0);
2344    
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  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          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          if ((x == 0) && (y == 0)) {                  pMB->qmvs[0] = pMB->qmvs[1]
2363                  threshA = 512;                          = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
                 threshB = 1024;  
2364    
2365                  bPredEq = 0;                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
2366                  psad[0] = psad[1] = psad[2] = psad[3] = 0;                          pMB->sad8[2] = pMB->sad8[3] =  Data->iMinSAD[0];
                 *currMV = pmv[0] = pmv[1] = pmv[2] = pmv[3] = zeroMV;  
2367    
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 {          } else {
2372                  threshA = psad[0];                          pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
2373                  threshB = threshA + 256;                          pMB->pmvs[0].y = Data->currentMV[0].y - Data->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 */  
         }  
   
         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);  
2374          }          }
2375          if (currMV->x < min_dx) {          } else {
2376                  currMV->x = EVEN(min_dx);  // INTER4V MODE; all other things are already set in Search8
2377          }                  pMB->mode = MODE_INTER4V;
2378          if (currMV->y > max_dy) {                  pMB->sad16 = Data->iMinSAD[1] + Data->iMinSAD[2] + Data->iMinSAD[3]
2379                  currMV->y = EVEN(max_dy);                                                  + Data->iMinSAD[4] + IMV16X16 * iQuant;
         }  
         if (currMV->y < min_dy) {  
                 currMV->y = EVEN(min_dy);  
2380          }          }
2381    
2382          iMinSAD =  }
                 sad16(cur,  
                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - pmv[0].x, currMV->y - pmv[0].y,  
                                           (uint8_t) iFcode, iQuant);  
2383    
2384          if ((iMinSAD < 256) ||  void
2385                  ((MVequal(*currMV, prevMB->i_mvs[0])) &&  MotionEstimationHinted( MBParam * const pParam,
2386                   ((int32_t) iMinSAD < prevMB->i_sad16))) {                                                  FRAMEINFO * const current,
2387                  if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode                                                  FRAMEINFO * const reference,
2388                                                    const IMAGE * const pRefH,
2389                                                    const IMAGE * const pRefV,
2390                                                    const IMAGE * const pRefHV)
2391                  {                  {
2392                          if (!MVzero(*currMV)) {          MACROBLOCK *const pMBs = current->mbs;
2393                                  iMinSAD += MV16_00_BIAS;          const IMAGE *const pCurrent = &current->image;
2394                                  CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures          const IMAGE *const pRef = &reference->image;
                                 iMinSAD -= MV16_00_BIAS;  
                         }  
                 }  
2395    
2396                  if (MotionFlags & PMV_EARLYSTOP16)          uint32_t x, y;
2397                          goto PMVfastInt16_Terminate_with_Refine;          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                            SearchPhinted(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
2442                                                            y, current->motion_flags, pMB->quant,
2443                                                            pParam, pMBs, current->global_flags & XVID_INTER4V, pMB,
2444                                                            &Data);
2445    
2446  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion                  }
2447     vector of the median.          }
2448     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2          free(qimage);
2449  */  }
2450    
2451          if ((bPredEq) && (MVequal(pmv[0], prevMB->i_mvs[0])))  static __inline int
2452                  iFound = 2;  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  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          int i = 255, mask;
2463     Otherwise select large Diamond Search.          VECTOR pmv[3];
2464  */          *(Data->iMinSAD) = MV_MAX_ERROR;
2465    
2466          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))          //median is only used as prediction. it doesn't have to be real
2467                  iDiamondSize = 2;               // halfpel units!          if (x == 1 && y == 1) Data->predMV.x = Data->predMV.y = 0;
2468          else          else
2469                  iDiamondSize = 4;               // halfpel units!                  if (x == 1) //left macroblock does not have any vector now
2470                            Data->predMV = (pMB - pParam->mb_width)->mvs[0]; // top instead of median
2471  /*                  else if (y == 1) // top macroblock don't have it's vector
2472     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.                          Data->predMV = (pMB - 1)->mvs[0]; // left instead of median
2473     Also calculate (0,0) but do not subtract offset.                          else Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); //else median
2474     Let MinSAD be the smallest SAD up to this point.  
2475     If MV is (0,0) subtract offset.          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  // (0,0) is often a good choice          Data->Cur = pCur + (x + y * pParam->edged_width) * 16;
2479            Data->Ref = pRef + (x + y * pParam->edged_width) * 16;
2480          if (!MVzero(pmv[0]))  
2481                  CHECK_MV16_ZERO;          pmv[1].x = EVEN(pMB->mvs[0].x);
2482            pmv[1].y = EVEN(pMB->mvs[0].y);
2483  // previous frame MV is always possible          pmv[2].x = EVEN(Data->predMV.x);
2484            pmv[2].y = EVEN(Data->predMV.y);
2485          if (!MVzero(prevMB->i_mvs[0]))          pmv[0].x = pmv[0].y = 0;
2486                  if (!MVequal(prevMB->i_mvs[0], pmv[0]))  
2487                          CHECK_MV16_CANDIDATE(prevMB->i_mvs[0].x, prevMB->i_mvs[0].y);          (*CheckCandidate)(0, 0, 255, &i, Data);
2488    
2489  // left neighbour, if allowed  //early skip for 0,0
2490            if (*Data->iMinSAD < MAX_SAD00_FOR_SKIP * 4) {
2491          if (!MVzero(pmv[1]))                  pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
2492                  if (!MVequal(pmv[1], prevMB->i_mvs[0]))                  pMB->mode = MODE_NOT_CODED;
2493                          if (!MVequal(pmv[1], pmv[0]))                  return 0;
2494                                  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;  
   
2495    
2496  /* Step 6: If MinSAD <= thresa goto Step 10.          if (!(mask = make_mask(pmv, 1)))
2497     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.                  (*CheckCandidate)(pmv[1].x, pmv[1].y, mask, &i, Data);
2498  */          if (!(mask = make_mask(pmv, 2)))
2499                    (*CheckCandidate)(pmv[2].x, pmv[2].y, mask, &i, Data);
2500    
2501          if ((iMinSAD <= threshA) ||          if (*Data->iMinSAD > MAX_SAD00_FOR_SKIP * 4) // diamond only if needed
2502                  (MVequal(*currMV, prevMB->i_mvs[0]) &&                  DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, i);
                  ((int32_t) iMinSAD < prevMB->i_sad16))) {  
2503    
2504                  if (MotionFlags & PMV_EARLYSTOP16)          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
2505                          goto PMVfastInt16_Terminate_with_Refine;          pMB->mode = MODE_INTER;
2506            return *(Data->iMinSAD);
2507          }          }
2508    
2509    #define INTRA_THRESH    1350
2510    #define INTER_THRESH    900
2511    
 /************ (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.  
 */  
2512    
2513          if (MotionFlags & PMV_USESQUARES16)  int
2514                  MainSearchPtr = Square16_MainSearch;  MEanalysis(     const IMAGE * const pRef,
2515          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)                          FRAMEINFO * const Current,
2516                  MainSearchPtr = AdvDiamond16_MainSearch;                          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                  MainSearchPtr = Diamond16_MainSearch;                  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    
         backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  
2542    
2543            InterThresh += 300 * (1 - bCount);
2544            if (InterThresh < 200) InterThresh = 200;
2545    
2546  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          if (sadInit) (*sadInit) ();
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  
                                                   currMV->y, iMinSAD, &newMV, pmv, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
2547    
2548          if (iSAD < iMinSAD) {          for (y = 1; y < pParam->mb_height-1; y++) {
2549                  *currMV = newMV;                  for (x = 1; x < pParam->mb_width-1; x++) {
2550                  iMinSAD = iSAD;                          int sad, dev;
2551          }                          MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
2552    
2553          if (MotionFlags & PMV_EXTSEARCH16) {                          sad = MEanalyzeMB(pRef->y, pCurrent->y, x, y,
2554  /* extended: search (up to) two more times: orignal prediction and (0,0) */                                                                  pParam, pMBs, pMB, &Data);
2555    
2556                  if (!(MVequal(pmv[0], backupMV))) {                          if (sad > IntraThresh) {
2557                          iSAD =                                  dev = dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,
2558                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                                            pParam->edged_width);
2559                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, pmv,                                  if (dev + IntraThresh < sad) {
2560                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,                                          pMB->mode = MODE_INTRA;
2561                                                                    iDiamondSize, iFcode, iQuant, iFound);                                          if (++intra > (pParam->mb_height-2)*(pParam->mb_width-2)/2) return 2;  // I frame
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
2562                          }                          }
2563                  }                  }
2564                            sSAD += sad;
                 if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {  
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, pmv, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
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     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  FindFcode(      const MBParam * const pParam,
2576  */                          const FRAMEINFO * const current)
2577    {
2578            uint32_t x, y;
2579            int max = 0, min = 0, i;
2580    
2581  PMVfastInt16_Terminate_with_Refine:          for (y = 0; y < pParam->mb_height; y++) {
2582                    for (x = 0; x < pParam->mb_width; x++) {
2583    
2584          pMB->i_mvs[0] = pMB->i_mvs[1] = pMB->i_mvs[2] = pMB->i_mvs[3] = pMB->i_mv16 = *currMV;                          MACROBLOCK *pMB = &current->mbs[x + y * pParam->mb_width];
2585          pMB->i_sad8[0] = pMB->i_sad8[1] = pMB->i_sad8[2] = pMB->i_sad8[3] = pMB->i_sad16 = iMinSAD;                          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 (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step                                  if (pMB->mvs[i].x < min) min = pMB->mvs[i].x;
2590                  iMinSAD =                                  if (pMB->mvs[i].y < min) min = pMB->mvs[i].y;
2591                          Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,                          }
2592                                                           iMinSAD, pmv, min_dx, max_dx, min_dy, max_dy,                  }
2593                                                           iFcode, iQuant, iEdgedWidth);          }
2594    
2595          pmv[0] = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          // get _REAL_ prediction (halfpel possible)          min = -min;
2596            max += 1;
2597            if (min > max) max = min;
2598            if (pParam->m_quarterpel) max *= 2;
2599    
2600  PMVfastInt16_Terminate_without_Refine:          for (i = 1; (max > 32 << (i - 1)); i++);
2601          currPMV->x = currMV->x - pmv[0].x;          return i;
         currPMV->y = currMV->y - pmv[0].y;  
         return iMinSAD;  
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            uint32_t mx, my, a, count = 0;
2610    
2611            for (my = 1; my < pParam->mb_height-1; my++)
2612                    for (mx = 1; mx < pParam->mb_width-1; mx++) {
2613                            VECTOR mv;
2614                            const MACROBLOCK *pMB = &pMBs[mx + my * pParam->mb_width];
2615                            if (pMB->mode == MODE_INTRA || pMB->mode == MODE_NOT_CODED) continue;
2616                            mv = pMB->mvs[0];
2617                            a = ABS(mv.x - x) + ABS(mv.y - y);
2618                            if (a < 6) count += 6 - a;
2619                    }
2620    
2621  /* ***********************************************************          if (count > *bestcount) {
2622          bvop motion estimation                  *bestcount = count;
2623  // TODO: need to incorporate prediction here (eg. sad += calc_delta_16)                  *iDirection = dir;
2624  ***************************************************************/                  GMC->x = x; GMC->y = y;
2625            }
2626    }
2627    
2628    
2629  void  static VECTOR
2630  MotionEstimationBVOP(MBParam * const pParam,  GlobalMotionEst(const MACROBLOCK * const pMBs, const MBParam * const pParam, const uint32_t iFcode)
                                          FRAMEINFO * const frame,  
                                          // forward (past) reference  
                                          const MACROBLOCK * const f_mbs,  
                                          const IMAGE * const f_ref,  
                                          const IMAGE * const f_refH,  
                                          const IMAGE * const f_refV,  
                                          const IMAGE * const f_refHV,  
                                          // backward (future) reference  
                                          const MACROBLOCK * const b_mbs,  
                                          const IMAGE * const b_ref,  
                                          const IMAGE * const b_refH,  
                                          const IMAGE * const b_refV,  
                                          const IMAGE * const b_refHV)  
2631  {  {
         const uint32_t mb_width = pParam->mb_width;  
         const uint32_t mb_height = pParam->mb_height;  
         const int32_t edged_width = pParam->edged_width;  
2632    
2633          uint32_t i, j;          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          int32_t f_sad16;          min_x = min_y = -32<<iFcode;
2641          int32_t b_sad16;          max_x = max_y = 32<<iFcode;
         int32_t i_sad16;  
         int32_t d_sad16;  
         int32_t best_sad;  
2642    
2643          VECTOR pmv_dontcare;  //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          // note: i==horizontal, j==vertical                                                  if (pMB->mode == MODE_INTRA || pMB->mode == MODE_NOT_CODED)
         for (j = 0; j < mb_height; j++) {  
                 for (i = 0; i < mb_width; i++) {  
                         MACROBLOCK *mb = &frame->mbs[i + j * mb_width];  
                         const MACROBLOCK *f_mb = &f_mbs[i + j * mb_width];  
                         const MACROBLOCK *b_mb = &b_mbs[i + j * mb_width];  
   
                         if (b_mb->mode == MODE_INTER && b_mb->cbp == 0 &&  
                                 b_mb->mvs[0].x == 0 && b_mb->mvs[0].y == 0) {  
                                 mb->mode = MODE_NOT_CODED;  
                                 mb->mvs[0].x = 0;  
                                 mb->mvs[0].y = 0;  
                                 mb->b_mvs[0].x = 0;  
                                 mb->b_mvs[0].y = 0;  
                                 continue;  
                         }  
                 /* force F_SAD16  
                         f_sad16 = 100;  
                         b_sad16 = 65535;  
   
                         mb->mode = MODE_FORWARD;  
                         mb->mvs[0].x = 1;  
                         mb->mvs[0].y = 1;  
                         mb->b_mvs[0].x = 1;  
                         mb->b_mvs[0].y = 1;  
2656                          continue;                          continue;
                  ^^ force F_SAD16 */  
   
2657    
2658                          // forward search                                                  mv = pMB->mvs[0];
2659                          f_sad16 =                                                  if ( ABS(mv.x - x) <= step && ABS(mv.y - y) <= step )   /* GMC translation is always halfpel-res */
2660                                  SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,                                                          count++;
2661                                                   &frame->image, i, j, frame->motion_flags,                                          }
2662                                                   frame->quant, frame->fcode, pParam,                                  if (count >= bestcount) { bestcount = count; gmc.x = x; gmc.y = y; }
2663                                                   f_mbs,  f_mbs, /* todo */                          }
2664                                                   &mb->mvs[0], &pmv_dontcare);   // ignore pmv                  min_x = gmc.x - step;
2665                    max_x = gmc.x + step;
2666                          // backward search                  min_y = gmc.y - step;
2667                          b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,                  max_y = gmc.y + step;
                                                 &frame->image, i, j, frame->motion_flags,  
                                                 frame->quant, frame->bcode, pParam,  
                                                 b_mbs, b_mbs,   /* todo */  
                                                 &mb->b_mvs[0], &pmv_dontcare);  // ignore pmv  
   
                         // interpolate search (simple, but effective)  
                         i_sad16 = 65535;  
   
                         /*  
                         x/y range somewhat buggy  
                         i_sad16 =  
                                 sad16bi_c(frame->image.y + i * 16 + j * 16 * edged_width,  
                                                   get_ref(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                   i, j, 16, mb->mvs[0].x, mb->mvs[0].y,  
                                                                   edged_width), get_ref(b_ref->y, b_refH->y,  
                                                                                                                 b_refV->y, b_refHV->y,  
                                                                                                                 i, j, 16,  
                                                                                                                 mb->b_mvs[0].x,  
                                                                                                                 mb->b_mvs[0].x,  
                                                                                                                 edged_width),  
                                                   edged_width);  
                         */  
2668    
2669                          // TODO: direct search          }
                         // predictor + range of [-32,32]  
                         d_sad16 = 65535;  
2670    
2671            if (bestcount < (pParam->mb_height-2)*(pParam->mb_width-2)/10)
2672                    gmc.x = gmc.y = 0; //no camara pan, no GMC
2673    
2674                          if (f_sad16 < b_sad16) {  // step2: let's refine camera panning using gradiend-descent approach.
2675                                  best_sad = f_sad16;  // TODO: more warping points may be evaluated here (like in interpolate mode search - two vectors in one diamond)
2676                                  mb->mode = MODE_FORWARD;          bestcount = 0;
2677                          } else {          CheckGMC(gmc.x, gmc.y, 255, &iDirection, pMBs, &bestcount, &gmc, pParam);
2678                                  best_sad = b_sad16;          do {
2679                                  mb->mode = MODE_BACKWARD;                  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                          if (i_sad16 < best_sad) {          } while (iDirection);
                                 best_sad = i_sad16;  
                                 mb->mode = MODE_INTERPOLATE;  
                         }  
2687    
2688                          if (d_sad16 < best_sad) {          if (pParam->m_quarterpel) {
2689                                  best_sad = d_sad16;                  gmc.x *= 2;
2690                                  mb->mode = MODE_DIRECT;                  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.300  
changed lines
  Added in v.661

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