[svn] / branches / dev-api-3 / xvidcore / src / motion / motion_est.c Repository:
ViewVC logotype

Diff of /branches/dev-api-3/xvidcore/src/motion/motion_est.c

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

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

Legend:
Removed from v.318  
changed lines
  Added in v.702

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