[cvs] / xvidcore / src / motion / motion_est.c Repository:
ViewVC logotype

Diff of /xvidcore/src/motion/motion_est.c

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

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

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

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