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

Legend:
Removed from v.1.40  
changed lines
  Added in v.1.44.2.11

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