[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 317, Fri Jul 19 14:56:00 2002 UTC branches/dev-api-3/xvidcore/src/motion/motion_est.c revision 698, Sun Dec 8 06:43:34 2002 UTC
# Line 28  Line 28 
28   *   *
29   *************************************************************************/   *************************************************************************/
30    
 /**************************************************************************  
  *  
  *  Modifications:  
  *  
  *      01.05.2002      updated MotionEstimationBVOP  
  *      25.04.2002 partial prevMB conversion  
  *  22.04.2002 remove some compile warning by chenm001 <chenm001@163.com>  
  *  14.04.2002 added MotionEstimationBVOP()  
  *  02.04.2002 add EPZS(^2) as ME algorithm, use PMV_USESQUARES to choose between  
  *             EPZS and EPZS^2  
  *  08.02.2002 split up PMVfast into three routines: PMVFast, PMVFast_MainLoop  
  *             PMVFast_Refine to support multiple searches with different start points  
  *  07.01.2002 uv-block-based interpolation  
  *  06.01.2002 INTER/INTRA-decision is now done before any SEARCH8 (speedup)  
  *             changed INTER_BIAS to 150 (as suggested by suxen_drol)  
  *             removed halfpel refinement step in PMVfastSearch8 + quality=5  
  *             added new quality mode = 6 which performs halfpel refinement  
  *             filesize difference between quality 5 and 6 is smaller than 1%  
  *             (Isibaar)  
  *  31.12.2001 PMVfastSearch16 and PMVfastSearch8 (gruel)  
  *  30.12.2001 get_range/MotionSearchX simplified; blue/green bug fix  
  *  22.12.2001 commented best_point==99 check  
  *  19.12.2001 modified get_range (purple bug fix)  
  *  15.12.2001 moved pmv displacement from mbprediction  
  *  02.12.2001 motion estimation/compensation split (Isibaar)  
  *  16.11.2001 rewrote/tweaked search algorithms; pross@cs.rmit.edu.au  
  *  10.11.2001 support for sad16/sad8 functions  
  *  28.08.2001 reactivated MODE_INTER4V for EXT_MODE  
  *  24.08.2001 removed MODE_INTER4V_Q, disabled MODE_INTER4V for EXT_MODE  
  *  22.08.2001 added MODE_INTER4V_Q  
  *  20.08.2001 added pragma to get rid of internal compiler error with VC6  
  *             idea by Cyril. Thanks.  
  *  
  *  Michael Militzer <isibaar@videocoding.de>  
  *  
  **************************************************************************/  
   
31  #include <assert.h>  #include <assert.h>
32  #include <stdio.h>  #include <stdio.h>
33  #include <stdlib.h>  #include <stdlib.h>
# Line 74  Line 37 
37  #include "../prediction/mbprediction.h"  #include "../prediction/mbprediction.h"
38  #include "../global.h"  #include "../global.h"
39  #include "../utils/timer.h"  #include "../utils/timer.h"
40    #include "../image/interpolate8x8.h"
41    #include "motion_est.h"
42  #include "motion.h"  #include "motion.h"
43  #include "sad.h"  #include "sad.h"
44    #include "../utils/emms.h"
45    
46    #define INITIAL_SKIP_THRESH     (10)
47    #define FINAL_SKIP_THRESH       (50)
48    #define MAX_SAD00_FOR_SKIP      (20)
49    #define MAX_CHROMA_SAD_FOR_SKIP (22)
50    #define SKIP_THRESH_B (25)
51    
52    #define CHECK_CANDIDATE(X,Y,D) { \
53    (*CheckCandidate)((const int)(X),(const int)(Y), (D), &iDirection, data ); }
54    
55  static int32_t lambda_vec16[32] =       /* rounded values for lambda param for weight of motion bits as in modified H.26L */  #define iDiamondSize 2
 { 0, (int) (1.00235 + 0.5), (int) (1.15582 + 0.5), (int) (1.31976 + 0.5),  
                 (int) (1.49591 + 0.5), (int) (1.68601 + 0.5),  
         (int) (1.89187 + 0.5), (int) (2.11542 + 0.5), (int) (2.35878 + 0.5),  
                 (int) (2.62429 + 0.5), (int) (2.91455 + 0.5),  
         (int) (3.23253 + 0.5), (int) (3.58158 + 0.5), (int) (3.96555 + 0.5),  
                 (int) (4.38887 + 0.5), (int) (4.85673 + 0.5),  
         (int) (5.37519 + 0.5), (int) (5.95144 + 0.5), (int) (6.59408 + 0.5),  
                 (int) (7.31349 + 0.5), (int) (8.12242 + 0.5),  
         (int) (9.03669 + 0.5), (int) (10.0763 + 0.5), (int) (11.2669 + 0.5),  
                 (int) (12.6426 + 0.5), (int) (14.2493 + 0.5),  
         (int) (16.1512 + 0.5), (int) (18.442 + 0.5), (int) (21.2656 + 0.5),  
                 (int) (24.8580 + 0.5), (int) (29.6436 + 0.5),  
         (int) (36.4949 + 0.5)  
 };  
   
 static int32_t *lambda_vec8 = lambda_vec16;     /* same table for INTER and INTER4V for now */  
56    
57    static VECTOR
58    GlobalMotionEst(const MACROBLOCK * const pMBs,
59                                    const MBParam * const pParam, const uint32_t iFcode);
60    
61    
62  // mv.length table  static __inline int
63  static const uint32_t mvtab[33] = {  d_mv_bits(int x, int y, const uint32_t iFcode)
         1, 2, 3, 4, 6, 7, 7, 7,  
         9, 9, 9, 10, 10, 10, 10, 10,  
         10, 10, 10, 10, 10, 10, 10, 10,  
         10, 11, 11, 11, 11, 11, 11, 12, 12  
 };  
   
   
 static __inline uint32_t  
 mv_bits(int32_t component,  
                 const uint32_t iFcode)  
64  {  {
65          if (component == 0)          int xb, yb;
                 return 1;  
66    
67          if (component < 0)          if (x == 0) xb = 1;
68                  component = -component;          else {
69                    if (x < 0) x = -x;
70                    x += (1 << (iFcode - 1)) - 1;
71                    x >>= (iFcode - 1);
72                    if (x > 32) x = 32;
73                    xb = mvtab[x] + iFcode;
74            }
75    
76            if (y == 0) yb = 1;
77            else {
78                    if (y < 0) y = -y;
79                    y += (1 << (iFcode - 1)) - 1;
80                    y >>= (iFcode - 1);
81                    if (y > 32) y = 32;
82                    yb = mvtab[y] + iFcode;
83            }
84            return xb + yb;
85    }
86    
87    static int32_t
88    ChromaSAD(int dx, int dy, const SearchData * const data)
89    {
90            int sad;
91            dx = (dx >> 1) + roundtab_79[dx & 0x3];
92            dy = (dy >> 1) + roundtab_79[dy & 0x3];
93    
94            switch (((dx & 1) << 1) + (dy & 1))     { // ((dx%2)?2:0)+((dy%2)?1:0)
95                    case 0:
96                            sad = sad8(data->CurU, data->RefCU + (dy/2) * (data->iEdgedWidth/2) + dx/2, data->iEdgedWidth/2);
97                            sad += sad8(data->CurV, data->RefCV + (dy/2) * (data->iEdgedWidth/2) + dx/2, data->iEdgedWidth/2);
98                            break;
99                    case 1:
100                            dx = dx / 2; dy = (dy - 1) / 2;
101                            sad = sad8bi(data->CurU, data->RefCU + dy * (data->iEdgedWidth/2) + dx, data->RefCU + (dy+1) * (data->iEdgedWidth/2) + dx, data->iEdgedWidth/2);
102                            sad += sad8bi(data->CurV, data->RefCV + dy * (data->iEdgedWidth/2) + dx, data->RefCV + (dy+1) * (data->iEdgedWidth/2) + dx, data->iEdgedWidth/2);
103                            break;
104                    case 2:
105                            dx = (dx - 1) / 2; dy = dy / 2;
106                            sad = sad8bi(data->CurU, data->RefCU + dy * (data->iEdgedWidth/2) + dx, data->RefCU + dy * (data->iEdgedWidth/2) + dx+1, data->iEdgedWidth/2);
107                            sad += sad8bi(data->CurV, data->RefCV + dy * (data->iEdgedWidth/2) + dx, data->RefCV + dy * (data->iEdgedWidth/2) + dx+1, data->iEdgedWidth/2);
108                            break;
109                    default:
110                            dx = (dx - 1) / 2; dy = (dy - 1) / 2;
111                            interpolate8x8_halfpel_hv(data->RefQ,
112                                                                             data->RefCU + dy * (data->iEdgedWidth/2) + dx, data->iEdgedWidth/2,
113                                                                             data->rounding);
114                            sad = sad8(data->CurU, data->RefQ, data->iEdgedWidth/2);
115                            interpolate8x8_halfpel_hv(data->RefQ,
116                                                                             data->RefCV + dy * (data->iEdgedWidth/2) + dx, data->iEdgedWidth/2,
117                                                                             data->rounding);
118                            sad += sad8(data->CurV, data->RefQ, data->iEdgedWidth/2);
119                            break;
120            }
121            return sad;
122    }
123    
124          if (iFcode == 1) {  static __inline const uint8_t *
125                  if (component > 32)  GetReference(const int x, const int y, const int dir, const SearchData * const data)
126                          component = 32;  {
127    //      dir : 0 = forward, 1 = backward
128            switch ( (dir << 2) | ((x&1)<<1) | (y&1) ) {
129                    case 0 : return data->Ref + x/2 + (y/2)*(data->iEdgedWidth);
130                    case 1 : return data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth);
131                    case 2 : return data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth);
132                    case 3 : return data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth);
133                    case 4 : return data->bRef + x/2 + (y/2)*(data->iEdgedWidth);
134                    case 5 : return data->bRefV + x/2 + ((y-1)/2)*(data->iEdgedWidth);
135                    case 6 : return data->bRefH + (x-1)/2 + (y/2)*(data->iEdgedWidth);
136                    default : return data->bRefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth);
137    
138                  return mvtab[component] + 1;          }
139          }          }
140    
141          component += (1 << (iFcode - 1)) - 1;  static uint8_t *
142          component >>= (iFcode - 1);  Interpolate8x8qpel(const int x, const int y, const int block, const int dir, const SearchData * const data)
143    {
144    // create or find a qpel-precision reference picture; return pointer to it
145            uint8_t * Reference = (uint8_t *)data->RefQ + 16*dir;
146            const int32_t iEdgedWidth = data->iEdgedWidth;
147            const uint32_t rounding = data->rounding;
148            const int halfpel_x = x/2;
149            const int halfpel_y = y/2;
150            const uint8_t *ref1, *ref2, *ref3, *ref4;
151    
152          if (component > 32)          ref1 = GetReference(halfpel_x, halfpel_y, dir, data); // this reference is used in all cases
153                  component = 32;          ref1 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
154            switch( ((x&1)<<1) + (y&1) ) {
155            case 0: // pure halfpel position
156                    Reference = (uint8_t *) GetReference(halfpel_x, halfpel_y, dir, data);
157                    Reference += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
158                    break;
159    
160          return mvtab[component] + 1 + iFcode - 1;          case 1: // x halfpel, y qpel - top or bottom during qpel refinement
161  }                  ref2 = GetReference(halfpel_x, y - halfpel_y, dir, data);
162                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
163                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
164                    break;
165    
166            case 2: // x qpel, y halfpel - left or right during qpel refinement
167                    ref2 = GetReference(x - halfpel_x, halfpel_y, dir, data);
168                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
169                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
170                    break;
171    
172  static __inline uint32_t          default: // x and y in qpel resolution - the "corners" (top left/right and
173  calc_delta_16(const int32_t dx,                           // bottom left/right) during qpel refinement
174                            const int32_t dy,                  ref2 = GetReference(halfpel_x, y - halfpel_y, dir, data);
175                            const uint32_t iFcode,                  ref3 = GetReference(x - halfpel_x, halfpel_y, dir, data);
176                            const uint32_t iQuant)                  ref4 = GetReference(x - halfpel_x, y - halfpel_y, dir, data);
177  {                  ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
178          return NEIGH_TEND_16X16 * lambda_vec16[iQuant] * (mv_bits(dx, iFcode) +                  ref3 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
179                                                                                                            mv_bits(dy, iFcode));                  ref4 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
180                    interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
181                    break;
182  }  }
183            return Reference;
 static __inline uint32_t  
 calc_delta_8(const int32_t dx,  
                          const int32_t dy,  
                          const uint32_t iFcode,  
                          const uint32_t iQuant)  
 {  
         return NEIGH_TEND_8X8 * lambda_vec8[iQuant] * (mv_bits(dx, iFcode) +  
                                                                                                    mv_bits(dy, iFcode));  
184  }  }
185    
186  bool  static uint8_t *
187  MotionEstimation(MBParam * const pParam,  Interpolate16x16qpel(const int x, const int y, const int dir, const SearchData * const data)
                                  FRAMEINFO * const current,  
                                  FRAMEINFO * const reference,  
                                  const IMAGE * const pRefH,  
                                  const IMAGE * const pRefV,  
                                  const IMAGE * const pRefHV,  
                                  const uint32_t iLimit)  
188  {  {
189          const uint32_t iWcount = pParam->mb_width;  // create or find a qpel-precision reference picture; return pointer to it
190          const uint32_t iHcount = pParam->mb_height;          uint8_t * Reference = (uint8_t *)data->RefQ + 16*dir;
191          MACROBLOCK *const pMBs = current->mbs;          const int32_t iEdgedWidth = data->iEdgedWidth;
192          MACROBLOCK *const prevMBs = reference->mbs;          const uint32_t rounding = data->rounding;
193          const IMAGE *const pCurrent = &current->image;          const int halfpel_x = x/2;
194          const IMAGE *const pRef = &reference->image;          const int halfpel_y = y/2;
195            const uint8_t *ref1, *ref2, *ref3, *ref4;
196    
197          static const VECTOR zeroMV = { 0, 0 };          ref1 = GetReference(halfpel_x, halfpel_y, dir, data); // this reference is used in all cases
198            switch( ((x&1)<<1) + (y&1) ) {
199            case 0: // pure halfpel position
200                    return (uint8_t *) GetReference(halfpel_x, halfpel_y, dir, data);
201            case 1: // x halfpel, y qpel - top or bottom during qpel refinement
202                    ref2 = GetReference(halfpel_x, y - halfpel_y, dir, data);
203                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
204                    interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
205                    interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
206                    interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
207                    break;
208    
209          int32_t x, y;          case 2: // x qpel, y halfpel - left or right during qpel refinement
210          int32_t iIntra = 0;                  ref2 = GetReference(x - halfpel_x, halfpel_y, dir, data);
211          VECTOR pmv;                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
212                    interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
213                    interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
214                    interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
215                    break;
216    
217          if (sadInit)          default: // x and y in qpel resolution - the "corners" (top left/right and
218                  (*sadInit) ();                           // bottom left/right) during qpel refinement
219                    ref2 = GetReference(halfpel_x, y - halfpel_y, dir, data);
220                    ref3 = GetReference(x - halfpel_x, halfpel_y, dir, data);
221                    ref4 = GetReference(x - halfpel_x, y - halfpel_y, dir, data);
222                    interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
223                    interpolate8x8_avg4(Reference+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, rounding);
224                    interpolate8x8_avg4(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, rounding);
225                    interpolate8x8_avg4(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, rounding);
226                    break;
227            }
228            return Reference;
229    }
230    
231          for (y = 0; y < iHcount; y++)   {  /* CHECK_CANDIATE FUNCTIONS START */
                 for (x = 0; x < iWcount; x ++)  {  
232    
233                          MACROBLOCK *const pMB = &pMBs[x + y * iWcount];  static void
234    CheckCandidate16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
235    {
236            int t, xc, yc;
237            const uint8_t * Reference;
238            VECTOR * current;
239    
240                          pMB->sad16 =          if (( x > data->max_dx) || ( x < data->min_dx)
241                                  SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,                  || ( y > data->max_dy) || (y < data->min_dy)) return;
                                                  y, current->motion_flags, current->quant,  
                                                  current->fcode, pParam, pMBs, prevMBs, &pMB->mv16,  
                                                  &pMB->pmvs[0]);  
242    
243                          if (0 < (pMB->sad16 - MV16_INTER_BIAS)) {          if (data->qpel_precision) { // x and y are in 1/4 precision
244                                  int32_t deviation;                  Reference = Interpolate16x16qpel(x, y, 0, data);
245                    t = d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
246                    xc = x/2; yc = y/2; //for chroma sad
247                    current = data->currentQMV;
248            } else {
249                    switch ( ((x&1)<<1) + (y&1) ) {
250                            case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
251                            case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;
252                            case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;
253                            default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
254                    }
255                    if (data->qpel) t = d_mv_bits(2*x - data->predMV.x, 2*y - data->predMV.y, data->iFcode);
256                    else t = d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
257                    current = data->currentMV;
258                    xc = x; yc = y;
259            }
260    
261                                  deviation =          data->temp[0] = sad16v(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
                                         dev16(pCurrent->y + x * 16 + y * 16 * pParam->edged_width,  
                                                   pParam->edged_width);  
262    
263                                  if (deviation < (pMB->sad16 - MV16_INTER_BIAS)) {          data->temp[0] += (data->lambda16 * t * data->temp[0])/1000;
264                                          pMB->mode = MODE_INTRA;          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))/100;
                                         pMB->mv16 = pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =  
                                                 pMB->mvs[3] = zeroMV;  
                                         pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =  
                                                 pMB->sad8[3] = 0;  
265    
266                                          iIntra++;          if (data->chroma) data->temp[0] += ChromaSAD(xc, yc, data);
                                         if (iIntra >= iLimit)  
                                                 return 1;  
267    
268                                          continue;          if (data->temp[0] < data->iMinSAD[0]) {
269                                  }                  data->iMinSAD[0] = data->temp[0];
270                          }                  current[0].x = x; current[0].y = y;
271                    *dir = Direction; }
272    
273                          pmv = pMB->pmvs[0];          if (data->temp[1] < data->iMinSAD[1]) {
274                          if (current->global_flags & XVID_INTER4V)                  data->iMinSAD[1] = data->temp[1]; current[1].x = x; current[1].y= y; }
275                                  if ((!(current->global_flags & XVID_LUMIMASKING) ||          if (data->temp[2] < data->iMinSAD[2]) {
276                                           pMB->dquant == NO_CHANGE)) {                  data->iMinSAD[2] = data->temp[2]; current[2].x = x; current[2].y = y; }
277                                          int32_t sad8 = IMV16X16 * current->quant;          if (data->temp[3] < data->iMinSAD[3]) {
278                    data->iMinSAD[3] = data->temp[3]; current[3].x = x; current[3].y = y; }
279                                          if (sad8 < pMB->sad16)          if (data->temp[4] < data->iMinSAD[4]) {
280                    data->iMinSAD[4] = data->temp[4]; current[4].x = x; current[4].y = y; }
                                                 sad8 += pMB->sad8[0] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x, 2 * y, pMB->mv16.x,  
                                                                         pMB->mv16.y, current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[0],  
                                                                         &pMB->pmvs[0]);  
   
                                         if (sad8 < pMB->sad16)  
                                                 sad8 += pMB->sad8[1] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x + 1, 2 * y, pMB->mv16.x,  
                                                                         pMB->mv16.y, current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[1],  
                                                                         &pMB->pmvs[1]);  
   
                                         if (sad8 < pMB->sad16)  
                                                 sad8 += pMB->sad8[2] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x, 2 * y + 1, pMB->mv16.x,  
                                                                         pMB->mv16.y, current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[2],  
                                                                         &pMB->pmvs[2]);  
   
                                         if (sad8 < pMB->sad16)  
                                                 sad8 += pMB->sad8[3] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x + 1, 2 * y + 1,  
                                                                         pMB->mv16.x, pMB->mv16.y,  
                                                                         current->motion_flags, current->quant,  
                                                                         current->fcode, pParam, pMBs, prevMBs,  
                                                                         &pMB->mvs[3], &pMB->pmvs[3]);  
   
                                         /* decide: MODE_INTER or MODE_INTER4V  
                                            mpeg4:   if (sad8 < pMB->sad16 - nb/2+1) use_inter4v  
                                          */  
281    
                                         if (sad8 < pMB->sad16) {  
                                                 pMB->mode = MODE_INTER4V;  
                                                 pMB->sad8[0] *= 4;  
                                                 pMB->sad8[1] *= 4;  
                                                 pMB->sad8[2] *= 4;  
                                                 pMB->sad8[3] *= 4;  
                                                 continue;  
282                                          }                                          }
283    
284                                  }  static void
285    CheckCandidate16no4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
286    {
287            int32_t sad;
288            const uint8_t * Reference;
289            int t;
290            VECTOR * current;
291    
292                          pMB->mode = MODE_INTER;          if (( x > data->max_dx) || ( x < data->min_dx)
293                          pMB->pmvs[0] = pmv;     /* pMB->pmvs[1] = pMB->pmvs[2] = pMB->pmvs[3]  are not needed for INTER */                  || ( y > data->max_dy) || (y < data->min_dy)) return;
294                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mv16;  
295                          pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] =          if (data->qpel_precision) { // x and y are in 1/4 precision
296                                  pMB->sad16;                  Reference = Interpolate16x16qpel(x, y, 0, data);
297                    t = d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
298                    current = data->currentQMV;
299            } else {
300                    switch ( ((x&1)<<1) + (y&1) ) {
301                            case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
302                            case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;
303                            case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;
304                            default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
305                          }                          }
306                    if (data->qpel) t = d_mv_bits(2*x - data->predMV.x, 2*y - data->predMV.y, data->iFcode);
307                    else t = d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
308                    current = data->currentMV;
309                          }                          }
310    
311          return 0;          sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
312            sad += (data->lambda16 * t * sad)/1000;
313    
314            if (sad < *(data->iMinSAD)) {
315                    *(data->iMinSAD) = sad;
316                    current->x = x; current->y = y;
317                    *dir = Direction; }
318  }  }
319    
320  #define CHECK_MV16_ZERO {\  static void
321    if ( (0 <= max_dx) && (0 >= min_dx) \  CheckCandidate16no4vI(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
     && (0 <= max_dy) && (0 >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \  
     iSAD += calc_delta_16(-pmv[0].x, -pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=0; currMV->y=0; }  }     \  
 }  
   
 #define NOCHECK_MV16_CANDIDATE(X,Y) { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \  
 }  
   
 #define CHECK_MV16_CANDIDATE(X,Y) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_CANDIDATE_DIR(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \  
 }  
   
 #define CHECK_MV16_CANDIDATE_FOUND(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
 }  
   
   
 #define CHECK_MV8_ZERO {\  
   iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, 0, 0 , iEdgedWidth), iEdgedWidth); \  
   iSAD += calc_delta_8(-pmv[0].x, -pmv[0].y, (uint8_t)iFcode, iQuant);\  
   if (iSAD < iMinSAD) \  
   { iMinSAD=iSAD; currMV->x=0; currMV->y=0; } \  
 }  
   
 #define NOCHECK_MV8_CANDIDATE(X,Y) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \  
 }  
   
 #define CHECK_MV8_CANDIDATE(X,Y) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV8_CANDIDATE_DIR(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \  
 }  
   
 #define CHECK_MV8_CANDIDATE_FOUND(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
 }  
   
 /* too slow and not fully functional at the moment */  
 /*  
 int32_t ZeroSearch16(  
                                         const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const IMAGE * const pCur,  
                                         const int x, const int y,  
                                         const uint32_t MotionFlags,  
                                         const uint32_t iQuant,  
                                         const uint32_t iFcode,  
                                         MBParam * const pParam,  
                                         const MACROBLOCK * const pMBs,  
                                         const MACROBLOCK * const prevMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
322  {  {
323          const int32_t iEdgedWidth = pParam->edged_width;  // maximum speed - for P/B/I decision
324          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;          int32_t sad;
         int32_t iSAD;  
         VECTOR pred;  
325    
326            if (( x > data->max_dx) || ( x < data->min_dx)
327                    || ( y > data->max_dy) || (y < data->min_dy)) return;
328    
329          pred = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          sad = sad16(data->Cur, data->Ref + x/2 + (y/2)*(data->iEdgedWidth),
330                                            data->iEdgedWidth, 256*4096);
331    
332          iSAD = sad16( cur,          if (sad < *(data->iMinSAD)) {
333                  get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth),                  *(data->iMinSAD) = sad;
334                  iEdgedWidth, MV_MAX_ERROR);                  data->currentMV[0].x = x; data->currentMV[0].y = y;
335          if (iSAD <= iQuant * 96)                  *dir = Direction; }
336                  iSAD -= MV16_00_BIAS;  }
337    
         currMV->x = 0;  
         currMV->y = 0;  
         currPMV->x = -pred.x;  
         currPMV->y = -pred.y;  
338    
339          return iSAD;  static void
340    CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)
341    {
342            int32_t sad;
343            int xb, yb, t;
344            const uint8_t *ReferenceF, *ReferenceB;
345            VECTOR *current;
346    
347            if (( xf > data->max_dx) || ( xf < data->min_dx)
348                    || ( yf > data->max_dy) || (yf < data->min_dy)) return;
349    
350            if (data->qpel_precision) {
351                    ReferenceF = Interpolate16x16qpel(xf, yf, 0, data);
352                    xb = data->currentQMV[1].x; yb = data->currentQMV[1].y;
353                    current = data->currentQMV;
354                    ReferenceB = Interpolate16x16qpel(xb, yb, 1, data);
355                    t = d_mv_bits(xf - data->predMV.x, yf - data->predMV.y, data->iFcode)
356                                     + d_mv_bits(xb - data->bpredMV.x, yb - data->bpredMV.y, data->iFcode);
357            } else {
358                    ReferenceF = Interpolate16x16qpel(2*xf, 2*yf, 0, data);
359                    xb = data->currentMV[1].x; yb = data->currentMV[1].y;
360                    ReferenceB = Interpolate16x16qpel(2*xb, 2*yb, 1, data);
361                    current = data->currentMV;
362                    if (data->qpel)
363                            t = d_mv_bits(2*xf - data->predMV.x, 2*yf - data->predMV.y, data->iFcode)
364                                             + d_mv_bits(2*xb - data->bpredMV.x, 2*yb - data->bpredMV.y, data->iFcode);
365                    else
366                            t = d_mv_bits(xf - data->predMV.x, yf - data->predMV.y, data->iFcode)
367                                             + d_mv_bits(xb - data->bpredMV.x, yb - data->bpredMV.y, data->iFcode);
368  }  }
 */  
369    
370  int32_t          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
371  Diamond16_MainSearch(const uint8_t * const pRef,          sad += (data->lambda16 * t * sad)/1000;
372                                           const uint8_t * const pRefH,  
373                                           const uint8_t * const pRefV,          if (sad < *(data->iMinSAD)) {
374                                           const uint8_t * const pRefHV,                  *(data->iMinSAD) = sad;
375                                           const uint8_t * const cur,                  current->x = xf; current->y = yf;
376                                           const int x,                  *dir = Direction; }
377                                           const int y,  }
378                                           int32_t startx,  
379                                           int32_t starty,  static void
380                                           int32_t iMinSAD,  CheckCandidateDirect(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                                          VECTOR * const currMV,  
                                          const VECTOR * const pmv,  
                                          const int32_t min_dx,  
                                          const int32_t max_dx,  
                                          const int32_t min_dy,  
                                          const int32_t max_dy,  
                                          const int32_t iEdgedWidth,  
                                          const int32_t iDiamondSize,  
                                          const int32_t iFcode,  
                                          const int32_t iQuant,  
                                          int iFound)  
381  {  {
382  /* Do a diamond search around given starting point, return SAD of best */          int32_t sad = 0;
383            int k;
384            const uint8_t *ReferenceF;
385            const uint8_t *ReferenceB;
386            VECTOR mvs, b_mvs;
387    
388          int32_t iDirection = 0;          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
         int32_t iSAD;  
         VECTOR backupMV;  
389    
390          backupMV.x = startx;          for (k = 0; k < 4; k++) {
391          backupMV.y = starty;                  mvs.x = data->directmvF[k].x + x;
392                    b_mvs.x = ((x == 0) ?
393                            data->directmvB[k].x
394                            : mvs.x - data->referencemv[k].x);
395    
396  /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */                  mvs.y = data->directmvF[k].y + y;
397                    b_mvs.y = ((y == 0) ?
398                            data->directmvB[k].y
399                            : mvs.y - data->referencemv[k].y);
400    
401          CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);                  if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
402          CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);                          || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
403          CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);                          || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
404          CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);                          || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
405    
406          if (iDirection)                  if (!data->qpel) {
407                  while (!iFound) {                          mvs.x *= 2; mvs.y *= 2;
408                          iFound = 1;                          b_mvs.x *= 2; b_mvs.y *= 2; //we move to qpel precision anyway
                         backupMV = *currMV;  
   
                         if (iDirection != 2)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                    backupMV.y, 1);  
                         if (iDirection != 1)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                    backupMV.y, 2);  
                         if (iDirection != 4)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,  
                                                                                    backupMV.y - iDiamondSize, 3);  
                         if (iDirection != 3)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,  
                                                                                    backupMV.y + iDiamondSize, 4);  
         } else {  
                 currMV->x = startx;  
                 currMV->y = starty;  
         }  
         return iMinSAD;  
409  }  }
410                    ReferenceF = Interpolate8x8qpel(mvs.x, mvs.y, k, 0, data);
411                    ReferenceB = Interpolate8x8qpel(b_mvs.x, b_mvs.y, k, 1, data);
412    
413  int32_t                  sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
414  Square16_MainSearch(const uint8_t * const pRef,                                                  ReferenceF, ReferenceB,
415                                          const uint8_t * const pRefH,                                                  data->iEdgedWidth);
416                                          const uint8_t * const pRefV,                  if (sad > *(data->iMinSAD)) return;
417                                          const uint8_t * const pRefHV,          }
                                         const uint8_t * const cur,  
                                         const int x,  
                                         const int y,  
                                         int32_t startx,  
                                         int32_t starty,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                         const VECTOR * const pmv,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a square search around given starting point, return SAD of best */  
418    
419          int32_t iDirection = 0;          sad += (data->lambda16 * d_mv_bits(x, y, 1) * sad)/1000;
         int32_t iSAD;  
         VECTOR backupMV;  
420    
421          backupMV.x = startx;          if (sad < *(data->iMinSAD)) {
422          backupMV.y = starty;                  *(data->iMinSAD) = sad;
423                    data->currentMV->x = x; data->currentMV->y = y;
424                    *dir = Direction; }
425    }
426    
427  /* It's one search with full square pattern, and new parts for all following diamonds */  static void
428    CheckCandidateDirectno4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
429    {
430            int32_t sad;
431            const uint8_t *ReferenceF;
432            const uint8_t *ReferenceB;
433            VECTOR mvs, b_mvs;
434    
435  /*   new direction are extra, so 1-4 is normal diamond          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
       537  
       1*2  
       648  
 */  
   
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
   
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 5);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 6);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 7);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 8);  
   
   
         if (iDirection)  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;  
436    
437                          switch (iDirection) {          mvs.x = data->directmvF[0].x + x;
438                          case 1:          b_mvs.x = ((x == 0) ?
439                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  data->directmvB[0].x
440                                                                                     backupMV.y, 1);                  : mvs.x - data->referencemv[0].x);
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
                         case 2:  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
441    
442                          case 3:          mvs.y = data->directmvF[0].y + y;
443                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize,          b_mvs.y = ((y == 0) ?
444                                                                                   4);                  data->directmvB[0].y
445                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,                  : mvs.y - data->referencemv[0].y);
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
446    
447                          case 4:          if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
448                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize,                  || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
449                                                                                   3);                  || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
450                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,                  || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 break;  
   
                         case 5:  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
   
                         case 6:  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
   
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
451    
452                                  break;          if (!data->qpel) {
453                            mvs.x *= 2; mvs.y *= 2;
454                            b_mvs.x *= 2; b_mvs.y *= 2; //we move to qpel precision anyway
455                    }
456            ReferenceF = Interpolate16x16qpel(mvs.x, mvs.y, 0, data);
457            ReferenceB = Interpolate16x16qpel(b_mvs.x, b_mvs.y, 1, data);
458    
459                          case 7:          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
460                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          sad += (data->lambda16 * d_mv_bits(x, y, 1) * sad)/1000;
                                                                                    backupMV.y, 1);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
461    
462                          case 8:          if (sad < *(data->iMinSAD)) {
463                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y,                  *(data->iMinSAD) = sad;
464                                                                                   2);                  data->currentMV->x = x; data->currentMV->y = y;
465                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize,                  *dir = Direction; }
                                                                                  4);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         default:  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
   
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         }  
         } else {  
                 currMV->x = startx;  
                 currMV->y = starty;  
466          }          }
         return iMinSAD;  
 }  
   
467    
468  int32_t  static void
469  Full16_MainSearch(const uint8_t * const pRef,  CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                                   const uint8_t * const pRefH,  
                                   const uint8_t * const pRefV,  
                                   const uint8_t * const pRefHV,  
                                   const uint8_t * const cur,  
                                   const int x,  
                                   const int y,  
                                   int32_t startx,  
                                   int32_t starty,  
                                   int32_t iMinSAD,  
                                   VECTOR * const currMV,  
                                   const VECTOR * const pmv,  
                                   const int32_t min_dx,  
                                   const int32_t max_dx,  
                                   const int32_t min_dy,  
                                   const int32_t max_dy,  
                                   const int32_t iEdgedWidth,  
                                   const int32_t iDiamondSize,  
                                   const int32_t iFcode,  
                                   const int32_t iQuant,  
                                   int iFound)  
470  {  {
471          int32_t iSAD;          int32_t sad; int t;
472          int32_t dx, dy;          const uint8_t * Reference;
473          VECTOR backupMV;  
474            if (( x > data->max_dx) || ( x < data->min_dx)
475                    || ( y > data->max_dy) || (y < data->min_dy)) return;
476    
477            if (data->qpel) Reference = Interpolate16x16qpel(x, y, 0, data);
478            else Reference = Interpolate16x16qpel(2*x, 2*y, 0, data);
479    
480          backupMV.x = startx;          sad = sad8(data->Cur, Reference, data->iEdgedWidth);
481          backupMV.y = starty;          if (data->qpel) t = d_mv_bits(2 * x - data->predMV.x, 2 * y - data->predMV.y, data->iFcode);
482            else t = d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
483    
484          for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)          sad += (data->lambda8 * t * (sad+NEIGH_8X8_BIAS))/100;
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV16_CANDIDATE(dx, dy);  
485    
486          return iMinSAD;          if (sad < *(data->iMinSAD)) {
487                    *(data->iMinSAD) = sad;
488                    data->currentMV->x = x; data->currentMV->y = y;
489                    *dir = Direction; }
490  }  }
491    
492  int32_t  /* CHECK_CANDIATE FUNCTIONS END */
 AdvDiamond16_MainSearch(const uint8_t * const pRef,  
                                                 const uint8_t * const pRefH,  
                                                 const uint8_t * const pRefV,  
                                                 const uint8_t * const pRefHV,  
                                                 const uint8_t * const cur,  
                                                 const int x,  
                                                 const int y,  
                                                 int32_t startx,  
                                                 int32_t starty,  
                                                 int32_t iMinSAD,  
                                                 VECTOR * const currMV,  
                                                 const VECTOR * const pmv,  
                                                 const int32_t min_dx,  
                                                 const int32_t max_dx,  
                                                 const int32_t min_dy,  
                                                 const int32_t max_dy,  
                                                 const int32_t iEdgedWidth,  
                                                 const int32_t iDiamondSize,  
                                                 const int32_t iFcode,  
                                                 const int32_t iQuant,  
                                                 int iDirection)  
 {  
493    
494          int32_t iSAD;  /* MAINSEARCH FUNCTIONS START */
495    
496    static void
497    AdvDiamondSearch(int x, int y, const SearchData * const data, int bDirection)
498    {
499    
500  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
501    
502          if (iDirection) {                  int iDirection;
                 CHECK_MV16_CANDIDATE(startx - iDiamondSize, starty);  
                 CHECK_MV16_CANDIDATE(startx + iDiamondSize, starty);  
                 CHECK_MV16_CANDIDATE(startx, starty - iDiamondSize);  
                 CHECK_MV16_CANDIDATE(startx, starty + iDiamondSize);  
         } else {  
                 int bDirection = 1 + 2 + 4 + 8;  
503    
504                  do {                  do {
505                          iDirection = 0;                          iDirection = 0;
506                          if (bDirection & 1)     //we only want to check left if we came from the right (our last motion was to the left, up-left or down-left)                          if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
507                                  CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);                          if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
508                            if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
509                          if (bDirection & 2)                          if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
                                 CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);  
   
                         if (bDirection & 4)  
                                 CHECK_MV16_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);  
   
                         if (bDirection & 8)  
                                 CHECK_MV16_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);  
510    
511                          /* now we're doing diagonal checks near our candidate */                          /* now we're doing diagonal checks near our candidate */
512    
513                          if (iDirection)         //checking if anything found                          if (iDirection) {               //checking if anything found
                         {  
514                                  bDirection = iDirection;                                  bDirection = iDirection;
515                                  iDirection = 0;                                  iDirection = 0;
516                                  startx = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
517                                  starty = currMV->y;                                  if (bDirection & 3) {   //our candidate is left or right
518                                  if (bDirection & 3)     //our candidate is left or right                                          CHECK_CANDIDATE(x, y + iDiamondSize, 8);
519                                  {                                          CHECK_CANDIDATE(x, y - iDiamondSize, 4);
520                                          CHECK_MV16_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);                                  } else {                        // what remains here is up or down
521                                          CHECK_MV16_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y, 2);
522                                  } else                  // what remains here is up or down                                          CHECK_CANDIDATE(x - iDiamondSize, y, 1); }
                                 {  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);  
                                 }  
523    
524                                  if (iDirection) {                                  if (iDirection) {
525                                          bDirection += iDirection;                                          bDirection += iDirection;
526                                          startx = currMV->x;                                          x = data->currentMV->x; y = data->currentMV->y; }
527                                          starty = currMV->y;                          } else {                                //about to quit, eh? not so fast....
                                 }  
                         } else                          //about to quit, eh? not so fast....  
                         {  
528                                  switch (bDirection) {                                  switch (bDirection) {
529                                  case 2:                                  case 2:
530                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
531                                                                                           starty - iDiamondSize, 2 + 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
532                                          break;                                          break;
533                                  case 1:                                  case 1:
534                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
535                                                                                           starty - iDiamondSize, 1 + 4);                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty + iDiamondSize, 1 + 8);  
536                                          break;                                          break;
537                                  case 2 + 4:                                  case 2 + 4:
538                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
539                                                                                           starty - iDiamondSize, 1 + 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
540                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                          starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
541                                          break;                                          break;
542                                  case 4:                                  case 4:
543                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
544                                                                                           starty - iDiamondSize, 2 + 4);                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty - iDiamondSize, 1 + 4);  
545                                          break;                                          break;
546                                  case 8:                                  case 8:
547                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
548                                                                                           starty + iDiamondSize, 2 + 8);                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty + iDiamondSize, 1 + 8);  
549                                          break;                                          break;
550                                  case 1 + 4:                                  case 1 + 4:
551                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
552                                                                                           starty + iDiamondSize, 1 + 8);                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
553                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
                                                                                          starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty - iDiamondSize, 2 + 4);  
554                                          break;                                          break;
555                                  case 2 + 8:                                  case 2 + 8:
556                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
557                                                                                           starty - iDiamondSize, 1 + 4);                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
558                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                          starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
559                                          break;                                          break;
560                                  case 1 + 8:                                  case 1 + 8:
561                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
562                                                                                           starty - iDiamondSize, 2 + 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
563                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                                                                          starty + iDiamondSize, 2 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty + iDiamondSize, 1 + 8);  
564                                          break;                                          break;
565                                  default:                //1+2+4+8 == we didn't find anything at all                                  default:                //1+2+4+8 == we didn't find anything at all
566                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
567                                                                                           starty - iDiamondSize, 1 + 4);                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
568                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
569                                                                                           starty + iDiamondSize, 1 + 8);                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
570                                          break;                                          break;
571                                  }                                  }
572                                  if (!iDirection)                                  if (!iDirection) break;         //ok, the end. really
                                         break;          //ok, the end. really  
                                 else {  
573                                          bDirection = iDirection;                                          bDirection = iDirection;
574                                          startx = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
                                         starty = currMV->y;  
                                 }  
575                          }                          }
576                  }                  }
577                  while (1);                              //forever                  while (1);                              //forever
578          }          }
         return iMinSAD;  
 }  
579    
580  int32_t  static void
581  AdvDiamond8_MainSearch(const uint8_t * const pRef,  SquareSearch(int x, int y, const SearchData * const data, int bDirection)
                                            const uint8_t * const pRefH,  
                                            const uint8_t * const pRefV,  
                                            const uint8_t * const pRefHV,  
                                            const uint8_t * const cur,  
                                            const int x,  
                                            const int y,  
                                            int32_t startx,  
                                            int32_t starty,  
                                            int32_t iMinSAD,  
                                            VECTOR * const currMV,  
                                            const VECTOR * const pmv,  
                                            const int32_t min_dx,  
                                            const int32_t max_dx,  
                                            const int32_t min_dy,  
                                            const int32_t max_dy,  
                                            const int32_t iEdgedWidth,  
                                            const int32_t iDiamondSize,  
                                            const int32_t iFcode,  
                                            const int32_t iQuant,  
                                            int iDirection)  
582  {  {
583            int iDirection;
584    
585            do {
586                    iDirection = 0;
587                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);
588                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);
589                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);
590                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128);
591                    if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64);
592                    if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128);
593                    if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128);
594                    if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128);
595    
596                    bDirection = iDirection;
597                    x = data->currentMV->x; y = data->currentMV->y;
598            } while (iDirection);
599    }
600    
601          int32_t iSAD;  static void
602    DiamondSearch(int x, int y, const SearchData * const data, int bDirection)
603    {
604    
605  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
606    
607          if (iDirection) {                  int iDirection;
                 CHECK_MV8_CANDIDATE(startx - iDiamondSize, starty);  
                 CHECK_MV8_CANDIDATE(startx + iDiamondSize, starty);  
                 CHECK_MV8_CANDIDATE(startx, starty - iDiamondSize);  
                 CHECK_MV8_CANDIDATE(startx, starty + iDiamondSize);  
         } else {  
                 int bDirection = 1 + 2 + 4 + 8;  
608    
609                  do {                  do {
610                          iDirection = 0;                          iDirection = 0;
611                          if (bDirection & 1)     //we only want to check left if we came from the right (our last motion was to the left, up-left or down-left)                          if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
612                                  CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);                          if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
613                            if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
614                          if (bDirection & 2)                          if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
                                 CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);  
   
                         if (bDirection & 4)  
                                 CHECK_MV8_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);  
   
                         if (bDirection & 8)  
                                 CHECK_MV8_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);  
615    
616                          /* now we're doing diagonal checks near our candidate */                          /* now we're doing diagonal checks near our candidate */
617    
618                          if (iDirection)         //checking if anything found                          if (iDirection) {               //checking if anything found
                         {  
619                                  bDirection = iDirection;                                  bDirection = iDirection;
620                                  iDirection = 0;                                  iDirection = 0;
621                                  startx = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
622                                  starty = currMV->y;                                  if (bDirection & 3) {   //our candidate is left or right
623                                  if (bDirection & 3)     //our candidate is left or right                                          CHECK_CANDIDATE(x, y + iDiamondSize, 8);
624                                  {                                          CHECK_CANDIDATE(x, y - iDiamondSize, 4);
625                                          CHECK_MV8_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);                                  } else {                        // what remains here is up or down
626                                          CHECK_MV8_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y, 2);
627                                  } else                  // what remains here is up or down                                          CHECK_CANDIDATE(x - iDiamondSize, y, 1); }
                                 {  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);  
                                 }  
628    
                                 if (iDirection) {  
629                                          bDirection += iDirection;                                          bDirection += iDirection;
630                                          startx = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
                                         starty = currMV->y;  
                                 }  
                         } else                          //about to quit, eh? not so fast....  
                         {  
                                 switch (bDirection) {  
                                 case 2:  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1:  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 2 + 4:  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 4:  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         break;  
                                 case 8:  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 1 + 4:  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         break;  
                                 case 2 + 8:  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1 + 8:  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         break;  
                                 default:                //1+2+4+8 == we didn't find anything at all  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         break;  
                                 }  
                                 if (!(iDirection))  
                                         break;          //ok, the end. really  
                                 else {  
                                         bDirection = iDirection;  
                                         startx = currMV->x;  
                                         starty = currMV->y;  
                                 }  
631                          }                          }
632                  }                  }
633                  while (1);                              //forever                  while (iDirection);
         }  
         return iMinSAD;  
634  }  }
635    
636    /* MAINSEARCH FUNCTIONS END */
637    
638  int32_t  /* HALFPELREFINE COULD BE A MAINSEARCH FUNCTION, BUT THERE IS NO NEED FOR IT */
639  Full8_MainSearch(const uint8_t * const pRef,  
640                                   const uint8_t * const pRefH,  static void
641                                   const uint8_t * const pRefV,  SubpelRefine(const SearchData * const data)
                                  const uint8_t * const pRefHV,  
                                  const uint8_t * const cur,  
                                  const int x,  
                                  const int y,  
                                  int32_t startx,  
                                  int32_t starty,  
                                  int32_t iMinSAD,  
                                  VECTOR * const currMV,  
                                  const VECTOR * const pmv,  
                                  const int32_t min_dx,  
                                  const int32_t max_dx,  
                                  const int32_t min_dy,  
                                  const int32_t max_dy,  
                                  const int32_t iEdgedWidth,  
                                  const int32_t iDiamondSize,  
                                  const int32_t iFcode,  
                                  const int32_t iQuant,  
                                  int iFound)  
642  {  {
643          int32_t iSAD;  /* Do a half-pel or q-pel refinement */
         int32_t dx, dy;  
644          VECTOR backupMV;          VECTOR backupMV;
645            int iDirection; //not needed
646    
647          backupMV.x = startx;          if (data->qpel_precision)
648          backupMV.y = starty;                  backupMV = *(data->currentQMV);
649            else backupMV = *(data->currentMV);
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV8_CANDIDATE(dx, dy);  
650    
651          return iMinSAD;          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y - 1, 0);
652  }          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y - 1, 0);
653            CHECK_CANDIDATE(backupMV.x - 1, backupMV.y + 1, 0);
654            CHECK_CANDIDATE(backupMV.x + 1, backupMV.y + 1, 0);
655    
656  Halfpel8_RefineFuncPtr Halfpel8_Refine;          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y, 0);
657            CHECK_CANDIDATE(backupMV.x + 1, backupMV.y, 0);
 int32_t  
 Halfpel16_Refine(const uint8_t * const pRef,  
                                  const uint8_t * const pRefH,  
                                  const uint8_t * const pRefV,  
                                  const uint8_t * const pRefHV,  
                                  const uint8_t * const cur,  
                                  const int x,  
                                  const int y,  
                                  VECTOR * const currMV,  
                                  int32_t iMinSAD,  
                                  const VECTOR * const pmv,  
                                  const int32_t min_dx,  
                                  const int32_t max_dx,  
                                  const int32_t min_dy,  
                                  const int32_t max_dy,  
                                  const int32_t iFcode,  
                                  const int32_t iQuant,  
                                  const int32_t iEdgedWidth)  
 {  
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
   
         int32_t iSAD;  
         VECTOR backupMV = *currMV;  
   
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y - 1);  
         CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y - 1);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y - 1);  
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y + 1);  
         CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y + 1);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y + 1);  
658    
659          return iMinSAD;          CHECK_CANDIDATE(backupMV.x, backupMV.y + 1, 0);
660            CHECK_CANDIDATE(backupMV.x, backupMV.y - 1, 0);
661  }  }
662    
663  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)  static __inline int
664    SkipDecisionP(const IMAGE * current, const IMAGE * reference,
665                                                            const int x, const int y,
666                                                            const uint32_t iEdgedWidth, const uint32_t iQuant)
667    
 int32_t  
 PMVfastSearch16(const uint8_t * const pRef,  
                                 const uint8_t * const pRefH,  
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const IMAGE * const pCur,  
                                 const int x,  
                                 const int y,  
                                 const uint32_t MotionFlags,  
                                 const uint32_t iQuant,  
                                 const uint32_t iFcode,  
                                 const MBParam * const pParam,  
                                 const MACROBLOCK * const pMBs,  
                                 const MACROBLOCK * const prevMBs,  
                                 VECTOR * const currMV,  
                                 VECTOR * const currPMV)  
668  {  {
669          const uint32_t iWcount = pParam->mb_width;  /*      keep repeating checks for all b-frames before this P frame,
670          const int32_t iWidth = pParam->width;          to make sure that SKIP is possible (todo)
671          const int32_t iHeight = pParam->height;          how: if skip is not possible set sad00 to a very high value */
672          const int32_t iEdgedWidth = pParam->edged_width;  
673            uint32_t sadC = sad8(current->u + x*8 + y*(iEdgedWidth/2)*8,
674          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;                                          reference->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2);
675            if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
676          int32_t iDiamondSize;          sadC += sad8(current->v + (x + y*(iEdgedWidth/2))*8,
677                                            reference->v + (x + y*(iEdgedWidth/2))*8, iEdgedWidth/2);
678          int32_t min_dx;          if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
   
         int32_t iFound;  
   
         VECTOR newMV;  
         VECTOR backupMV;                        /* just for PMVFAST */  
   
         VECTOR pmv[4];  
         int32_t psad[4];  
   
         MainSearch16FuncPtr MainSearchPtr;  
   
         const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;  
   
         int32_t threshA, threshB;  
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD;  
   
 /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
679    
680  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          return 1;
   
         if (!(MotionFlags & PMV_HALFPEL16)) {  
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
         }  
   
         /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
         //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);  
   
 /*      fprintf(stderr,"pmv: %d %d / %d --- %d %d   %d %d   %d %d - %d %d %d\n",  
                 pmv[0].x,pmv[0].y,psad[0],  
                 pmv[1].x,pmv[1].y,pmv[2].x,pmv[2].y,pmv[3].x,pmv[3].y,  
                 psad[1],psad[2],psad[3]);  
 */  
         if ((x == 0) && (y == 0)) {  
                 threshA = 512;  
                 threshB = 1024;  
         } else {  
                 threshA = psad[0];  
                 threshB = threshA + 256;  
                 if (threshA < 512)  
                         threshA = 512;  
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
681          }          }
682    
683          iFound = 0;  static __inline void
684    SkipMacroblockP(MACROBLOCK *pMB, const int32_t sad)
685    {
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  /* Step 4: Calculate SAD around the Median prediction.          pMB->qmvs[0].x = pMB->qmvs[1].x = pMB->qmvs[2].x = pMB->qmvs[3].x = 0;
691     MinSAD=SAD          pMB->qmvs[0].y = pMB->qmvs[1].y = pMB->qmvs[2].y = pMB->qmvs[3].y = 0;
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
692    
693          *currMV = pmv[0];                       /* current best := prediction */          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
         if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */  
                 currMV->x = EVEN(currMV->x);  
                 currMV->y = EVEN(currMV->y);  
694          }          }
695    
696          if (currMV->x > max_dx) {  bool
697                  currMV->x = max_dx;  MotionEstimation(MBParam * const pParam,
698          }                                   FRAMEINFO * const current,
699          if (currMV->x < min_dx) {                                   FRAMEINFO * const reference,
700                  currMV->x = min_dx;                                   const IMAGE * const pRefH,
701          }                                   const IMAGE * const pRefV,
702          if (currMV->y > max_dy) {                                   const IMAGE * const pRefHV,
703                  currMV->y = max_dy;                                   const uint32_t iLimit)
         }  
         if (currMV->y < min_dy) {  
                 currMV->y = min_dy;  
         }  
   
         iMinSAD =  
                 sad16(cur,  
                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - pmv[0].x, currMV->y - pmv[0].y,  
                                           (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
704                  {                  {
705                          if (!MVzero(*currMV)) {          MACROBLOCK *const pMBs = current->mbs;
706                                  iMinSAD += MV16_00_BIAS;          const IMAGE *const pCurrent = &current->image;
707                                  CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures          const IMAGE *const pRef = &reference->image;
                                 iMinSAD -= MV16_00_BIAS;  
                         }  
                 }  
   
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
         }  
   
   
 /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  
    vector of the median.  
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
   
         if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[0])))  
                 iFound = 2;  
   
 /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.  
    Otherwise select large Diamond Search.  
 */  
   
         if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))  
                 iDiamondSize = 1;               // halfpel!  
         else  
                 iDiamondSize = 2;               // halfpel!  
   
         if (!(MotionFlags & PMV_HALFPELDIAMOND16))  
                 iDiamondSize *= 2;  
   
 /*  
    Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  
    Also calculate (0,0) but do not subtract offset.  
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset.  
 */  
   
 // (0,0) is always possible  
   
         if (!MVzero(pmv[0]))  
                 CHECK_MV16_ZERO;  
   
 // previous frame MV is always possible  
   
         if (!MVzero(prevMB->mvs[0]))  
                 if (!MVequal(prevMB->mvs[0], pmv[0]))  
                         CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);  
708    
709  // left neighbour, if allowed          const VECTOR zeroMV = { 0, 0 };
710    
711          if (!MVzero(pmv[1]))          uint32_t x, y;
712                  if (!MVequal(pmv[1], prevMB->mvs[0]))          uint32_t iIntra = 0;
713                          if (!MVequal(pmv[1], pmv[0])) {          int32_t InterBias, quant = current->quant, sad00;
714                                  if (!(MotionFlags & PMV_HALFPEL16)) {          uint8_t *qimage;
715                                          pmv[1].x = EVEN(pmv[1].x);  
716                                          pmv[1].y = EVEN(pmv[1].y);          // 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                                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  //initial skip decision
771    /* no early skip for GMC (global vector = skip vector is unknown!)  */
772                            if (current->coding_type == P_VOP)      { /* no fast SKIP for S(GMC)-VOPs */
773                                    if (pMB->dquant == NO_CHANGE && sad00 < pMB->quant * INITIAL_SKIP_THRESH)
774                                            if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, pParam->edged_width, pMB->quant)) {
775                                                    SkipMacroblockP(pMB, sad00);
776                                                    continue;
777                          }                          }
 // 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);  
778                                          }                                          }
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
779    
780  // top right neighbour, if allowed                          SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
781                                          if (!MVzero(pmv[3]))                                                  y, current->motion_flags, pMB->quant,
782                                                  if (!MVequal(pmv[3], prevMB->mvs[0]))                                                  &Data, pParam, pMBs, reference->mbs,
783                                                          if (!MVequal(pmv[3], pmv[0]))                                                  current->global_flags & XVID_INTER4V, pMB);
784                                                                  if (!MVequal(pmv[3], pmv[1]))  
785                                                                          if (!MVequal(pmv[3], pmv[2])) {  /* final skip decision, a.k.a. "the vector you found, really that good?" */
786                                                                                  if (!(MotionFlags & PMV_HALFPEL16)) {                          if (current->coding_type == P_VOP)      {
787                                                                                          pmv[3].x = EVEN(pmv[3].x);                                  if ( (pMB->dquant == NO_CHANGE) && (sad00 < pMB->quant * MAX_SAD00_FOR_SKIP)
788                                                                                          pmv[3].y = EVEN(pmv[3].y);                                  && ((100*pMB->sad16)/(sad00+1) > FINAL_SKIP_THRESH) )
789                                                                                  }                                          if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, pParam->edged_width, pMB->quant)) {
790                                                                                  CHECK_MV16_CANDIDATE(pmv[3].x,                                                  SkipMacroblockP(pMB, sad00);
791                                                                                                                           pmv[3].y);                                                  continue;
                                                                         }  
792                                  }                                  }
   
         if ((MVzero(*currMV)) &&  
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV16_00_BIAS;  
   
   
 /* Step 6: If MinSAD <= thresa goto Step 10.  
    If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
 */  
   
         if ((iMinSAD <= threshA) ||  
                 (MVequal(*currMV, prevMB->mvs[0]) &&  
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
793          }          }
794    
795    /* finally, intra decision */
796    
797  /************ (Diamond Search)  **************/                          InterBias = MV16_INTER_BIAS;
798  /*                          if (pMB->quant > 8)  InterBias += 100 * (pMB->quant - 8); // to make high quants work
799     Step 7: Perform Diamond search, with either the small or large diamond.                          if (y != 0)
800     If Found=2 only examine one Diamond pattern, and afterwards goto step 10                                  if ((pMB - pParam->mb_width)->mode == MODE_INTRA ) InterBias -= 80;
801     Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.                          if (x != 0)
802     If center then goto step 10.                                  if ((pMB - 1)->mode == MODE_INTRA ) InterBias -= 80;
    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);  
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
803    
804          if (MotionFlags & PMV_EXTSEARCH16) {                          if (Data.chroma) InterBias += 50; // to compensate bigger SAD
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
805    
806                  if (!(MVequal(pmv[0], backupMV))) {                          if (InterBias < pMB->sad16)  {
807                          iSAD =                                  const int32_t deviation =
808                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                          dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,
809                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, pmv,                                                    pParam->edged_width);
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
810    
811                          if (iSAD < iMinSAD) {                                  if (deviation < (pMB->sad16 - InterBias)) {
812                                  *currMV = newMV;                                          if (++iIntra >= iLimit) { free(qimage); return 1; }
813                                  iMinSAD = iSAD;                                          pMB->mode = MODE_INTRA;
814                                            pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =
815                                                            pMB->mvs[3] = zeroMV;
816                                            pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] =
817                                                            pMB->qmvs[3] = zeroMV;
818                                            pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =
819                                                    pMB->sad8[3] = 0;
820                          }                          }
821                  }                  }
   
                 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;  
822                          }                          }
823                  }                  }
824          }          free(qimage);
   
 /*  
    Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  
 */  
825    
826    PMVfast16_Terminate_with_Refine:          if (current->coding_type == S_VOP)      /* first GMC step only for S(GMC)-VOPs */
827          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step                  current->GMC_MV = GlobalMotionEst( pMBs, pParam, current->fcode );
828                  iMinSAD =          else
829                          Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,                  current->GMC_MV = zeroMV;
                                                          iMinSAD, pmv, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
830    
831  /*fprintf(stderr,"Chosen for %d %d: %d %d - %d %d\n",x,y,currMV->x,currMV->y,pmv[0].x,pmv[0].y);          return 0;
 */  
   PMVfast16_Terminate_without_Refine:  
         currPMV->x = currMV->x - pmv[0].x;  
         currPMV->y = currMV->y - pmv[0].y;  
         return iMinSAD;  
832  }  }
833    
834    
835    #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)
836    
837    static __inline int
838    make_mask(const VECTOR * const pmv, const int i)
   
 int32_t  
 Diamond8_MainSearch(const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x,  
                                         const int y,  
                                         int32_t startx,  
                                         int32_t starty,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                         const VECTOR * const pmv,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
839  {  {
840  /* Do a diamond search around given starting point, return SAD of best */          int mask = 255, j;
841            for (j = 0; j < i; j++) {
842          int32_t iDirection = 0;                  if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already
843          int32_t iSAD;                  if (pmv[i].x == pmv[j].x) {
844          VECTOR backupMV;                          if (pmv[i].y == pmv[j].y + iDiamondSize) { mask &= ~4; continue; }
845                            if (pmv[i].y == pmv[j].y - iDiamondSize) { mask &= ~8; continue; }
846          backupMV.x = startx;                  } else
847          backupMV.y = starty;                          if (pmv[i].y == pmv[j].y) {
848                                    if (pmv[i].x == pmv[j].x + iDiamondSize) { mask &= ~1; continue; }
849  /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */                                  if (pmv[i].x == pmv[j].x - iDiamondSize) { mask &= ~2; continue; }
   
         CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
   
         if (iDirection)  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;     // since iDirection!=0, this is well defined!  
   
                         if (iDirection != 2)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                   backupMV.y, 1);  
                         if (iDirection != 1)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                   backupMV.y, 2);  
                         if (iDirection != 4)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y - iDiamondSize, 3);  
                         if (iDirection != 3)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y + iDiamondSize, 4);  
         } else {  
                 currMV->x = startx;  
                 currMV->y = starty;  
850          }          }
         return iMinSAD;  
851  }  }
852            return mask;
 int32_t  
 Halfpel8_Refine_c(const uint8_t * const pRef,  
                                 const uint8_t * const pRefH,  
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const uint8_t * const cur,  
                                 const int x,  
                                 const int y,  
                                 VECTOR * const currMV,  
                                 int32_t iMinSAD,  
                                 const VECTOR * const pmv,  
                                 const int32_t min_dx,  
                                 const int32_t max_dx,  
                                 const int32_t min_dy,  
                                 const int32_t max_dy,  
                                 const int32_t iFcode,  
                                 const int32_t iQuant,  
                                 const int32_t iEdgedWidth)  
 {  
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
   
         int32_t iSAD;  
         VECTOR backupMV = *currMV;  
   
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y + 1);  
         CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y + 1);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y + 1);  
   
         return iMinSAD;  
853  }  }
854    
855    static __inline void
856  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)  PreparePredictionsP(VECTOR * const pmv, int x, int y, const int iWcount,
857                            const int iHcount, const MACROBLOCK * const prevMB)
 int32_t  
 PMVfastSearch8(const uint8_t * const pRef,  
                            const uint8_t * const pRefH,  
                            const uint8_t * const pRefV,  
                            const uint8_t * const pRefHV,  
                            const IMAGE * const pCur,  
                            const int x,  
                            const int y,  
                            const int start_x,  
                            const int start_y,  
                            const uint32_t MotionFlags,  
                            const uint32_t iQuant,  
                            const uint32_t iFcode,  
                            const MBParam * const pParam,  
                            const MACROBLOCK * const pMBs,  
                            const MACROBLOCK * const prevMBs,  
                            VECTOR * const currMV,  
                            VECTOR * const currPMV)  
858  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
   
         const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;  
   
         int32_t iDiamondSize;  
   
         int32_t min_dx;  
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
   
         VECTOR pmv[4];  
         int32_t psad[4];  
         VECTOR newMV;  
         VECTOR backupMV;  
         VECTOR startMV;  
   
 //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;  
         const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;  
   
          int32_t threshA, threshB;  
         int32_t iFound, bPredEq;  
         int32_t iMinSAD, iSAD;  
   
         int32_t iSubBlock = (y & 1) + (y & 1) + (x & 1);  
   
         MainSearch8FuncPtr MainSearchPtr;  
   
         /* Init variables */  
         startMV.x = start_x;  
         startMV.y = start_y;  
   
         /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,  
                           iFcode);  
   
         if (!(MotionFlags & PMV_HALFPELDIAMOND8)) {  
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
         }  
   
         /* because we might use IF (dx>max_dx) THEN dx=max_dx; */  
         //bPredEq = get_pmvdata(pMBs, (x >> 1), (y >> 1), iWcount, iSubBlock, pmv, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, (x >> 1), (y >> 1), iSubBlock, pmv, psad);  
   
         if ((x == 0) && (y == 0)) {  
                 threshA = 512 / 4;  
                 threshB = 1024 / 4;  
   
         } else {  
                 threshA = psad[0] / 4;  /* good estimate */  
                 threshB = threshA + 256 / 4;  
                 if (threshA < 512 / 4)  
                         threshA = 512 / 4;  
                 if (threshA > 1024 / 4)  
                         threshA = 1024 / 4;  
                 if (threshB > 1792 / 4)  
                         threshB = 1792 / 4;  
         }  
   
         iFound = 0;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
   
   
 // Prepare for main loop  
   
 //  if (MotionFlags & PMV_USESQUARES8)  
 //      MainSearchPtr = Square8_MainSearch;  
 //  else  
   
         if (MotionFlags & PMV_ADVANCEDDIAMOND8)  
                 MainSearchPtr = AdvDiamond8_MainSearch;  
         else  
                 MainSearchPtr = Diamond8_MainSearch;  
859    
860    //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself
861    
862          *currMV = startMV;          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          iMinSAD =          if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }// pmv[3] is left neighbour
868                  sad8(cur,          else pmv[3].x = pmv[3].y = 0;
                          get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  
                                                 iEdgedWidth), iEdgedWidth);  
         iMinSAD +=  
                 calc_delta_8(currMV->x - pmv[0].x, currMV->y - pmv[0].y,  
                                          (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256 / 4) || ((MVequal(*currMV, prevMB->mvs[iSubBlock]))  
                                                                 && ((int32_t) iMinSAD <  
                                                                         prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  
    vector of the median.  
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
   
         if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[iSubBlock])))  
                 iFound = 2;  
   
 /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.  
    Otherwise select large Diamond Search.  
 */  
   
         if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))  
                 iDiamondSize = 1;               // 1 halfpel!  
         else  
                 iDiamondSize = 2;               // 2 halfpel = 1 full pixel!  
869    
870          if (!(MotionFlags & PMV_HALFPELDIAMOND8))          if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }// [4] top neighbour
871                  iDiamondSize *= 2;      else pmv[4].x = pmv[4].y = 0;
872    
873            // [1] median prediction
874            pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
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
    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) */  
877    
878                  if (!(MVequal(pmv[0], backupMV))) {          pmv[2].x = EVEN(prevMB->mvs[0].x); // [2] is last frame
879                          iSAD =          pmv[2].y = EVEN(prevMB->mvs[0].y);
                                 (*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);  
880    
881                          if (iSAD < iMinSAD) {          if ((x != iWcount-1) && (y != iHcount-1)) {
882                                  *currMV = newMV;                  pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); //[6] right-down neighbour in last frame
883                                  iMinSAD = iSAD;                  pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
884                          }          } else pmv[6].x = pmv[6].y = 0;
                 }  
   
                 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;  
                         }  
                 }  
885          }          }
886    
887  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.  static void
888     By performing an optional local half-pixel search, we can refine this result even further.  SearchP(const IMAGE * const pRef,
 */  
   
   PMVfast8_Terminate_with_Refine:  
         if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step  
                 iMinSAD =  
                         Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                         iMinSAD, pmv, min_dx, max_dx, min_dy, max_dy,  
                                                         iFcode, iQuant, iEdgedWidth);  
   
   
   PMVfast8_Terminate_without_Refine:  
         currPMV->x = currMV->x - pmv[0].x;  
         currPMV->y = currMV->y - pmv[0].y;  
   
         return iMinSAD;  
 }  
   
 int32_t  
 EPZSSearch16(const uint8_t * 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;  
   
         int32_t min_dx;  
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
   
         VECTOR newMV;  
         VECTOR backupMV;  
904    
905          VECTOR pmv[4];          int i, iDirection = 255, mask, threshA;
906          int32_t psad[8];          VECTOR pmv[7];
907    
908          static MACROBLOCK *oldMBs = NULL;          get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);  //has to be changed to get_pmv(2)()
909            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
910  //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;                                  pParam->width, pParam->height, Data->iFcode, pParam->m_quarterpel);
911          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;  
912          MACROBLOCK *oldMB = NULL;          Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16;
913            Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8;
914           int32_t thresh2;          Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8;
915          int32_t bPredEq;  
916          int32_t iMinSAD, iSAD = 9999;          Data->Ref = pRef->y + (x + Data->iEdgedWidth*y) * 16;
917            Data->RefH = pRefH + (x + Data->iEdgedWidth*y) * 16;
918          MainSearch16FuncPtr MainSearchPtr;          Data->RefV = pRefV + (x + Data->iEdgedWidth*y) * 16;
919            Data->RefHV = pRefHV + (x + Data->iEdgedWidth*y) * 16;
920          if (oldMBs == NULL) {          Data->RefCV = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8;
921                  oldMBs = (MACROBLOCK *) calloc(iWcount * iHcount, sizeof(MACROBLOCK));          Data->RefCU = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8;
922  //      fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));  
923          }          Data->lambda16 = lambda_vec16[iQuant];
924          oldMB = oldMBs + x + y * iWcount;          Data->lambda8 = lambda_vec8[iQuant];
925            Data->qpel_precision = 0;
 /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
926    
927          if (!(MotionFlags & PMV_HALFPEL16)) {          if (!(MotionFlags & PMV_HALFPEL16)) {
928                  min_dx = EVEN(min_dx);                  Data->min_dx = EVEN(Data->min_dx);
929                  max_dx = EVEN(max_dx);                  Data->max_dx = EVEN(Data->max_dx);
930                  min_dy = EVEN(min_dy);                  Data->min_dy = EVEN(Data->min_dy);
931                  max_dy = EVEN(max_dy);                  Data->max_dy = EVEN(Data->max_dy); }
932          }  
933          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */          if (pMB->dquant != NO_CHANGE) inter4v = 0;
934          //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  
935          bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);          for(i = 0;  i < 5; i++)
936                    Data->currentMV[i].x = Data->currentMV[i].y = 0;
937  /* Step 4: Calculate SAD around the Median prediction.  
938          MinSAD=SAD          if (pParam->m_quarterpel) Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
939          If Motion Vector equal to Previous frame motion vector          else Data->predMV = pmv[0];
940                  and MinSAD<PrevFrmSAD goto Step 10.  
941          If SAD<=256 goto Step 10.          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  // Prepare for main loop          if ((x == 0) && (y == 0)) threshA = 512;
949            else {
950          *currMV = pmv[0];                       /* current best := median prediction */                  threshA = Data->temp[0]; // that's when we keep this SAD atm
951          if (!(MotionFlags & PMV_HALFPEL16)) {                  if (threshA < 512) threshA = 512;
952                  currMV->x = EVEN(currMV->x);                  if (threshA > 1024) threshA = 1024; }
                 currMV->y = EVEN(currMV->y);  
         }  
   
         if (currMV->x > max_dx)  
                 currMV->x = max_dx;  
         if (currMV->x < min_dx)  
                 currMV->x = min_dx;  
         if (currMV->y > max_dy)  
                 currMV->y = max_dy;  
         if (currMV->y < min_dy)  
                 currMV->y = min_dy;  
   
 /***************** 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 **************/  
953    
954  // previous frame MV          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
955          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);                                          prevMBs + x + y * pParam->mb_width);
956    
957  // set threshhold based on Min of Prediction and SAD of collocated block          if (inter4v || Data->chroma) CheckCandidate = CheckCandidate16;
958  // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want          else CheckCandidate = CheckCandidate16no4v; //for extra speed
959    
960          if ((x == 0) && (y == 0)) {  /* main loop. checking all predictions */
                 thresh2 = 512;  
         } else {  
 /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */  
961    
962                  thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;          for (i = 1; i < 7; i++) {
963                    if (!(mask = make_mask(pmv, i)) ) continue;
964                    (*CheckCandidate)(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
965                    if (Data->iMinSAD[0] <= threshA) break;
966          }          }
967    
968  // MV=(0,0) is often a good choice          if ((Data->iMinSAD[0] <= threshA) ||
969                            (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
970                            (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16))) {
971                    inter4v = 0;
972            } else {
973    
974          CHECK_MV16_ZERO;                  MainSearchFunc * MainSearchPtr;
975                    if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
976                    else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
977                            else MainSearchPtr = DiamondSearch;
978    
979                    (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
980    
981    /* extended search, diamond starting in 0,0 and in prediction.
982            note that this search is/might be done in halfpel positions,
983            which makes it more different than the diamond above */
984    
985                    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  // left neighbour, if allowed                                  (*CheckCandidate)(startMV.x, startMV.y, 255, &iDirection, Data);
994          if (x != 0) {                                  (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
995                  if (!(MotionFlags & PMV_HALFPEL16)) {                                  if (bSAD < Data->iMinSAD[0]) {
996                          pmv[1].x = EVEN(pmv[1].x);                                          Data->currentMV[0] = backupMV;
997                          pmv[1].y = EVEN(pmv[1].y);                                          Data->iMinSAD[0] = bSAD; }
                 }  
                 CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
         }  
 // top neighbour, if allowed  
         if (y != 0) {  
                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                         pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
998                  }                  }
                 CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
999    
1000  // top right neighbour, if allowed                          backupMV = Data->currentMV[0];
1001                  if ((uint32_t) x != (iWcount - 1)) {                          if (MotionFlags & PMV_HALFPELREFINE16) startMV.x = startMV.y = 1;
1002                          if (!(MotionFlags & PMV_HALFPEL16)) {                          else startMV.x = startMV.y = 0;
1003                                  pmv[3].x = EVEN(pmv[3].x);                          if (!(MVequal(startMV, backupMV))) {
1004                                  pmv[3].y = EVEN(pmv[3].y);                                  bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1005    
1006                                    (*CheckCandidate)(startMV.x, startMV.y, 255, &iDirection, Data);
1007                                    (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
1008                                    if (bSAD < Data->iMinSAD[0]) {
1009                                            Data->currentMV[0] = backupMV;
1010                                            Data->iMinSAD[0] = bSAD; }
1011                          }                          }
                         CHECK_MV16_CANDIDATE(pmv[3].x, pmv[3].y);  
1012                  }                  }
1013          }          }
1014    
1015  /* Terminate if MinSAD <= T_2          if (MotionFlags & PMV_HALFPELREFINE16) SubpelRefine(Data);
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
1016    
1017          if ((iMinSAD <= thresh2)          for(i = 0; i < 5; i++) {
1018                  || (MVequal(*currMV, prevMB->mvs[0]) &&                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // initialize qpel vectors
1019                          ((int32_t) iMinSAD <= prevMB->sad16))) {                  Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
1020          }          }
1021    
1022  /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/          if((pParam->m_quarterpel) && (MotionFlags & PMV_QUARTERPELREFINE16)) {
1023    
1024          backupMV = prevMB->mvs[0];      // collocated MV                  Data->qpel_precision = 1;
1025          backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x);     // acceleration X                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1026          backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y);     // acceleration Y                                  pParam->width, pParam->height, Data->iFcode, 0);
1027    
1028          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y);                  SubpelRefine(Data);
1029            }
1030    
1031  // left neighbour          if (Data->iMinSAD[0] < (int32_t)iQuant * 30 ) inter4v = 0;
1032          if (x != 0)          if (inter4v) {
1033                  CHECK_MV16_CANDIDATE((prevMB - 1)->mvs[0].x, (prevMB - 1)->mvs[0].y);                  SearchData Data8;
1034                    Data8.iFcode = Data->iFcode;
1035                    Data8.lambda8 = Data->lambda8;
1036                    Data8.iEdgedWidth = Data->iEdgedWidth;
1037                    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  // top neighbour                  if (Data->chroma) {
1045          if (y != 0)                          int sumx, sumy, dx, dy;
1046                  CHECK_MV16_CANDIDATE((prevMB - iWcount)->mvs[0].x,  
1047                                                           (prevMB - iWcount)->mvs[0].y);                          if(pParam->m_quarterpel) {
1048                                    sumx= pMB->qmvs[0].x/2 + pMB->qmvs[1].x/2 + pMB->qmvs[2].x/2 + pMB->qmvs[3].x/2;
1049                                    sumy = pMB->qmvs[0].y/2 + pMB->qmvs[1].y/2 + pMB->qmvs[2].y/2 + pMB->qmvs[3].y/2;
1050                            } else {
1051                                    sumx = pMB->mvs[0].x + pMB->mvs[1].x + pMB->mvs[2].x + pMB->mvs[3].x;
1052                                    sumy = pMB->mvs[0].y + pMB->mvs[1].y + pMB->mvs[2].y + pMB->mvs[3].y;
1053                            }
1054                            dx = (sumx >> 3) + roundtab_76[sumx & 0xf];
1055                            dy = (sumy >> 3) + roundtab_76[sumy & 0xf];
1056    
1057  // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs                          Data->iMinSAD[1] += ChromaSAD(dx, dy, Data);
1058                    }
1059            }
1060    
1061          if ((uint32_t) x != iWcount - 1)          if (!(inter4v) ||
1062                  CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);                  (Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
1063                            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  // bottom neighbour, dito                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
1070          if ((uint32_t) y != iHcount - 1)                          pMB->sad8[2] = pMB->sad8[3] =  Data->iMinSAD[0];
                 CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,  
                                                          (prevMB + iWcount)->mvs[0].y);  
1071    
1072  /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */                  if(pParam->m_quarterpel) {
1073          if (iMinSAD <= thresh2) {                          pMB->qmvs[0] = pMB->qmvs[1]
1074                  if (MotionFlags & PMV_QUICKSTOP16)                                  = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1075                          goto EPZS16_Terminate_without_Refine;                          pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1076                  if (MotionFlags & PMV_EARLYSTOP16)                          pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;
1077                          goto EPZS16_Terminate_with_Refine;                  } 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  /************ (if Diamond Search)  **************/  static void
1090    Search8(const SearchData * const OldData,
1091                    const int x, const int y,
1092                    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          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                  if (MotionFlags & PMV_EXTSEARCH8) {
1132                            int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
1133    
1134          if (MotionFlags & PMV_USESQUARES16)                          MainSearchFunc *MainSearchPtr;
1135                  MainSearchPtr = Square16_MainSearch;                          if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
1136          else                                  else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1137           if (MotionFlags & PMV_ADVANCEDDIAMOND16)                                          else MainSearchPtr = DiamondSearch;
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
1138    
1139  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);
1140    
1141          iSAD =                          if(*(Data->iMinSAD) < temp_sad) {
1142                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,                                          Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1143                                                    currMV->y, iMinSAD, &newMV, pmv, min_dx, max_dx,                                          Data->currentQMV->y = 2 * Data->currentMV->y;
1144                                                    min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);                          }
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
1145          }          }
1146    
1147                    if (MotionFlags & PMV_HALFPELREFINE8) {
1148                            int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
1149    
1150          if (MotionFlags & PMV_EXTSEARCH16) {                          SubpelRefine(Data); // perform halfpel refine of current best vector
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
1151    
1152                  if (!(MVequal(pmv[0], backupMV))) {                          if(*(Data->iMinSAD) < temp_sad) { // we have found a better match
1153                          iSAD =                                  Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1154                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                  Data->currentQMV->y = 2 * Data->currentMV->y;
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, pmv,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   2, iFcode, iQuant, 0);  
1155                  }                  }
   
                 if (iSAD < iMinSAD) {  
                         *currMV = newMV;  
                         iMinSAD = iSAD;  
1156                  }                  }
1157    
1158                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                  if(pParam->m_quarterpel) {
1159                          iSAD =                          if((!(Data->currentQMV->x & 1)) && (!(Data->currentQMV->y & 1)) &&
1160                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                                  (MotionFlags & PMV_QUARTERPELREFINE8)) {
1161                                                                    iMinSAD, &newMV, pmv, min_dx, max_dx, min_dy,                          Data->qpel_precision = 1;
1162                                                                    max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);                          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1163                                    pParam->width, pParam->height, OldData->iFcode, 0);
1164                            SubpelRefine(Data);
1165                            }
1166                    }
1167            }
1168    
1169                          if (iSAD < iMinSAD) {          if(pParam->m_quarterpel) {
1170                                  *currMV = newMV;                  pMB->pmvs[block].x = Data->currentQMV->x - Data->predMV.x;
1171                                  iMinSAD = iSAD;                  pMB->pmvs[block].y = Data->currentQMV->y - Data->predMV.y;
1172                    pMB->qmvs[block] = *(Data->currentQMV);
1173                          }                          }
1174            else {
1175                    pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1176                    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    /* B-frames code starts here */
1184    
1185    static __inline VECTOR
1186    ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1187    {
1188    /* the stupidiest function ever */
1189            if (mode == MODE_FORWARD) return pMB->mvs[0];
1190            else return pMB->b_mvs[0];
1191          }          }
1192    
1193  /***************        Choose best MV found     **************/  static void __inline
1194    PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
1195                                                            const uint32_t iWcount,
1196                                                            const MACROBLOCK * const pMB,
1197                                                            const uint32_t mode_curr)
1198    {
1199    
1200            // [0] is prediction
1201            pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
1202    
1203    EPZS16_Terminate_with_Refine:          pmv[1].x = pmv[1].y = 0; // [1] is zero
         if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step  
                 iMinSAD =  
                         Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                          iMinSAD, pmv, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
1204    
1205    EPZS16_Terminate_without_Refine:          pmv[2] = ChoosePred(pMB, mode_curr);
1206            pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
1207    
1208          *oldMB = *prevMB;          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          currPMV->x = currMV->x - pmv[0].x;          if (y != 0) {
1214          currPMV->y = currMV->y - pmv[0].y;                  pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
1215          return iMinSAD;                  pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
1216            } else pmv[4].x = pmv[4].y = 0;
1217    
1218            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            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    // more?
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            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 iDiamondSize = 1;          if (MotionFlags & PMV_USESQUARES16)
1283                    MainSearchPtr = SquareSearch;
1284            else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
1285                    MainSearchPtr = AdvDiamondSearch;
1286                    else MainSearchPtr = DiamondSearch;
1287    
1288          int32_t min_dx;          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
1289    
1290          VECTOR newMV;          SubpelRefine(Data);
         VECTOR backupMV;  
1291    
1292          VECTOR pmv[4];          if (Data->qpel) {
1293          int32_t psad[8];                  Data->currentQMV->x = 2*Data->currentMV->x;
1294                    Data->currentQMV->y = 2*Data->currentMV->y;
1295                    Data->qpel_precision = 1;
1296                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1297                                            pParam->width, pParam->height, iFcode, 0);
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 int32_t iSubBlock = ((y & 1) << 1) + (x & 1);          }
1326    
1327  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;  }
         const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;  
1328    
1329          int32_t bPredEq;  static int32_t
1330          int32_t iMinSAD, iSAD = 9999;  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          MainSearch8FuncPtr MainSearchPtr;          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          iMinSAD =          skip_sad = *Data->iMinSAD;
                 sad8(cur,  
                          get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  
                                                 iEdgedWidth), iEdgedWidth);  
         iMinSAD +=  
                 calc_delta_8(currMV->x - pmv[0].x, currMV->y - pmv[0].y,  
                                          (uint8_t) iFcode, iQuant);  
1451    
1452    //  DIRECT MODE DELTA VECTOR SEARCH.
1453    //      This has to be made more effective, but at the moment I'm happy it's running at all
1454    
1455  // thresh1 is fixed to 256          if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1456          if (iMinSAD < 256 / 4) {                  else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1457                  if (MotionFlags & PMV_QUICKSTOP8)                          else MainSearchPtr = DiamondSearch;
                         goto EPZS8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
         }  
1458    
1459  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/          (*MainSearchPtr)(0, 0, Data, 255);
1460    
1461            SubpelRefine(Data);
1462    
1463  // MV=(0,0) is often a good choice  //      *Data->iMinSAD +=  1 * Data->lambda16; // one bit is needed to code direct mode
1464          CHECK_MV8_ZERO;          *best_sad = *Data->iMinSAD;
1465    
1466  // previous frame MV          if (b_mb->mode == MODE_INTER4V)
1467          CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x, prevMB->mvs[iSubBlock].y);                  pMB->mode = MODE_DIRECT;
1468            else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation
1469    
1470  // left neighbour, if allowed          pMB->pmvs[3] = *Data->currentMV;
         if (psad[1] != MV_MAX_ERROR) {  
                 if (!(MotionFlags & PMV_HALFPEL8)) {  
                         pmv[1].x = EVEN(pmv[1].x);  
                         pmv[1].y = EVEN(pmv[1].y);  
                 }  
                 CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);  
         }  
 // top neighbour, if allowed  
         if (psad[2] != MV_MAX_ERROR) {  
                 if (!(MotionFlags & PMV_HALFPEL8)) {  
                         pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
                 }  
                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
1471    
1472  // top right neighbour, if allowed          for (k = 0; k < 4; k++) {
1473                  if (psad[3] != 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[3].x = EVEN(pmv[3].x);                                                          ? Data->directmvB[k].x
1476                                  pmv[3].y = EVEN(pmv[3].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                    }
1487    
1488                    if (b_mb->mode != MODE_INTER4V) {
1489                            pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1490                            pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1491                            pMB->qmvs[3] = pMB->qmvs[2] = pMB->qmvs[1] = pMB->qmvs[0];
1492                            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                                    const uint8_t * const f_RefH,
1503                                    const uint8_t * const f_RefV,
1504                                    const uint8_t * const f_RefHV,
1505                                    const uint8_t * const b_Ref,
1506                                    const uint8_t * const b_RefH,
1507                                    const uint8_t * const b_RefV,
1508                                    const uint8_t * const b_RefHV,
1509                                    const IMAGE * const pCur,
1510                                    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  /* Terminate if MinSAD <= T_2  {
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
1522    
1523          if (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */          const int32_t iEdgedWidth = pParam->edged_width;
1524                  if (MotionFlags & PMV_QUICKSTOP8)          int iDirection, i, j;
1525                          goto EPZS8_Terminate_without_Refine;          SearchData bData;
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
         }  
1526    
1527  /************ (Diamond Search)  **************/          *(bData.iMinSAD = fData->iMinSAD) = 4096*256;
1528            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          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, 255, &iDirection, fData);
1564    
1565          if (!(MotionFlags & PMV_HALFPELDIAMOND8))  //diamond. I wish we could use normal mainsearch functions (square, advdiamond)
                 iDiamondSize *= 2;  
1566    
1567  /* default: use best prediction as starting point for one call of EPZS_MainSearch */          do {
1568                    iDirection = 255;
1569                    // 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(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode, 0);
1591                    get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode, 0);
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  // there is no EPZS^2 for inter4v at the moment  void
1625    MotionEstimationBVOP(MBParam * const pParam,
1626                                             FRAMEINFO * const frame,
1627                                             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  //  if (MotionFlags & PMV_USESQUARES8)          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
 //      MainSearchPtr = Square8_MainSearch;  
 //  else  
1649    
1650          if (MotionFlags & PMV_ADVANCEDDIAMOND8)          const int32_t TRB = time_pp - time_bp;
1651                  MainSearchPtr = AdvDiamond8_MainSearch;          const int32_t TRD = time_pp;
1652          else          uint8_t * qimage;
1653                  MainSearchPtr = Diamond8_MainSearch;  
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                            // backward search
1716                            SearchBF(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
1717                                                    &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                          if (iSAD < iMinSAD) {                          switch (pMB->mode) {
1737                                  *currMV = newMV;                                  case MODE_FORWARD:
1738                                  iMinSAD = iSAD;                                          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  /***************        Choose best MV found     **************/          free(qimage);
   
   EPZS8_Terminate_with_Refine:  
         if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step  
                 iMinSAD =  
                         Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                         iMinSAD, pmv, min_dx, max_dx, min_dy, max_dy,  
                                                         iFcode, iQuant, iEdgedWidth);  
   
   EPZS8_Terminate_without_Refine:  
   
         currPMV->x = currMV->x - pmv[0].x;  
         currPMV->y = currMV->y - pmv[0].y;  
         return iMinSAD;  
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          int32_t iFound;          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          VECTOR newMV;          if (!(MotionFlags & PMV_HALFPEL16)) {
1806          VECTOR backupMV;                        /* just for PMVFAST */                  Data->min_dx = EVEN(Data->min_dx);
1807                    Data->max_dx = EVEN(Data->max_dx);
1808                    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(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1855                                    pParam->width, pParam->height, Data->iFcode, 0);
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_iref_mv(pRef, 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                  if (MotionFlags & PMV_EARLYSTOP16)  static __inline int
1987                          goto PMVfastInt16_Terminate_with_Refine;  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            //median is only used as prediction. it doesn't have to be real
2002            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;
         backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  
2076    
2077    
2078  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          InterThresh += 400 * (1 - bCount);
2079          iSAD =          if (InterThresh < 200) InterThresh = 200;
                 (*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);  
2080    
2081          if (iSAD < iMinSAD) {          if (sadInit) (*sadInit) ();
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
2082    
2083          if (MotionFlags & PMV_EXTSEARCH16) {          for (y = 1; y < pParam->mb_height-1; y++) {
2084  /* extended: search (up to) two more times: orignal prediction and (0,0) */                  for (x = 1; x < pParam->mb_width-1; x++) {
2085                            int sad, dev;
2086                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
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,  
                                          const int32_t time_bp,  
                                          const int32_t time_pp,  
                                          // forward (past) reference  
                                          const MACROBLOCK * const f_mbs,  
                                          const IMAGE * const f_ref,  
                                          const IMAGE * const f_refH,  
                                          const IMAGE * const f_refV,  
                                          const IMAGE * const f_refHV,  
                                          // backward (future) reference  
                                          const MACROBLOCK * const b_mbs,  
                                          const IMAGE * const b_ref,  
                                          const IMAGE * const b_refH,  
                                          const IMAGE * const b_refV,  
                                          const IMAGE * const b_refHV)  
2166  {  {
         const int mb_width = pParam->mb_width;  
         const int mb_height = pParam->mb_height;  
         const int edged_width = pParam->edged_width;  
2167    
2168          int i, j, k;          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          static const VECTOR zeroMV={0,0};          min_x = min_y = -32<<iFcode;
2176            max_x = max_y = 32<<iFcode;
2177    
2178          int f_sad16;    /* forward (as usual) search */  //step1: let's find a rough camera panning
2179          int b_sad16;    /* backward (only in b-frames) search */          for (step = 32; step >= 2; step /= 2) {
2180          int i_sad16;    /* interpolated (both direction, b-frames only) */                  bestcount = 0;
2181          int d_sad16;    /* direct mode (assume linear motion) */                  for (y = min_y; y <= max_y; y += step)
2182                            for (x = min_x ; x <= max_x; x += step) {
2183          int best_sad;                                  count = 0;
2184                                    //for all macroblocks
2185          VECTOR pmv_dontcare;                                  for (my = 1; my < pParam->mb_height-1; my++)
2186                                            for (mx = 1; mx < pParam->mb_width-1; mx++) {
2187          int f_count=0;                                                  const MACROBLOCK *pMB = &pMBs[mx + my * pParam->mb_width];
2188          int b_count=0;                                                  VECTOR mv;
         int i_count=0;  
         int d_count=0;  
         int dnv_count=0;  
         int s_count=0;  
         const int64_t TRB = (int32_t)time_pp - (int32_t)time_bp;  
         const int64_t TRD = (int32_t)time_pp;  
2189    
2190          fprintf(stderr,"TRB = %lld  TRD = %lld  time_bp =%d time_pp =%d\n\n",TRB,TRD,time_bp,time_pp);                                                  if (pMB->mode == MODE_INTRA || pMB->mode == MODE_NOT_CODED)
         // note: i==horizontal, j==vertical  
         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];  
   
                         VECTOR directMV;  
                         VECTOR deltaMV=zeroMV;  
   
 /* special case, if collocated block is SKIPed: encoding is forward(0,0)  */  
   
                         if (b_mb->mode == MODE_INTER && b_mb->cbp == 0 &&  
                                 b_mb->mvs[0].x == 0 && b_mb->mvs[0].y == 0) {  
                                 mb->mode = MODE_NOT_CODED;  
                                 mb->mvs[0].x = 0;  
                                 mb->mvs[0].y = 0;  
                                 mb->b_mvs[0].x = 0;  
                                 mb->b_mvs[0].y = 0;  
2191                                  continue;                                  continue;
                         }  
   
                         /* same method of scaling as in decoder.c, so we copy 1:1 from there */  
   
             for (k = 0; k < 4; k++) {  
                                 directMV = b_mb->mvs[k];  
   
                                 mb->mvs[k].x = (int32_t) ((TRB * directMV.x) / TRD + deltaMV.x);  
                 mb->b_mvs[k].x = (int32_t) ((deltaMV.x == 0)  
                                                                         ? ((TRB - TRD) * directMV.x) / TRD  
                                     : mb->mvs[k].x - directMV.x);  
                 mb->mvs[k].y = (int32_t) ((TRB * directMV.y) / TRD + deltaMV.y);  
                 mb->b_mvs[k].y = (int32_t) ((deltaMV.y == 0)  
                                                                         ? ((TRB - TRD) * directMV.y) / TRD  
                                     : mb->mvs[k].y - directMV.y);  
             }  
   
                         d_sad16 =  
                                 sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 i, j, 16, &mb->mvs[0], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 i, j, 16, &mb->b_mvs[0], edged_width),  
                                                   edged_width);  
   
                         // forward search  
                         f_sad16 = 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 (why?)  
2192    
2193                                                    mv = pMB->mvs[0];
2194                          // backward search                                                  if ( ABS(mv.x - x) <= step && ABS(mv.y - y) <= step )   /* GMC translation is always halfpel-res */
2195                          b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,                                                          count++;
                                                 &frame->image, i, j, frame->motion_flags,  
                                                 frame->quant, frame->bcode, pParam,  
                                                 b_mbs, b_mbs,   /* todo */  
                                                 &mb->b_mvs[0], &pmv_dontcare);  // ignore pmv  
   
                         i_sad16 =  
                                 sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 i, j, 16, &mb->mvs[0], edged_width),  
                                                   get_ref(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 i, j, 16, -mb->b_mvs[0].x, -mb->b_mvs[0].y, edged_width),  
                                                   edged_width);  
   
                         // TODO: direct search  
                         // predictor + range of [-32,32]  
   
                         DEBUG2("f_MV: ",mb->mvs[0].x,mb->mvs[0].y);  
                         DEBUG2("b_MV: ",mb->b_mvs[0].x,mb->b_mvs[0].y);  
   
 /*                      fprintf(stderr,"f_sad16 = %d, b_sad16 = %d, i_sad16 = %d, d_sad16 = %d\n",  
                                 f_sad16,b_sad16,i_sad16,d_sad16);  
 */  
   
 //                      d_sad16 -= 50;  
 //                      d_sad16 = 65535;  
 //                      i_sad16 = 65535;  
 //                      b_sad16 = 65535;  
   
                         if (f_sad16 < b_sad16) {  
                                 best_sad = f_sad16;  
                                 mb->mode = MODE_FORWARD;  
                         } else {  
                                 best_sad = b_sad16;  
                                 mb->mode = MODE_BACKWARD;  
2196                          }                          }
2197                                    if (count >= bestcount) { bestcount = count; gmc.x = x; gmc.y = y; }
                         if (i_sad16 < best_sad) {  
                                 best_sad = i_sad16;  
                                 mb->mode = MODE_INTERPOLATE;  
2198                          }                          }
2199                    min_x = gmc.x - step;
2200                    max_x = gmc.x + step;
2201                    min_y = gmc.y - step;
2202                    max_y = gmc.y + step;
2203    
                         if (d_sad16 < best_sad) {  
                                 best_sad = d_sad16;  
                                 mb->mode = MODE_DIRECT_NONE_MV;  
2204                          }                          }
2205    
2206                          switch (mb->mode)          if (bestcount < (pParam->mb_height-2)*(pParam->mb_width-2)/10)
2207                          {                  gmc.x = gmc.y = 0; //no camara pan, no GMC
                                 case MODE_FORWARD:  
                                         f_count++; break;  
                                 case MODE_BACKWARD:  
                                         b_count++; break;  
                                 case MODE_INTERPOLATE:  
                                         i_count++; break;  
                                 case MODE_DIRECT:  
                                         d_count++; break;  
                                 case MODE_DIRECT_NONE_MV:  
                                         dnv_count++; break;  
                                 default:  
                                         s_count++; break;  
                         }  
2208    
2209                  }  // step2: let's refine camera panning using gradiend-descent approach.
2210          }  // TODO: more warping points may be evaluated here (like in interpolate mode search - two vectors in one diamond)
2211            bestcount = 0;
2212            CheckGMC(gmc.x, gmc.y, 255, &iDirection, pMBs, &bestcount, &gmc, pParam);
2213            do {
2214                    x = gmc.x; y = gmc.y;
2215                    bDirection = iDirection; iDirection = 0;
2216                    if (bDirection & 1) CheckGMC(x - 1, y, 1+4+8, &iDirection, pMBs, &bestcount, &gmc, pParam);
2217                    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);
2220    
2221  #ifdef _DEBUG_BFRAME_STAT          } while (iDirection);
2222          fprintf(stderr,"B-Stat: F: %04d   B: %04d   I: %04d  D0: %04d   D: %04d   S: %04d\n",  
2223                                  f_count,b_count,i_count,dnv_count,d_count,s_count);          if (pParam->m_quarterpel) {
2224  #endif                  gmc.x *= 2;
2225                    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.317  
changed lines
  Added in v.698

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