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

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

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

revision 1.44, Mon Aug 12 10:07:16 2002 UTC revision 1.44.2.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                          if (pMB->mode == MODE_NOT_CODED)          case 2: // x qpel, y halfpel - left or right during qpel refinement
194                                  continue;                  GET_REFERENCE(halfpelMV.x, halfpelMV.y, ref1);
195                    GET_REFERENCE(x - halfpelMV.x, halfpelMV.y, ref2);
196    
197                          predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding);
198                    interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding);
199                    interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding);
200                    interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding);
201                    break;
202    
203                          pMB->sad16 =          default: // x and y in qpel resolution - the "corners" (top left/right and
204                                  SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,                           // bottom left/right) during qpel refinement
205                                                   x, y, predMV.x, predMV.y, predMV.x, predMV.y,                  GET_REFERENCE(halfpelMV.x, halfpelMV.y, ref1);
206                                                   current->motion_flags, current->quant,                  GET_REFERENCE(halfpelMV.x, y - halfpelMV.y, ref2);
207                                                   current->fcode, pParam, pMBs, prevMBs, &pMB->mv16,                  GET_REFERENCE(x - halfpelMV.x, halfpelMV.y, ref3);
208                                                   &pMB->pmvs[0]);                  GET_REFERENCE(x - halfpelMV.x, y - halfpelMV.y, ref4);
209    
210                          if (0 < (pMB->sad16 - MV16_INTER_BIAS)) {                  interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
211                                  int32_t deviation;                  interpolate8x8_avg4(Reference+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, rounding);
212                    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                                  deviation =          data->temp[0] = sad16v(data->Cur, Reference, data->iEdgedWidth, data->temp+1);
                                         dev16(pCurrent->y + x * 16 + y * 16 * pParam->edged_width,  
                                                   pParam->edged_width);  
218    
219                                  if (deviation < (pMB->sad16 - MV16_INTER_BIAS)) {          t = d_mv_bits(x - data->predQMV.x, y - data->predQMV.y, data->iFcode);
220                                          pMB->mode = MODE_INTRA;          data->temp[0] += data->lambda16 * t;
221                                          pMB->mv16 = pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =          data->temp[1] += data->lambda8 * t;
                                                 pMB->mvs[3] = zeroMV;  
                                         pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =  
                                                 pMB->sad8[3] = 0;  
222    
223                                          iIntra++;          if (data->temp[0] < data->iMinSAD[0]) {
224                                          if (iIntra >= iLimit)                  data->iMinSAD[0] = data->temp[0];
225                                                  return 1;                  data->currentQMV[0].x = x; data->currentQMV[0].y = y;
226            /*      *dir = Direction;*/ }
227    
228                                          continue;          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;
1236            }
1237            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);
1246    }
1247    
1248  int32_t  /* B-frames code starts here */
 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;  
1249    
1250                          case 8:  static __inline VECTOR
1251                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1252                                                                                   2);  {
1253                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  /* the stupidiest function ever */
1254                                                                                   4);          if (mode == MODE_FORWARD) return pMB->mvs[0];
1255                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          else return pMB->b_mvs[0];
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         default:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
   
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         }  
                 }  
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
         }  
         return iMinSAD;  
1256  }  }
1257    
1258    static void __inline
1259    PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
1260                                                            const uint32_t iWcount,
1261                                                            const MACROBLOCK * const pMB,
1262                                                            const uint32_t mode_curr)
1263    {
1264    
1265            // [0] is prediction
1266            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            pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
1272    
1273            if ((y != 0)&&(x != (int)(iWcount+1))) {                        // [3] top-right neighbour
1274                    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  int32_t          if (y != 0) {
1279  Halfpel8_Refine_c(const uint8_t * const pRef,                  pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
1280                                  const uint8_t * const pRefH,                  pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
1281                                  const uint8_t * const pRefV,          } else pmv[4].x = pmv[4].y = 0;
                                 const uint8_t * const pRefHV,  
                                 const uint8_t * const cur,  
                                 const int x,  
                                 const int y,  
                                 VECTOR * const currMV,  
                                 int32_t iMinSAD,  
                            const int center_x,  
                            const int center_y,  
                                 const int32_t min_dx,  
                                 const int32_t max_dx,  
                                 const int32_t min_dy,  
                                 const int32_t max_dy,  
                                 const int32_t iFcode,  
                                 const int32_t iQuant,  
                                 const int32_t iEdgedWidth)  
 {  
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
1282    
1283          int32_t iSAD;          if (x != 0) {
1284          VECTOR backupMV = *currMV;                  pmv[5] = ChoosePred(pMB-1, mode_curr);
1285                    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          CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y - 1);          if ((x != 0)&&(y != 0)) {
1289          CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y - 1);                  pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
1290          CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y - 1);                  pmv[6].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1291          CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y);          } else pmv[6].x = pmv[6].y = 0;
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y + 1);  
         CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y + 1);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y + 1);  
1292    
1293          return iMinSAD;  // more?
1294  }  }
1295    
1296    
1297  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)  /* search backward or forward, for b-frames */
1298    static void
1299  int32_t  SearchBF(       const uint8_t * const pRef,
 PMVfastSearch8(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 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 * 8 + y * 8 * iEdgedWidth;  
   
         int32_t iDiamondSize;  
1314    
1315          int32_t min_dx;          const int32_t iEdgedWidth = pParam->edged_width;
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
1316    
1317          VECTOR pmv[4];          int i, iDirection, mask;
1318          int32_t psad[4];          VECTOR pmv[7];
1319          VECTOR newMV;          MainSearchFunc *MainSearchPtr;
1320          VECTOR backupMV;          *Data->iMinSAD = MV_MAX_ERROR;
1321          VECTOR startMV;          Data->iFcode = iFcode;
1322    
1323  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          Data->Ref = pRef + (x + y * iEdgedWidth) * 16;
1324          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;          Data->RefH = pRefH + (x + y * iEdgedWidth) * 16;
1325            Data->RefV = pRefV + (x + y * iEdgedWidth) * 16;
1326            Data->RefHV = pRefHV + (x + y * iEdgedWidth) * 16;
1327    
1328           int32_t threshA, threshB;          Data->predMV = *predMV;
         int32_t iFound, bPredEq;  
         int32_t iMinSAD, iSAD;  
1329    
1330          int32_t iSubBlock = (y & 1) + (y & 1) + (x & 1);          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1331                                    pParam->width, pParam->height, iFcode, pParam->m_quarterpel);
1332    
1333          MainSearch8FuncPtr MainSearchPtr;          pmv[0] = Data->predMV;
1334            PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);
1335    
1336          /* Init variables */          Data->currentMV->x = Data->currentMV->y = 0;
         startMV.x = start_x;  
         startMV.y = start_y;  
1337    
1338          /* Get maximum range */          CheckCandidate = CheckCandidate16no4v;
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,  
                           iFcode);  
1339    
1340          if (!(MotionFlags & PMV_HALFPELDIAMOND8)) {  // main loop. checking all predictions
1341                  min_dx = EVEN(min_dx);          for (i = 0; i < 8; i++) {
1342                  max_dx = EVEN(max_dx);                  if (!(mask = make_mask(pmv, i)) ) continue;
1343                  min_dy = EVEN(min_dy);                  CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
                 max_dy = EVEN(max_dy);  
1344          }          }
1345    
1346          /* because we might use IF (dx>max_dx) THEN dx=max_dx; */          if (MotionFlags & PMV_USESQUARES16)
1347          //bPredEq = get_pmvdata(pMBs, (x >> 1), (y >> 1), iWcount, iSubBlock, pmv, psad);                  MainSearchPtr = SquareSearch;
1348          bPredEq = get_pmvdata2(pMBs, iWcount, 0, (x >> 1), (y >> 1), iSubBlock, pmv, psad);          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
1349                    MainSearchPtr = AdvDiamondSearch;
1350          if ((x == 0) && (y == 0)) {                  else MainSearchPtr = DiamondSearch;
                 threshA = 512 / 4;  
                 threshB = 1024 / 4;  
1351    
1352          } else {          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);
                 threshA = psad[0] / 4;  /* good estimate? */  
                 threshB = threshA + 256 / 4;  
                 if (threshA < 512 / 4)  
                         threshA = 512 / 4;  
                 if (threshA > 1024 / 4)  
                         threshA = 1024 / 4;  
                 if (threshB > 1792 / 4)  
                         threshB = 1792 / 4;  
         }  
   
         iFound = 0;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
1353    
1354            HalfpelRefine(Data);
1355    
1356  // Prepare for main loop  // three bits are needed to code backward mode. four for forward
1357    // we treat the bits just like they were vector's
1358            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    
1370    if (MotionFlags & PMV_USESQUARES8)  }
       MainSearchPtr = Square8_MainSearch;  
   else  
1371    
1372          if (MotionFlags & PMV_ADVANCEDDIAMOND8)  static int32_t
1373                  MainSearchPtr = AdvDiamond8_MainSearch;  SearchDirect(const IMAGE * const f_Ref,
1374          else                                  const uint8_t * const f_RefH,
1375                  MainSearchPtr = Diamond8_MainSearch;                                  const uint8_t * const f_RefV,
1376                                    const uint8_t * const f_RefHV,
1377                                    const IMAGE * const b_Ref,
1378                                    const uint8_t * const b_RefH,
1379                                    const uint8_t * const b_RefV,
1380                                    const uint8_t * const b_RefHV,
1381                                    const IMAGE * const pCur,
1382                                    const int x, const int y,
1383                                    const uint32_t MotionFlags,
1384                                    const int32_t TRB, const int32_t TRD,
1385                                    const MBParam * const pParam,
1386                                    MACROBLOCK * const pMB,
1387                                    const MACROBLOCK * const b_mb,
1388                                    int32_t * const best_sad,
1389                                    SearchData * const Data)
1390    
1391    {
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            for (k = 0; k < 4; k++) {
1415                    pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);
1416                    pMB->b_mvs[k].x = Data->directmvB[k].x = ((TRB - TRD) * Data->referencemv[k].x) / TRD;
1417                    pMB->mvs[k].y = Data->directmvF[k].y = ((TRB * Data->referencemv[k].y) / TRD);
1418                    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                    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          *currMV = startMV;          if (b_mb->mode == MODE_INTER4V)
1438                    CheckCandidate = CheckCandidateDirect;
1439            else CheckCandidate = CheckCandidateDirectno4v;
1440    
1441          iMinSAD =          (*CheckCandidate)(0, 0, 255, &k, Data);
                 sad8(cur,  
                          get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  
                                                 iEdgedWidth), iEdgedWidth);  
         iMinSAD +=  
                 calc_delta_8(currMV->x - center_x, currMV->y - center_y,  
                                          (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256 / 4) || ((MVequal(*currMV, prevMB->mvs[iSubBlock]))  
                                                                 && ((int32_t) iMinSAD <  
                                                                         prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  
    vector of the median.  
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
   
         if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[iSubBlock])))  
                 iFound = 2;  
   
 /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.  
    Otherwise select large Diamond Search.  
 */  
1442    
1443          if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))  // skip decision
1444                  iDiamondSize = 1;               // 1 halfpel!          if (*Data->iMinSAD - 2 * Data->lambda16 < (uint32_t)pMB->quant * SKIP_THRESH_B) {
1445          else                  //possible skip - checking chroma. everything copied from MC
1446                  iDiamondSize = 2;               // 2 halfpel = 1 full pixel!                  //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          if (!(MotionFlags & PMV_HALFPELDIAMOND8))                  sum = pMB->mvs[0].x + pMB->mvs[1].x + pMB->mvs[2].x + pMB->mvs[3].x;
1450                  iDiamondSize *= 2;                  dx = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1451    
1452                    sum = pMB->mvs[0].y + pMB->mvs[1].y + pMB->mvs[2].y + pMB->mvs[3].y;
1453                    dy = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1454    
1455  /*                  sum = pMB->b_mvs[0].x + pMB->b_mvs[1].x + pMB->b_mvs[2].x + pMB->b_mvs[3].x;
1456     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.                  b_dx = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
    Also calculate (0,0) but do not subtract offset.  
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset.  
 */  
   
 // the median prediction might be even better than mv16  
   
         if (!MVequal(pmv[0], startMV))  
                 CHECK_MV8_CANDIDATE(center_x, center_y);  
   
 // (0,0) if needed  
         if (!MVzero(pmv[0]))  
                 if (!MVzero(startMV))  
                         CHECK_MV8_ZERO;  
   
 // previous frame MV if needed  
         if (!MVzero(prevMB->mvs[iSubBlock]))  
                 if (!MVequal(prevMB->mvs[iSubBlock], startMV))  
                         if (!MVequal(prevMB->mvs[iSubBlock], pmv[0]))  
                                 CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x,  
                                                                         prevMB->mvs[iSubBlock].y);  
   
         if ((iMinSAD <= threshA) ||  
                 (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&  
                  ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 // left neighbour, if allowed and needed  
         if (!MVzero(pmv[1]))  
                 if (!MVequal(pmv[1], startMV))  
                         if (!MVequal(pmv[1], prevMB->mvs[iSubBlock]))  
                                 if (!MVequal(pmv[1], pmv[0])) {  
                                         if (!(MotionFlags & PMV_HALFPEL8)) {  
                                                 pmv[1].x = EVEN(pmv[1].x);  
                                                 pmv[1].y = EVEN(pmv[1].y);  
                                         }  
                                         CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);  
                                 }  
 // top neighbour, if allowed and needed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], startMV))  
                         if (!MVequal(pmv[2], prevMB->mvs[iSubBlock]))  
                                 if (!MVequal(pmv[2], pmv[0]))  
                                         if (!MVequal(pmv[2], pmv[1])) {  
                                                 if (!(MotionFlags & PMV_HALFPEL8)) {  
                                                         pmv[2].x = EVEN(pmv[2].x);  
                                                         pmv[2].y = EVEN(pmv[2].y);  
                                                 }  
                                                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed and needed  
                                                 if (!MVzero(pmv[3]))  
                                                         if (!MVequal(pmv[3], startMV))  
                                                                 if (!MVequal(pmv[3], prevMB->mvs[iSubBlock]))  
                                                                         if (!MVequal(pmv[3], pmv[0]))  
                                                                                 if (!MVequal(pmv[3], pmv[1]))  
                                                                                         if (!MVequal(pmv[3], pmv[2])) {  
                                                                                                 if (!  
                                                                                                         (MotionFlags &  
                                                                                                          PMV_HALFPEL8)) {  
                                                                                                         pmv[3].x = EVEN(pmv[3].x);  
                                                                                                         pmv[3].y = EVEN(pmv[3].y);  
                                                                                                 }  
                                                                                                 CHECK_MV8_CANDIDATE(pmv[3].x,  
                                                                                                                                         pmv[3].y);  
                                                                                         }  
                                         }  
   
         if ((MVzero(*currMV)) &&  
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV8_00_BIAS;  
   
   
 /* Step 6: If MinSAD <= thresa goto Step 10.  
    If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
 */  
   
         if ((iMinSAD <= threshA) ||  
                 (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&  
                  ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 /************ (Diamond Search)  **************/  
 /*  
    Step 7: Perform Diamond search, with either the small or large diamond.  
    If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
    Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
    If center then goto step 10.  
    Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
    Refine by using small diamond and goto step 10.  
 */  
   
         backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  
   
 /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  
                                                   currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
1457    
1458          if (MotionFlags & PMV_EXTSEARCH8) {                  sum = pMB->b_mvs[0].y + pMB->b_mvs[1].y + pMB->b_mvs[2].y + pMB->b_mvs[3].y;
1459  /* extended: search (up to) two more times: orignal prediction and (0,0) */                  b_dy = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1460    
1461                  if (!(MVequal(pmv[0], backupMV))) {                  sum = sad8bi(pCur->u + 8*x + 8*y*(Data->iEdgedWidth/2),
1462                          iSAD =                                          f_Ref->u + (y*8 + dy/2) * (Data->iEdgedWidth/2) + x*8 + dx/2,
1463                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                          b_Ref->u + (y*8 + b_dy/2) * (Data->iEdgedWidth/2) + x*8 + b_dx/2,
1464                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,                                          Data->iEdgedWidth/2);
1465                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,                  sum += sad8bi(pCur->v + 8*x + 8*y*(Data->iEdgedWidth/2),
1466                                                                    iDiamondSize, iFcode, iQuant, iFound);                                          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                          if (iSAD < iMinSAD) {                  if (sum < MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) {
1471                                  *currMV = newMV;                          pMB->mode = MODE_DIRECT_NONE_MV;
1472                                  iMinSAD = iSAD;                          return *Data->iMinSAD;
1473                          }                          }
1474                  }                  }
1475    
1476                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          skip_sad = *Data->iMinSAD;
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
1477    
1478                          if (iSAD < iMinSAD) {  //  DIRECT MODE DELTA VECTOR SEARCH.
1479                                  *currMV = newMV;  //      This has to be made more effective, but at the moment I'm happy it's running at all
1480                                  iMinSAD = iSAD;  
1481                          }          if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1482                  }                  else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1483          }                          else MainSearchPtr = DiamondSearch;
1484    
1485            (*MainSearchPtr)(0, 0, Data, 255);
1486    
1487  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.          HalfpelRefine(Data);
    By performing an optional local half-pixel search, we can refine this result even further.  
 */  
1488    
1489    PMVfast8_Terminate_with_Refine:          *Data->iMinSAD +=  1 * Data->lambda16 * 2; // one bit is needed to code direct mode
1490          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step          *best_sad = *Data->iMinSAD;
                 iMinSAD =  
                         Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                         iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                         iFcode, iQuant, iEdgedWidth);  
1491    
1492            if (b_mb->mode == MODE_INTER4V)
1493                    pMB->mode = MODE_DIRECT;
1494            else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation
1495    
1496    PMVfast8_Terminate_without_Refine:          pMB->pmvs[3] = *Data->currentMV;
         currPMV->x = currMV->x - center_x;  
         currPMV->y = currMV->y - center_y;  
1497    
1498          return iMinSAD;          for (k = 0; k < 4; k++) {
1499                    pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
1500                    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;
1514  }  }
1515    
1516  int32_t  
1517  EPZSSearch16(const uint8_t * const pRef,  static __inline void
1518                           const uint8_t * const pRefH,  SearchInterpolate(const uint8_t * const f_Ref,
1519                           const uint8_t * const pRefV,                                  const uint8_t * const f_RefH,
1520                           const uint8_t * const pRefHV,                                  const uint8_t * const f_RefV,
1521                                    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  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const uint32_t iHcount = pParam->mb_height;  
1539    
         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 * 16 + y * 16 * iEdgedWidth;          int iDirection, i, j;
1543            SearchData bData;
         int32_t min_dx;  
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
   
         VECTOR newMV;  
         VECTOR backupMV;  
   
         VECTOR pmv[4];  
         int32_t psad[8];  
1544    
1545          static MACROBLOCK *oldMBs = NULL;          *(bData.iMinSAD = fData->iMinSAD) = 4096*256;
1546            bData.Cur = fData->Cur;
1547            fData->iEdgedWidth = bData.iEdgedWidth = iEdgedWidth;
1548            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  //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;          CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, 255, &iDirection, fData);
         const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;  
         MACROBLOCK *oldMB = NULL;  
1579    
1580           int32_t thresh2;  //diamond. I wish we could use normal mainsearch functions (square, advdiamond)
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD = 9999;  
1581    
1582          MainSearch16FuncPtr MainSearchPtr;          do {
1583                    iDirection = 255;
1584          if (oldMBs == NULL) {                  // forward MV moves
1585                  oldMBs = (MACROBLOCK *) calloc(iWcount * iHcount, sizeof(MACROBLOCK));                  i = fData->currentMV[0].x; j = fData->currentMV[0].y;
1586  //      fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));  
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          }          }
         oldMB = oldMBs + x + y * iWcount;  
1617    
 /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
1618    
1619          if (!(MotionFlags & PMV_HALFPEL16)) {  void
1620                  min_dx = EVEN(min_dx);  MotionEstimationBVOP(MBParam * const pParam,
1621                  max_dx = EVEN(max_dx);                                           FRAMEINFO * const frame,
1622                  min_dy = EVEN(min_dy);                                           const int32_t time_bp,
1623                  max_dy = EVEN(max_dy);                                           const int32_t time_pp,
1624          }                                           // forward (past) reference
1625          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */                                           const MACROBLOCK * const f_mbs,
1626          //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);                                           const IMAGE * const f_ref,
1627          bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);                                           const IMAGE * const f_refH,
1628                                             const IMAGE * const f_refV,
1629  /* Step 4: Calculate SAD around the Median prediction.                                           const IMAGE * const f_refHV,
1630          MinSAD=SAD                                           // backward (future) reference
1631          If Motion Vector equal to Previous frame motion vector                                           const MACROBLOCK * const b_mbs,
1632                  and MinSAD<PrevFrmSAD goto Step 10.                                           const IMAGE * const b_ref,
1633          If SAD<=256 goto Step 10.                                           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  // Prepare for main loop          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
1643    
1644          currMV->x = start_x;          const int32_t TRB = time_pp - time_bp;
1645          currMV->y = start_y;          const int32_t TRD = time_pp;
1646    
1647          if (!(MotionFlags & PMV_HALFPEL16)) {  // some pre-inintialized data for the rest of the search
                 currMV->x = EVEN(currMV->x);  
                 currMV->y = EVEN(currMV->y);  
         }  
1648    
1649          if (currMV->x > max_dx)          SearchData Data;
1650                  currMV->x = max_dx;          int32_t iMinSAD;
1651          if (currMV->x < min_dx)          VECTOR currentMV[3];
1652                  currMV->x = min_dx;          Data.iEdgedWidth = pParam->edged_width;
1653          if (currMV->y > max_dy)          Data.currentMV = currentMV;
1654                  currMV->y = max_dy;          Data.iMinSAD = &iMinSAD;
1655          if (currMV->y < min_dy)          Data.lambda16 = lambda_vec16[frame->quant];
                 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 **************/  
1656    
1657  // previous frame MV          // note: i==horizontal, j==vertical
         CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);  
1658    
1659  // set threshhold based on Min of Prediction and SAD of collocated block          for (j = 0; j < pParam->mb_height; j++) {
 // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want  
1660    
1661          if ((x == 0) && (y == 0)) {                  f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
                 thresh2 = 512;  
         } else {  
 /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */  
1662    
1663                  thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;                  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    /* special case, if collocated block is SKIPed: encoding is forward (0,0), cpb=0 without further ado */
1668                            if (b_mb->mode == MODE_NOT_CODED) {
1669                                    pMB->mode = MODE_NOT_CODED;
1670                                    continue;
1671          }          }
1672    
1673  // MV=(0,0) is often a good choice                          Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
1674                            pMB->quant = frame->quant;
1675    /* direct search comes first, because it (1) checks for SKIP-mode
1676            and (2) sets very good predictions for forward and backward search */
1677    
1678                            skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
1679                                                                            b_ref, b_refH->y, b_refV->y, b_refHV->y,
1680                                                                            &frame->image,
1681                                                                            i, j,
1682                                                                            frame->motion_flags,
1683                                                                            TRB, TRD,
1684                                                                            pParam,
1685                                                                            pMB, b_mb,
1686                                                                            &best_sad,
1687                                                                            &Data);
1688    
1689          CHECK_MV16_ZERO;                          if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
1690    
1691    //                      best_sad = 256*4096; //uncomment to disable Directsearch.
1692    //      To disable any other mode, just comment the function call
1693    
1694  // left neighbour, if allowed                          // forward search
1695          if (x != 0) {                          SearchBF(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
1696                  if (!(MotionFlags & PMV_HALFPEL16)) {                                                  &frame->image, i, j,
1697                          pmv[1].x = EVEN(pmv[1].x);                                                  frame->motion_flags,
1698                          pmv[1].y = EVEN(pmv[1].y);                                                  frame->fcode, pParam,
1699                  }                                                  pMB, &f_predMV, &best_sad,
1700                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);                                                  MODE_FORWARD, &Data);
         }  
 // top neighbour, if allowed  
         if (y != 0) {  
                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                         pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
                 }  
                 CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed  
                 if ((uint32_t) x != (iWcount - 1)) {  
                         if (!(MotionFlags & PMV_HALFPEL16)) {  
                                 pmv[3].x = EVEN(pmv[3].x);  
                                 pmv[3].y = EVEN(pmv[3].y);  
                         }  
                         CHECK_MV16_CANDIDATE(pmv[3].x, pmv[3].y);  
                 }  
         }  
   
 /* Terminate if MinSAD <= T_2  
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
   
         if ((iMinSAD <= thresh2)  
                 || (MVequal(*currMV, prevMB->mvs[0]) &&  
                         ((int32_t) iMinSAD <= prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
         }  
   
 /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/  
   
         backupMV = prevMB->mvs[0];      // collocated MV  
         backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x);     // acceleration X  
         backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y);     // acceleration Y  
   
         CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y);  
   
 // left neighbour  
         if (x != 0)  
                 CHECK_MV16_CANDIDATE((prevMB - 1)->mvs[0].x, (prevMB - 1)->mvs[0].y);  
   
 // top neighbour  
         if (y != 0)  
                 CHECK_MV16_CANDIDATE((prevMB - iWcount)->mvs[0].x,  
                                                          (prevMB - iWcount)->mvs[0].y);  
   
 // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs  
   
         if ((uint32_t) x != iWcount - 1)  
                 CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);  
   
 // bottom neighbour, dito  
         if ((uint32_t) y != iHcount - 1)  
                 CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,  
                                                          (prevMB + iWcount)->mvs[0].y);  
   
 /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */  
         if (iMinSAD <= thresh2) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
         }  
   
 /************ (if Diamond Search)  **************/  
   
         backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  
   
         if (MotionFlags & PMV_USESQUARES16)  
                 MainSearchPtr = Square16_MainSearch;  
         else  
          if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
   
 /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  
   
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  
                                                   currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);  
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
   
   
         if (MotionFlags & PMV_EXTSEARCH16) {  
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
1701    
1702                  if (!(MVequal(pmv[0], backupMV))) {                          // backward search
1703                          iSAD =                          SearchBF(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
1704                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                                  &frame->image, i, j,
1705                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,                                                  frame->motion_flags,
1706                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,                                                  frame->bcode, pParam,
1707                                                                    2, iFcode, iQuant, 0);                                                  pMB, &b_predMV, &best_sad,
1708                  }                                                  MODE_BACKWARD, &Data);
1709    
1710                  if (iSAD < iMinSAD) {                          // interpolate search comes last, because it uses data from forward and backward as prediction
                         *currMV = newMV;  
                         iMinSAD = iSAD;  
                 }  
1711    
1712                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                          SearchInterpolate(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
1713                          iSAD =                                                  b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
1714                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                                                  &frame->image,
1715                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,                                                  i, j,
1716                                                                    max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);                                                  frame->fcode, frame->bcode,
1717                                                    frame->motion_flags,
1718                                                    pParam,
1719                                                    &f_predMV, &b_predMV,
1720                                                    pMB, &best_sad,
1721                                                    &Data);
1722    
1723                          if (iSAD < iMinSAD) {                          switch (pMB->mode) {
1724                                  *currMV = newMV;                                  case MODE_FORWARD:
1725                                  iMinSAD = iSAD;                                          f_count++;
1726                                            f_predMV = pMB->mvs[0];
1727                                            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                          }                          }
1744                  }                  }
1745          }          }
1746    
1747  /***************        Choose best MV found     **************/  //      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    
   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;  
1750  }  }
1751    
1752    /* Hinted ME starts here */
1753    
1754  int32_t  static void
1755  EPZSSearch8(const uint8_t * const pRef,  Search8hinted(const SearchData * const OldData,
1756                          const uint8_t * const pRefH,                          const int x, const int y,
                         const uint8_t * const pRefV,  
                         const uint8_t * const pRefHV,  
                         const IMAGE * const pCur,  
                         const int x,  
                         const int y,  
                         const int start_x,  
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
1757                          const uint32_t MotionFlags,                          const uint32_t MotionFlags,
                         const uint32_t iQuant,  
                         const uint32_t iFcode,  
1758                          const MBParam * const pParam,                          const MBParam * const pParam,
1759                            MACROBLOCK * const pMB,
1760                          const MACROBLOCK * const pMBs,                          const MACROBLOCK * const pMBs,
1761                          const MACROBLOCK * const prevMBs,                          const int block,
1762                          VECTOR * const currMV,                          SearchData * const Data)
                         VECTOR * const currPMV)  
1763  {  {
1764  /* Please not that EPZS might not be a good choice for 8x8-block motion search ! */          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          const uint32_t iWcount = pParam->mb_width;          if(pParam->m_quarterpel) {
1773          const int32_t iWidth = pParam->width;                  //it is qpel. substract d_mv_bits[qpel] from 0, add d_mv_bits[hpel] everywhere
1774          const int32_t iHeight = pParam->height;                  if (block == 0)
1775          const int32_t iEdgedWidth = pParam->edged_width;                          *(Data->iMinSAD) -= Data->lambda8 *
1776                                                                            d_mv_bits(      Data->currentQMV->x - Data->predQMV.x,
1777          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;                                                                                                  Data->currentQMV->y - Data->predQMV.y,
1778                                                                                                    Data->iFcode);
1779    
1780          int32_t iDiamondSize = 1;                  *(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    
         int32_t min_dx;  
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
1790    
1791          VECTOR newMV;          Data->Ref = OldData->Ref + 8 * ((block&1) + pParam->edged_width*(block>>1));
1792          VECTOR backupMV;          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          VECTOR pmv[4];          Data->Cur = OldData->Cur + 8 * ((block&1) + pParam->edged_width*(block>>1));
         int32_t psad[8];  
1798    
1799          const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);          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  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          CheckCandidate = CheckCandidate8;
         const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;  
1803    
1804          int32_t bPredEq;          temp_sad = *(Data->iMinSAD); // store current MinSAD
         int32_t iMinSAD, iSAD = 9999;  
1805    
1806          MainSearch8FuncPtr MainSearchPtr;          if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
1807                    else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1808                            else MainSearchPtr = DiamondSearch;
1809    
1810  /* Get maximum range */          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,  
                           iFcode);  
1811    
1812  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          if(*(Data->iMinSAD) < temp_sad) {
1813                    Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1814          if (!(MotionFlags & PMV_HALFPEL8)) {                  Data->currentQMV->y = 2 * Data->currentMV->y;
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
1815          }          }
         /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
         //bPredEq = get_pmvdata(pMBs, x >> 1, y >> 1, iWcount, iSubBlock, pmv[0].x, pmv[0].y, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, x >> 1, y >> 1, iSubBlock, pmv, psad);  
   
1816    
1817  /* Step 4: Calculate SAD around the Median prediction.          if (MotionFlags & PMV_HALFPELREFINE8) {
1818          MinSAD=SAD                  temp_sad = *(Data->iMinSAD); // store current MinSAD
         If Motion Vector equal to Previous frame motion vector  
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
 */  
1819    
1820  // Prepare for main loop                  HalfpelRefine(Data); // perform halfpel refine of current best vector
1821    
1822                    if(*(Data->iMinSAD) < temp_sad) { // we have found a better match
1823          if (!(MotionFlags & PMV_HALFPEL8)) {                          Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1824                  currMV->x = EVEN(currMV->x);                          Data->currentQMV->y = 2 * Data->currentMV->y;
                 currMV->y = EVEN(currMV->y);  
1825          }          }
   
         if (currMV->x > max_dx)  
                 currMV->x = max_dx;  
         if (currMV->x < min_dx)  
                 currMV->x = min_dx;  
         if (currMV->y > max_dy)  
                 currMV->y = max_dy;  
         if (currMV->y < min_dy)  
                 currMV->y = min_dy;  
   
 /***************** This is predictor SET A: only median prediction ******************/  
   
   
         iMinSAD =  
                 sad8(cur,  
                          get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  
                                                 iEdgedWidth), iEdgedWidth);  
         iMinSAD +=  
                 calc_delta_8(currMV->x - center_x, currMV->y - center_y,  
                                          (uint8_t) iFcode, iQuant);  
   
   
 // thresh1 is fixed to 256  
         if (iMinSAD < 256 / 4) {  
                 if (MotionFlags & PMV_QUICKSTOP8)  
                         goto EPZS8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
1826          }          }
1827    
1828  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/          if(pParam->m_quarterpel) {
1829                    if((!(Data->currentQMV->x & 1)) && (!(Data->currentQMV->y & 1)) &&
1830                            (MotionFlags & PMV_QUARTERPELREFINE8)) {
1831    
1832                            CheckCandidate = CheckCandidate8_qpel;
1833                            Data->iMinSAD[0] -= Data->lambda8 *
1834                                    d_mv_bits(Data->predMV.x - Data->currentMV[0].x, Data->predMV.y - Data->currentMV[0].y, Data->iFcode);
1835    
1836  // MV=(0,0) is often a good choice                          Data->iMinSAD[0] += Data->lambda8 *
1837          CHECK_MV8_ZERO;                                  d_mv_bits(Data->predQMV.x - Data->currentQMV[0].x, Data->predQMV.y - Data->currentQMV[0].y, Data->iFcode);
1838    
1839  // previous frame MV                                  QuarterpelRefine(Data);
         CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x, prevMB->mvs[iSubBlock].y);  
   
 // left neighbour, if allowed  
         if (psad[1] != MV_MAX_ERROR) {  
                 if (!(MotionFlags & PMV_HALFPEL8)) {  
                         pmv[1].x = EVEN(pmv[1].x);  
                         pmv[1].y = EVEN(pmv[1].y);  
                 }  
                 CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);  
         }  
 // top neighbour, if allowed  
         if (psad[2] != MV_MAX_ERROR) {  
                 if (!(MotionFlags & PMV_HALFPEL8)) {  
                         pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
                 }  
                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed  
                 if (psad[3] != MV_MAX_ERROR) {  
                         if (!(MotionFlags & PMV_HALFPEL8)) {  
                                 pmv[3].x = EVEN(pmv[3].x);  
                                 pmv[3].y = EVEN(pmv[3].y);  
                         }  
                         CHECK_MV8_CANDIDATE(pmv[3].x, pmv[3].y);  
                 }  
         }  
   
 /*  // this bias is zero anyway, at the moment!  
   
         if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)  
                 iMinSAD -= MV8_00_BIAS;  
   
 */  
   
 /* Terminate if MinSAD <= T_2  
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
   
         if (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */  
                 if (MotionFlags & PMV_QUICKSTOP8)  
                         goto EPZS8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
         }  
   
 /************ (Diamond Search)  **************/  
   
         backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  
   
         if (!(MotionFlags & PMV_HALFPELDIAMOND8))  
                 iDiamondSize *= 2;  
   
 /* default: use best prediction as starting point for one call of EPZS_MainSearch */  
   
 // there is no EPZS^2 for inter4v at the moment  
   
   if (MotionFlags & PMV_USESQUARES8)  
       MainSearchPtr = Square8_MainSearch;  
   else  
   
         if (MotionFlags & PMV_ADVANCEDDIAMOND8)  
                 MainSearchPtr = AdvDiamond8_MainSearch;  
         else  
                 MainSearchPtr = Diamond8_MainSearch;  
   
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  
                                                   currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, 0);  
   
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
   
         if (MotionFlags & PMV_EXTSEARCH8) {  
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
   
                 if (!(MVequal(pmv[0], backupMV))) {  
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, 0);  
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
                 }  
   
                 if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {  
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, 0);  
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
1840                  }                  }
1841            pMB->pmvs[block].x = Data->currentQMV->x - Data->predQMV.x;
1842            pMB->pmvs[block].y = Data->currentQMV->y - Data->predQMV.y;
1843            } else {
1844                    pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1845                    pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
1846          }          }
1847    
1848  /***************        Choose best MV found     **************/          pMB->mvs[block] = *(Data->currentMV);
1849            pMB->qmvs[block] = *(Data->currentQMV);
   EPZS8_Terminate_with_Refine:  
         if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step  
                 iMinSAD =  
                         Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                         iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                         iFcode, iQuant, iEdgedWidth);  
   
   EPZS8_Terminate_without_Refine:  
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;  
1871    
1872            const int32_t iEdgedWidth = pParam->edged_width;
1873    
1874  /* Get maximum range */          int i, t;
1875          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,          MainSearchFunc * MainSearchPtr;
                           iFcode);  
   
 /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  
   
         if ((x == 0) && (y == 0)) {  
                 threshA = 512;  
                 threshB = 1024;  
   
                 bPredEq = 0;  
                 psad[0] = psad[1] = psad[2] = psad[3] = 0;  
                 *currMV = pmv[0] = pmv[1] = pmv[2] = pmv[3] = zeroMV;  
   
         } else {  
   
                 bPredEq = get_ipmvdata(pMBs, iWcount, 0, x, y, 0, pmv, psad);  
   
                 threshA = psad[0];  
                 threshB = threshA + 256;  
                 if (threshA < 512)  
                         threshA = 512;  
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
   
                 *currMV = pmv[0];                       /* current best := prediction */  
         }  
   
         iFound = 0;  
1876    
1877  /* Step 4: Calculate SAD around the Median prediction.          Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1878     MinSAD=SAD          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1879     If Motion Vector equal to Previous frame motion vector                                  pParam->width, pParam->height, Data->iFcode, pParam->m_quarterpel);
1880     and MinSAD<PrevFrmSAD goto Step 10.  
1881     If SAD<=256 goto Step 10.          Data->Cur = pCur->y + (x + y * iEdgedWidth) * 16;
1882  */          Data->Ref = pRef + (x + iEdgedWidth*y)*16;
1883            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 (currMV->x > max_dx) {          if (!(MotionFlags & PMV_HALFPEL16)) {
1889                  currMV->x = EVEN(max_dx);                  Data->min_dx = EVEN(Data->min_dx);
1890          }                  Data->max_dx = EVEN(Data->max_dx);
1891          if (currMV->x < min_dx) {                  Data->min_dy = EVEN(Data->min_dy);
1892                  currMV->x = EVEN(min_dx);                  Data->max_dy = EVEN(Data->max_dy);
         }  
         if (currMV->y > max_dy) {  
                 currMV->y = EVEN(max_dy);  
         }  
         if (currMV->y < min_dy) {  
                 currMV->y = EVEN(min_dy);  
         }  
   
         iMinSAD =  
                 sad16(cur,  
                           get_iref_mv(pRef, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->i_mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->i_sad16))) {  
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
                 {  
                         if (!MVzero(*currMV)) {  
                                 iMinSAD += MV16_00_BIAS;  
                                 CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures  
                                 iMinSAD -= MV16_00_BIAS;  
                         }  
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    
2040                          if (b_mb->mode == MODE_INTER && b_mb->cbp == 0 &&                  }
2041                                  b_mb->mvs[0].x == 0 && b_mb->mvs[0].y == 0) {          }
2042                                  mb->mode = MODE_NOT_CODED;          free(qimage);
                                 mb->b_mvs[0] = mb->mvs[0] = zeroMV;  
                                 continue;  
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,  2,  
                                                 frame->fcode, frame->bcode,frame->quant,0);  
   
                         i_sad16 = Diamond16_InterpolMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i * 16 + j * 16 * edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 f_interpolMV.x, f_interpolMV.y,  
                                                 b_interpolMV.x, b_interpolMV.y,  
                                                 i_sad16,  
                                                 &f_interpolMV, &b_interpolMV,  
                                                 f_predMV.x, f_predMV.y, b_predMV.x, b_predMV.y,  
                                                 f_min_dx, f_max_dx, f_min_dy, f_max_dy,  
                                                 b_min_dx, b_max_dx, b_min_dy, b_max_dy,  
                                                 edged_width,  1,  
                                                 frame->fcode, frame->bcode,frame->quant,0);             // equiv to halfpel refine  
   
   
 /*  DIRECT MODE DELTA VECTOR SEARCH.  
     This has to be made more effective, but at the moment I'm happy it's running at all */  
   
 /* There are two range restrictions for direct mode: deltaMV is limited to [-32,31] in halfpel units, and  
    absolute vector must not lie outside of image dimensions. Constraint one is dealt with by CHECK_MV16_DIRECT  
    and for constraint two we need distance to boundary. This is done by get_range very large fcode (hack!) */  
   
                         get_range(&min_dx, &max_dx, &min_dy, &max_dy, i, j, 16, iWidth, iHeight, 19);  
   
                         d_sad16 = Diamond16_DirectMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i*16 + j*16*edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 TRB,TRD,  
                                                 0,0,  
                                                 d_sad16,  
                                                 &mb->deltamv,  
                                                 mb->directmv, // this has to be pre-initialized with b_mb->mvs[]  
                                         min_dx, max_dx, min_dy, max_dy,  
                                                 edged_width, 2, frame->quant, 0);  
   
                         d_sad16 = Diamond16_DirectMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i*16 + j*16*edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 TRB,TRD,  
                                                 mb->deltamv.x, mb->deltamv.y,  
                                                 d_sad16,  
                                                 &mb->deltamv,  
                                                 mb->directmv, // this has to be pre-initialized with b_mb->mvs[]  
                                         min_dx, max_dx, min_dy, max_dy,  
                                                 edged_width, 1, frame->quant, 0);               // equiv to halfpel refine  
   
   
 //                      i_sad16 = 65535;                /* remove the comment to disable any of the MODEs */  
 //                      f_sad16 = 65535;  
 //                      b_sad16 = 65535;  
 //                      d_sad16 = 65535;  
   
                         if (f_sad16 < b_sad16) {  
                                 best_sad = f_sad16;  
                                 mb->mode = MODE_FORWARD;  
                         } else {  
                                 best_sad = b_sad16;  
                                 mb->mode = MODE_BACKWARD;  
                         }  
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++) {
                                         i_count++;  
                                         mb->mvs[0] = f_interpolMV;  
                                         mb->b_mvs[0] = b_interpolMV;  
                                         f_predMV = mb->mvs[0];  
                                         b_predMV = mb->b_mvs[0];  
                                         break;  
                                 case MODE_DIRECT:  
                                         d_count++;  
                                         break;  
                                 default:  
                                         break;  
                         }  
2145    
2146                            MACROBLOCK *pMB = &current->mbs[x + y * pParam->mb_width];
2147                            for(i = 0; i < (pMB->mode == MODE_INTER4V ? 4:1); i++) {
2148                                    if (pMB->mvs[i].x > max) max = pMB->mvs[i].x;
2149                                    if (pMB->mvs[i].y > max) max = pMB->mvs[i].y;
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.44  
changed lines
  Added in v.1.44.2.11

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