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

Legend:
Removed from v.289  
changed lines
  Added in v.700

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