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

Legend:
Removed from v.347  
changed lines
  Added in v.644

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