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

Diff of /branches/dev-api-4/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 96, Mon Apr 1 22:47:58 2002 UTC branches/dev-api-4/xvidcore/src/motion/motion_est.c revision 1135, Fri Aug 29 13:47:21 2003 UTC
# Line 1  Line 1 
1  /**************************************************************************  /*****************************************************************************
2   *   *
3   *  Modifications:   *  XVID MPEG-4 VIDEO CODEC
4     *  - Motion Estimation related code  -
5   *   *
6   *  02.04.2002 add EPZS(^2) as ME algorithm, use PMV_USESQUARES to choose between   *  Copyright(C) 2002 Christoph Lampert <gruel@web.de>
7   *             EPZS and EPZS^2   *               2002 Michael Militzer <michael@xvid.org>
8   *  08.02.2002 split up PMVfast into three routines: PMVFast, PMVFast_MainLoop   *               2002-2003 Radoslaw Czyz <xvid@syskin.cjb.net>
  *             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.  
9   *   *
10   *  Michael Militzer <isibaar@videocoding.de>   *  This program is free software ; you can redistribute it and/or modify
11     *  it under the terms of the GNU General Public License as published by
12     *  the Free Software Foundation ; either version 2 of the License, or
13     *  (at your option) any later version.
14   *   *
15   **************************************************************************/   *  This program is distributed in the hope that it will be useful,
16     *  but WITHOUT ANY WARRANTY ; without even the implied warranty of
17     *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18     *  GNU General Public License for more details.
19     *
20     *  You should have received a copy of the GNU General Public License
21     *  along with this program ; if not, write to the Free Software
22     *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
23     *
24     * $Id: motion_est.c,v 1.58.2.32 2003-08-29 13:47:21 syskin Exp $
25     *
26     ****************************************************************************/
27    
28  #include <assert.h>  #include <assert.h>
29  #include <stdio.h>  #include <stdio.h>
30  #include <stdlib.h>  #include <stdlib.h>
31    #include <string.h>     /* memcpy */
32    #include <math.h>       /* lrint */
33    
34  #include "../encoder.h"  #include "../encoder.h"
35  #include "../utils/mbfunctions.h"  #include "../utils/mbfunctions.h"
36  #include "../prediction/mbprediction.h"  #include "../prediction/mbprediction.h"
37  #include "../global.h"  #include "../global.h"
38  #include "../utils/timer.h"  #include "../utils/timer.h"
39    #include "../image/interpolate8x8.h"
40    #include "motion_est.h"
41    #include "motion.h"
42  #include "sad.h"  #include "sad.h"
43    #include "gmc.h"
44    #include "../utils/emms.h"
45    #include "../dct/fdct.h"
46    
47    /*****************************************************************************
48     * Modified rounding tables -- declared in motion.h
49     * Original tables see ISO spec tables 7-6 -> 7-9
50     ****************************************************************************/
51    
52    const uint32_t roundtab[16] =
53    {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2 };
54    
55    /* K = 4 */
56    const uint32_t roundtab_76[16] =
57    { 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1 };
58    
59    /* K = 2 */
60    const uint32_t roundtab_78[8] =
61    { 0, 0, 1, 1, 0, 0, 0, 1  };
62    
63    /* K = 1 */
64    const uint32_t roundtab_79[4] =
65    { 0, 1, 0, 0 };
66    
67    #define INITIAL_SKIP_THRESH     (10)
68    #define FINAL_SKIP_THRESH       (50)
69    #define MAX_SAD00_FOR_SKIP      (20)
70    #define MAX_CHROMA_SAD_FOR_SKIP (22)
71    
72    #define CHECK_CANDIDATE(X,Y,D) { \
73    CheckCandidate((X),(Y), data, (D) ); }
74    
75    
76    /*****************************************************************************
77     * Code
78     ****************************************************************************/
79    
80    static __inline uint32_t
81    d_mv_bits(int x, int y, const VECTOR pred, const uint32_t iFcode, const int qpel, const int rrv)
82    {
83            int bits;
84            const int q = (1 << (iFcode - 1)) - 1;
85    
86            x <<= qpel;
87            y <<= qpel;
88            if (rrv) { x = RRV_MV_SCALEDOWN(x); y = RRV_MV_SCALEDOWN(y); }
89    
90            x -= pred.x;
91            bits = (x != 0 ? iFcode:0);
92            x = abs(x);
93            x += q;
94            x >>= (iFcode - 1);
95            bits += mvtab[x];
96    
97            y -= pred.y;
98            bits += (y != 0 ? iFcode:0);
99            y = abs(y);
100            y += q;
101            y >>= (iFcode - 1);
102            bits += mvtab[y];
103    
104            return bits;
105    }
106    
107    static int32_t ChromaSAD2(const int fx, const int fy, const int bx, const int by,
108                                                            const SearchData * const data)
109    {
110            int sad;
111            const uint32_t stride = data->iEdgedWidth/2;
112            uint8_t *f_refu, *f_refv, *b_refu, *b_refv;
113    
114            const INTERPOLATE8X8_PTR interpolate8x8_halfpel[] = {
115                    NULL,
116                    interpolate8x8_halfpel_v,
117                    interpolate8x8_halfpel_h,
118                    interpolate8x8_halfpel_hv
119            };
120    
121  // very large value          int offset = (fx>>1) + (fy>>1)*stride;
122  #define MV_MAX_ERROR    (4096 * 256)          int filter = ((fx & 1) << 1) | (fy & 1);
123    
124  // stop search if sdelta < THRESHOLD          if (filter != 0) {
125  #define MV16_THRESHOLD  192                  f_refu = data->RefQ;
126  #define MV8_THRESHOLD   56                  f_refv = data->RefQ + 8;
127                    interpolate8x8_halfpel[filter](f_refu, data->RefP[4] + offset, stride, data->rounding);
128                    interpolate8x8_halfpel[filter](f_refv, data->RefP[5] + offset, stride, data->rounding);
129            } else {
130                    f_refu = (uint8_t*)data->RefP[4] + offset;
131                    f_refv = (uint8_t*)data->RefP[5] + offset;
132            }
133    
134  /* sad16(0,0) bias; mpeg4 spec suggests nb/2+1 */          offset = (bx>>1) + (by>>1)*stride;
135  /* nb  = vop pixels * 2^(bpp-8) */          filter = ((bx & 1) << 1) | (by & 1);
 #define MV16_00_BIAS    (128+1)  
136    
137  /* INTER bias for INTER/INTRA decision; mpeg4 spec suggests 2*nb */          if (filter != 0) {
138  #define INTER_BIAS      512                  b_refu = data->RefQ + 16;
139                    b_refv = data->RefQ + 24;
140                    interpolate8x8_halfpel[filter](b_refu, data->b_RefP[4] + offset, stride, data->rounding);
141                    interpolate8x8_halfpel[filter](b_refv, data->b_RefP[5] + offset, stride, data->rounding);
142            } else {
143                    b_refu = (uint8_t*)data->b_RefP[4] + offset;
144                    b_refv = (uint8_t*)data->b_RefP[5] + offset;
145            }
146    
147  /* Parameters which control inter/inter4v decision */          sad = sad8bi(data->CurU, b_refu, f_refu, stride);
148  #define IMV16X16                        5          sad += sad8bi(data->CurV, b_refv, f_refv, stride);
149    
150  /* vector map (vlc delta size) smoother parameters */          return sad;
151  #define NEIGH_TEND_16X16        2  }
 #define NEIGH_TEND_8X8          2  
152    
153    static int32_t
154    ChromaSAD(const int dx, const int dy, const SearchData * const data)
155    {
156            int sad;
157            const uint32_t stride = data->iEdgedWidth/2;
158            int offset = (dx>>1) + (dy>>1)*stride;
159            int next = 1;
160    
161  // fast ((A)/2)*2          if (dx == data->temp[5] && dy == data->temp[6]) return data->temp[7]; /* it has been checked recently */
162  #define EVEN(A)         (((A)<0?(A)+1:(A)) & ~1)          data->temp[5] = dx; data->temp[6] = dy; /* backup */
163    
164            switch (((dx & 1) << 1) | (dy & 1))     {
165                    case 0:
166                            sad = sad8(data->CurU, data->RefP[4] + offset, stride);
167                            sad += sad8(data->CurV, data->RefP[5] + offset, stride);
168                            break;
169                    case 1:
170                            next = stride;
171                    case 2:
172                            sad = sad8bi(data->CurU, data->RefP[4] + offset, data->RefP[4] + offset + next, stride);
173                            sad += sad8bi(data->CurV, data->RefP[5] + offset, data->RefP[5] + offset + next, stride);
174                            break;
175                    default:
176                            interpolate8x8_halfpel_hv(data->RefQ, data->RefP[4] + offset, stride, data->rounding);
177                            sad = sad8(data->CurU, data->RefQ, stride);
178    
179  #define MIN(X, Y) ((X)<(Y)?(X):(Y))                          interpolate8x8_halfpel_hv(data->RefQ, data->RefP[5] + offset, stride, data->rounding);
180  #define MAX(X, Y) ((X)>(Y)?(X):(Y))                          sad += sad8(data->CurV, data->RefQ, stride);
181  #define ABS(X)    (((X)>0)?(X):-(X))                          break;
182  #define SIGN(X)   (((X)>0)?1:-1)          }
183            data->temp[7] = sad; /* backup, part 2 */
184            return sad;
185    }
186    
187  int32_t PMVfastSearch16(  static __inline const uint8_t *
188                                          const uint8_t * const pRef,  GetReferenceB(const int x, const int y, const uint32_t dir, const SearchData * const data)
189                                          const uint8_t * const pRefH,  {
190                                          const uint8_t * const pRefV,          /* dir : 0 = forward, 1 = backward */
191                                          const uint8_t * const pRefHV,          const uint8_t *const *const direction = ( dir == 0 ? data->RefP : data->b_RefP );
192                                          const IMAGE * const pCur,          const int picture = ((x&1)<<1) | (y&1);
193                                          const int x, const int y,          const int offset = (x>>1) + (y>>1)*data->iEdgedWidth;
194                                          const uint32_t MotionFlags,          return direction[picture] + offset;
195                                          const MBParam * const pParam,  }
196                                          MACROBLOCK * const pMBs,  
197                                          VECTOR * const currMV,  /* this is a simpler copy of GetReferenceB, but as it's __inline anyway, we can keep the two separate */
198                                          VECTOR * const currPMV);  static __inline const uint8_t *
199    GetReference(const int x, const int y, const SearchData * const data)
200    {
201            const int picture = ((x&1)<<1) | (y&1);
202            const int offset = (x>>1) + (y>>1)*data->iEdgedWidth;
203            return data->RefP[picture] + offset;
204    }
205    
206    static uint8_t *
207    Interpolate8x8qpel(const int x, const int y, const uint32_t block, const uint32_t dir, const SearchData * const data)
208    {
209            /* create or find a qpel-precision reference picture; return pointer to it */
210            uint8_t * Reference = data->RefQ + 16*dir;
211            const uint32_t iEdgedWidth = data->iEdgedWidth;
212            const uint32_t rounding = data->rounding;
213            const int halfpel_x = x/2;
214            const int halfpel_y = y/2;
215            const uint8_t *ref1, *ref2, *ref3, *ref4;
216    
217            ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
218            ref1 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
219            switch( ((x&1)<<1) + (y&1) ) {
220            case 3: /* x and y in qpel resolution - the "corners" (top left/right and */
221                            /* bottom left/right) during qpel refinement */
222                    ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
223                    ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
224                    ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);
225                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
226                    ref3 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
227                    ref4 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
228                    interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
229                    break;
230    
231  int32_t EPZSSearch16(          case 1: /* x halfpel, y qpel - top or bottom during qpel refinement */
232                                          const uint8_t * const pRef,                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
233                                          const uint8_t * const pRefH,                  ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
234                                          const uint8_t * const pRefV,                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
235                                          const uint8_t * const pRefHV,                  break;
                                         const IMAGE * const pCur,  
                                         const int x, const int y,  
                                         const uint32_t MotionFlags,  
                                         const MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV);  
236    
237            case 2: /* x qpel, y halfpel - left or right during qpel refinement */
238                    ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
239                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
240                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
241                    break;
242    
243  int32_t PMVfastSearch8(          default: /* pure halfpel position */
244                                          const uint8_t * const pRef,                  return (uint8_t *) ref1;
                                         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, int start_y,  
                                         const uint32_t MotionFlags,  
                                         const MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV);  
   
 int32_t EPZSSearch8(  
                                         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, int start_y,  
                                         const uint32_t MotionFlags,  
                                         const MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV);  
245    
246            }
247            return Reference;
248    }
249    
250  typedef int32_t (MainSearch16Func)(  static uint8_t *
251          const uint8_t * const pRef,  Interpolate16x16qpel(const int x, const int y, const uint32_t dir, const SearchData * const data)
252          const uint8_t * const pRefH,  {
253          const uint8_t * const pRefV,          /* create or find a qpel-precision reference picture; return pointer to it */
254          const uint8_t * const pRefHV,          uint8_t * Reference = data->RefQ + 16*dir;
255          const uint8_t * const cur,          const uint32_t iEdgedWidth = data->iEdgedWidth;
256          const int x, const int y,          const uint32_t rounding = data->rounding;
257          int32_t startx, int32_t starty,          const int halfpel_x = x/2;
258          int32_t iMinSAD,          const int halfpel_y = y/2;
259          VECTOR * const currMV,          const uint8_t *ref1, *ref2, *ref3, *ref4;
         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);  
260    
261  typedef MainSearch16Func* MainSearch16FuncPtr;          ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
262            switch( ((x&1)<<1) + (y&1) ) {
263            case 3:
264                    /*
265                     * x and y in qpel resolution - the "corners" (top left/right and
266                     * bottom left/right) during qpel refinement
267                     */
268                    ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
269                    ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
270                    ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);
271                    interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
272                    interpolate8x8_avg4(Reference+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, rounding);
273                    interpolate8x8_avg4(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, rounding);
274                    interpolate8x8_avg4(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, rounding);
275                    break;
276    
277            case 1: /* x halfpel, y qpel - top or bottom during qpel refinement */
278                    ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
279                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
280                    interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
281                    interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
282                    interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
283                    break;
284    
285  typedef int32_t (MainSearch8Func)(          case 2: /* x qpel, y halfpel - left or right during qpel refinement */
286          const uint8_t * const pRef,                  ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
287          const uint8_t * const pRefH,                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
288          const uint8_t * const pRefV,                  interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
289          const uint8_t * const pRefHV,                  interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
290          const uint8_t * const cur,                  interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
291          const int x, const int y,                  break;
         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);  
   
 typedef MainSearch8Func* MainSearch8FuncPtr;  
   
 // mv.length table  
 static const uint32_t mvtab[33] = {  
     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  
 };  
292    
293    
294  static __inline uint32_t mv_bits(int32_t component, const uint32_t iFcode)          default: /* pure halfpel position */
295  {                  return (uint8_t *) ref1;
296      if (component == 0)          }
297                  return 1;          return Reference;
298    }
299    
300      if (component < 0)  /* CHECK_CANDIATE FUNCTIONS START */
                 component = -component;  
301    
302      if (iFcode == 1)  static void
303    CheckCandidate16(const int x, const int y, const SearchData * const data, const int Direction)
304      {      {
305                  if (component > 32)          int xc, yc;
306                      component = 32;          const uint8_t * Reference;
307            VECTOR * current;
308            int32_t sad; uint32_t t;
309    
310                  return mvtab[component] + 1;          if ( (x > data->max_dx) || (x < data->min_dx)
311                    || (y > data->max_dy) || (y < data->min_dy) ) return;
312    
313            if (!data->qpel_precision) {
314                    Reference = GetReference(x, y, data);
315                    current = data->currentMV;
316                    xc = x; yc = y;
317            } else { /* x and y are in 1/4 precision */
318                    Reference = Interpolate16x16qpel(x, y, 0, data);
319                    xc = x/2; yc = y/2; /* for chroma sad */
320                    current = data->currentQMV;
321      }      }
322    
323      component += (1 << (iFcode - 1)) - 1;          sad = sad16v(data->Cur, Reference, data->iEdgedWidth, data->temp);
324      component >>= (iFcode - 1);          t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
325    
326            sad += (data->lambda16 * t * sad)>>10;
327            data->temp[0] += (data->lambda8 * t * (data->temp[0] + NEIGH_8X8_BIAS))>>10;
328    
329      if (component > 32)          if (data->chroma && sad < data->iMinSAD[0])
330                  component = 32;                  sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
331                                                            (yc >> 1) + roundtab_79[yc & 0x3], data);
332    
333      return mvtab[component] + 1 + iFcode - 1;          if (sad < data->iMinSAD[0]) {
334                    data->iMinSAD[0] = sad;
335                    current[0].x = x; current[0].y = y;
336                    *data->dir = Direction;
337  }  }
338    
339            if (data->temp[0] < data->iMinSAD[1]) {
340                    data->iMinSAD[1] = data->temp[0]; current[1].x = x; current[1].y = y; }
341            if (data->temp[1] < data->iMinSAD[2]) {
342                    data->iMinSAD[2] = data->temp[1]; current[2].x = x; current[2].y = y; }
343            if (data->temp[2] < data->iMinSAD[3]) {
344                    data->iMinSAD[3] = data->temp[2]; current[3].x = x; current[3].y = y; }
345            if (data->temp[3] < data->iMinSAD[4]) {
346                    data->iMinSAD[4] = data->temp[3]; current[4].x = x; current[4].y = y; }
347    }
348    
349  static __inline uint32_t calc_delta_16(const int32_t dx, const int32_t dy, const uint32_t iFcode)  static void
350    CheckCandidate8(const int x, const int y, const SearchData * const data, const int Direction)
351  {  {
352          return NEIGH_TEND_16X16 * (mv_bits(dx, iFcode) + mv_bits(dy, iFcode));          int32_t sad; uint32_t t;
353            const uint8_t * Reference;
354            VECTOR * current;
355    
356            if ( (x > data->max_dx) || (x < data->min_dx)
357                    || (y > data->max_dy) || (y < data->min_dy) ) return;
358    
359            if (!data->qpel_precision) {
360                    Reference = GetReference(x, y, data);
361                    current = data->currentMV;
362            } else { /* x and y are in 1/4 precision */
363                    Reference = Interpolate8x8qpel(x, y, 0, 0, data);
364                    current = data->currentQMV;
365  }  }
366    
367  static __inline uint32_t calc_delta_8(const int32_t dx, const int32_t dy, const uint32_t iFcode)          sad = sad8(data->Cur, Reference, data->iEdgedWidth);
368            t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
369    
370            sad += (data->lambda8 * t * (sad+NEIGH_8X8_BIAS))>>10;
371    
372            if (sad < *(data->iMinSAD)) {
373                    *(data->iMinSAD) = sad;
374                    current->x = x; current->y = y;
375                    *data->dir = Direction;
376            }
377    }
378    
379    static void
380    CheckCandidate32(const int x, const int y, const SearchData * const data, const int Direction)
381  {  {
382      return NEIGH_TEND_8X8 * (mv_bits(dx, iFcode) + mv_bits(dy, iFcode));          uint32_t t;
383            const uint8_t * Reference;
384            int sad;
385    
386            if ( (!(x&1) && x !=0) || (!(y&1) && y !=0) || /* non-zero even value */
387                    (x > data->max_dx) || (x < data->min_dx)
388                    || (y > data->max_dy) || (y < data->min_dy) ) return;
389    
390            Reference = GetReference(x, y, data);
391            t = d_mv_bits(x, y, data->predMV, data->iFcode, 0, 1);
392    
393            sad = sad32v_c(data->Cur, Reference, data->iEdgedWidth, data->temp);
394    
395            sad += (data->lambda16 * t * sad) >> 10;
396            data->temp[0] += (data->lambda8 * t * (data->temp[0] + NEIGH_8X8_BIAS))>>10;
397    
398            if (sad < data->iMinSAD[0]) {
399                    data->iMinSAD[0] = sad;
400                    data->currentMV[0].x = x; data->currentMV[0].y = y;
401                    *data->dir = Direction;
402  }  }
403    
404            if (data->temp[0] < data->iMinSAD[1]) {
405                    data->iMinSAD[1] = data->temp[0]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
406            if (data->temp[1] < data->iMinSAD[2]) {
407                    data->iMinSAD[2] = data->temp[1]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
408            if (data->temp[2] < data->iMinSAD[3]) {
409                    data->iMinSAD[3] = data->temp[2]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
410            if (data->temp[3] < data->iMinSAD[4]) {
411                    data->iMinSAD[4] = data->temp[3]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
412    }
413    
414    static void
415    CheckCandidate16no4v(const int x, const int y, const SearchData * const data, const int Direction)
416    {
417            int32_t sad, xc, yc;
418            const uint8_t * Reference;
419            uint32_t t;
420            VECTOR * current;
421    
422            if ( (x > data->max_dx) || ( x < data->min_dx)
423                    || (y > data->max_dy) || (y < data->min_dy) ) return;
424    
425  /* calculate the min/max range (in halfpixels)          if (data->rrv && (!(x&1) && x !=0) | (!(y&1) && y !=0) ) return; /* non-zero even value */
         relative to the _MACROBLOCK_ position  
 */  
426    
427  static void __inline get_range(          if (data->qpel_precision) { /* x and y are in 1/4 precision */
428          int32_t * const min_dx, int32_t * const max_dx,                  Reference = Interpolate16x16qpel(x, y, 0, data);
429          int32_t * const min_dy, int32_t * const max_dy,                  current = data->currentQMV;
430          const uint32_t x, const uint32_t y,                  xc = x/2; yc = y/2;
431          const uint32_t block_sz,                                        // block dimension, 8 or 16          } else {
432          const uint32_t width, const uint32_t height,                  Reference = GetReference(x, y, data);
433          const uint32_t fcode)                  current = data->currentMV;
434  {                  xc = x; yc = y;
435            }
436          const int search_range = 32 << (fcode - 1);          t = d_mv_bits(x, y, data->predMV, data->iFcode,
437          const int high = search_range - 1;                                          data->qpel^data->qpel_precision, data->rrv);
438          const int low = -search_range;  
439            sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
440          // convert full-pixel measurements to half pixel          sad += (data->lambda16 * t * sad)>>10;
441          const int hp_width = 2 * width;  
442          const int hp_height = 2 * height;          if (data->chroma && sad < *data->iMinSAD)
443          const int hp_edge = 2 * block_sz;                  sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
444          const int hp_x = 2 * (x) * block_sz;            // we need _right end_ of block, not x-coordinate                                                          (yc >> 1) + roundtab_79[yc & 0x3], data);
         const int hp_y = 2 * (y) * block_sz;            // same for _bottom end_  
   
         *max_dx = MIN(high,     hp_width - hp_x);  
         *max_dy = MIN(high,     hp_height - hp_y);  
         *min_dx = MAX(low,      -(hp_edge + hp_x));  
         *min_dy = MAX(low,      -(hp_edge + hp_y));  
445    
446            if (sad < *(data->iMinSAD)) {
447                    *(data->iMinSAD) = sad;
448                    current->x = x; current->y = y;
449                    *data->dir = Direction;
450            }
451  }  }
452    
453    static void
454    CheckCandidate16I(const int x, const int y, const SearchData * const data, const int Direction)
455    {
456            int sad;
457    //      int xc, yc;
458            const uint8_t * Reference;
459    //      VECTOR * current;
460    
461  /*          if ( (x > data->max_dx) || ( x < data->min_dx)
462   * getref: calculate reference image pointer                  || (y > data->max_dy) || (y < data->min_dy) ) return;
463   * the decision to use interpolation h/v/hv or the normal image is  
464   * based on dx & dy.          Reference = GetReference(x, y, data);
465    //      xc = x; yc = y;
466    
467            sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
468    //      sad += d_mv_bits(x, y, data->predMV, data->iFcode, 0, 0);
469    
470    /*      if (data->chroma) sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
471                                                                                    (yc >> 1) + roundtab_79[yc & 0x3], data);
472   */   */
473    
474  static __inline const uint8_t * get_ref(          if (sad < data->iMinSAD[0]) {
475          const uint8_t * const refn,                  data->iMinSAD[0] = sad;
476          const uint8_t * const refh,                  data->currentMV[0].x = x; data->currentMV[0].y = y;
477          const uint8_t * const refv,                  *data->dir = Direction;
478          const uint8_t * const refhv,          }
479          const uint32_t x, const uint32_t y,  }
         const uint32_t block,                                   // block dimension, 8 or 16  
         const int32_t dx, const int32_t dy,  
         const uint32_t stride)  
 {  
480    
481          switch ( ((dx&1)<<1) + (dy&1) )         // ((dx%2)?2:0)+((dy%2)?1:0)  static void
482    CheckCandidate32I(const int x, const int y, const SearchData * const data, const int Direction)
483          {          {
484          case 0  : return refn + (x*block+dx/2) + (y*block+dy/2)*stride;          /* maximum speed - for P/B/I decision */
485          case 1  : return refv + (x*block+dx/2) + (y*block+(dy-1)/2)*stride;          int32_t sad;
486          case 2  : return refh + (x*block+(dx-1)/2) + (y*block+dy/2)*stride;  
487          default :          if ( (x > data->max_dx) || (x < data->min_dx)
488          case 3  : return refhv + (x*block+(dx-1)/2) + (y*block+(dy-1)/2)*stride;                  || (y > data->max_dy) || (y < data->min_dy) ) return;
489    
490            sad = sad32v_c(data->Cur, data->RefP[0] + x + y*((int)data->iEdgedWidth),
491                                            data->iEdgedWidth, data->temp);
492    
493            if (sad < *(data->iMinSAD)) {
494                    *(data->iMinSAD) = sad;
495                    data->currentMV[0].x = x; data->currentMV[0].y = y;
496                    *data->dir = Direction;
497          }          }
498            if (data->temp[0] < data->iMinSAD[1]) {
499                    data->iMinSAD[1] = data->temp[0]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
500            if (data->temp[1] < data->iMinSAD[2]) {
501                    data->iMinSAD[2] = data->temp[1]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
502            if (data->temp[2] < data->iMinSAD[3]) {
503                    data->iMinSAD[3] = data->temp[2]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
504            if (data->temp[3] < data->iMinSAD[4]) {
505                    data->iMinSAD[4] = data->temp[3]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
506    
507  }  }
508    
509    static void
510    CheckCandidateInt(const int xf, const int yf, const SearchData * const data, const int Direction)
511    {
512            int32_t sad, xb, yb, xcf, ycf, xcb, ycb;
513            uint32_t t;
514            const uint8_t *ReferenceF, *ReferenceB;
515            VECTOR *current;
516    
517  /* This is somehow a copy of get_ref, but with MV instead of X,Y */          if ((xf > data->max_dx) || (xf < data->min_dx) ||
518                    (yf > data->max_dy) || (yf < data->min_dy))
519                    return;
520    
521  static __inline const uint8_t * get_ref_mv(          if (!data->qpel_precision) {
522          const uint8_t * const refn,                  ReferenceF = GetReference(xf, yf, data);
523          const uint8_t * const refh,                  xb = data->currentMV[1].x; yb = data->currentMV[1].y;
524          const uint8_t * const refv,                  ReferenceB = GetReferenceB(xb, yb, 1, data);
525          const uint8_t * const refhv,                  current = data->currentMV;
526          const uint32_t x, const uint32_t y,                  xcf = xf; ycf = yf;
527          const uint32_t block,                   // block dimension, 8 or 16                  xcb = xb; ycb = yb;
528          const VECTOR* mv,       // measured in half-pel!          } else {
529          const uint32_t stride)                  ReferenceF = Interpolate16x16qpel(xf, yf, 0, data);
530  {                  xb = data->currentQMV[1].x; yb = data->currentQMV[1].y;
531                    current = data->currentQMV;
532                    ReferenceB = Interpolate16x16qpel(xb, yb, 1, data);
533                    xcf = xf/2; ycf = yf/2;
534                    xcb = xb/2; ycb = yb/2;
535            }
536    
537            t = d_mv_bits(xf, yf, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0)
538                     + d_mv_bits(xb, yb, data->bpredMV, data->iFcode, data->qpel^data->qpel_precision, 0);
539    
540            sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
541            sad += (data->lambda16 * t * sad)>>10;
542    
543            if (data->chroma && sad < *data->iMinSAD)
544                    sad += ChromaSAD2((xcf >> 1) + roundtab_79[xcf & 0x3],
545                                                            (ycf >> 1) + roundtab_79[ycf & 0x3],
546                                                            (xcb >> 1) + roundtab_79[xcb & 0x3],
547                                                            (ycb >> 1) + roundtab_79[ycb & 0x3], data);
548    
549            if (sad < *(data->iMinSAD)) {
550                    *(data->iMinSAD) = sad;
551                    current->x = xf; current->y = yf;
552                    *data->dir = Direction;
553            }
554    }
555    
556          switch ( (((mv->x)&1)<<1) + ((mv->y)&1) )  static void
557    CheckCandidateDirect(const int x, const int y, const SearchData * const data, const int Direction)
558          {          {
559          case 0  : return refn + (x*block+(mv->x)/2) + (y*block+(mv->y)/2)*stride;          int32_t sad = 0, xcf = 0, ycf = 0, xcb = 0, ycb = 0;
560          case 1  : return refv + (x*block+(mv->x)/2) + (y*block+((mv->y)-1)/2)*stride;          uint32_t k;
561          case 2  : return refh + (x*block+((mv->x)-1)/2) + (y*block+(mv->y)/2)*stride;          const uint8_t *ReferenceF;
562          default :          const uint8_t *ReferenceB;
563          case 3  : return refhv + (x*block+((mv->x)-1)/2) + (y*block+((mv->y)-1)/2)*stride;          VECTOR mvs, b_mvs;
564    
565            if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
566    
567            for (k = 0; k < 4; k++) {
568                    mvs.x = data->directmvF[k].x + x;
569                    b_mvs.x = ((x == 0) ?
570                            data->directmvB[k].x
571                            : mvs.x - data->referencemv[k].x);
572    
573                    mvs.y = data->directmvF[k].y + y;
574                    b_mvs.y = ((y == 0) ?
575                            data->directmvB[k].y
576                            : mvs.y - data->referencemv[k].y);
577    
578                    if ((mvs.x > data->max_dx)   || (mvs.x < data->min_dx)   ||
579                            (mvs.y > data->max_dy)   || (mvs.y < data->min_dy)   ||
580                            (b_mvs.x > data->max_dx) || (b_mvs.x < data->min_dx) ||
581                            (b_mvs.y > data->max_dy) || (b_mvs.y < data->min_dy) )
582                            return;
583    
584                    if (data->qpel) {
585                            xcf += mvs.x/2; ycf += mvs.y/2;
586                            xcb += b_mvs.x/2; ycb += b_mvs.y/2;
587                    } else {
588                            xcf += mvs.x; ycf += mvs.y;
589                            xcb += b_mvs.x; ycb += b_mvs.y;
590                            mvs.x *= 2; mvs.y *= 2; /* we move to qpel precision anyway */
591                            b_mvs.x *= 2; b_mvs.y *= 2;
592          }          }
593    
594                    ReferenceF = Interpolate8x8qpel(mvs.x, mvs.y, k, 0, data);
595                    ReferenceB = Interpolate8x8qpel(b_mvs.x, b_mvs.y, k, 1, data);
596    
597                    sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
598                                                    ReferenceF, ReferenceB, data->iEdgedWidth);
599                    if (sad > *(data->iMinSAD)) return;
600  }  }
601    
602  #ifndef SEARCH16          sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;
 #define SEARCH16        PMVfastSearch16  
 //#define SEARCH16      FullSearch16  
 //#define SEARCH16      EPZSSearch16  
 #endif  
603    
604  #ifndef SEARCH8          if (data->chroma && sad < *data->iMinSAD)
605  #define SEARCH8         PMVfastSearch8                  sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],
606  //#define SEARCH8       EPZSSearch8                                                          (ycf >> 3) + roundtab_76[ycf & 0xf],
607  #endif                                                          (xcb >> 3) + roundtab_76[xcb & 0xf],
608                                                            (ycb >> 3) + roundtab_76[ycb & 0xf], data);
609    
610  bool MotionEstimation(          if (sad < *(data->iMinSAD)) {
611          MACROBLOCK * const pMBs,                  *(data->iMinSAD) = sad;
612          MBParam * const pParam,                  data->currentMV->x = x; data->currentMV->y = y;
613          const IMAGE * const pRef,                  *data->dir = Direction;
614          const IMAGE * const pRefH,          }
615          const IMAGE * const pRefV,  }
         const IMAGE * const pRefHV,  
         IMAGE * const pCurrent,  
         const uint32_t iLimit)  
616    
617    static void
618    CheckCandidateDirectno4v(const int x, const int y, const SearchData * const data, const int Direction)
619  {  {
620          const uint32_t iWcount = pParam->mb_width;          int32_t sad, xcf, ycf, xcb, ycb;
621          const uint32_t iHcount = pParam->mb_height;          const uint8_t *ReferenceF;
622            const uint8_t *ReferenceB;
623            VECTOR mvs, b_mvs;
624    
625          uint32_t i, j, iIntra = 0;          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
626    
627          VECTOR mv16;          mvs.x = data->directmvF[0].x + x;
628          VECTOR pmv16;          b_mvs.x = ((x == 0) ?
629                    data->directmvB[0].x
630                    : mvs.x - data->referencemv[0].x);
631    
632          int32_t sad8 = 0;          mvs.y = data->directmvF[0].y + y;
633          int32_t sad16;          b_mvs.y = ((y == 0) ?
634          int32_t deviation;                  data->directmvB[0].y
635                    : mvs.y - data->referencemv[0].y);
636    
637          // note: i==horizontal, j==vertical          if ( (mvs.x > data->max_dx) || (mvs.x < data->min_dx)
638          for (i = 0; i < iHcount; i++)                  || (mvs.y > data->max_dy) || (mvs.y < data->min_dy)
639                  for (j = 0; j < iWcount; j++)                  || (b_mvs.x > data->max_dx) || (b_mvs.x < data->min_dx)
640                  {                  || (b_mvs.y > data->max_dy) || (b_mvs.y < data->min_dy) ) return;
                         MACROBLOCK *pMB = &pMBs[j + i * iWcount];  
641    
642                          sad16 = SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,          if (data->qpel) {
643                                           j, i, pParam->motion_flags,                  xcf = 4*(mvs.x/2); ycf = 4*(mvs.y/2);
644                                           pParam, pMBs, &mv16, &pmv16);                  xcb = 4*(b_mvs.x/2); ycb = 4*(b_mvs.y/2);
645                          pMB->sad16=sad16;                  ReferenceF = Interpolate16x16qpel(mvs.x, mvs.y, 0, data);
646                    ReferenceB = Interpolate16x16qpel(b_mvs.x, b_mvs.y, 1, data);
647            } else {
648                    xcf = 4*mvs.x; ycf = 4*mvs.y;
649                    xcb = 4*b_mvs.x; ycb = 4*b_mvs.y;
650                    ReferenceF = GetReference(mvs.x, mvs.y, data);
651                    ReferenceB = GetReferenceB(b_mvs.x, b_mvs.y, 1, data);
652            }
653    
654            sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
655            sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;
656    
657                          /* decide: MODE_INTER or MODE_INTRA          if (data->chroma && sad < *data->iMinSAD)
658                             if (dev_intra < sad_inter - 2 * nb) use_intra                  sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],
659                          */                                                          (ycf >> 3) + roundtab_76[ycf & 0xf],
660                                                            (xcb >> 3) + roundtab_76[xcb & 0xf],
661                                                            (ycb >> 3) + roundtab_76[ycb & 0xf], data);
662    
663                          deviation = dev16(pCurrent->y + j*16 + i*16*pParam->edged_width, pParam->edged_width);          if (sad < *(data->iMinSAD)) {
664                    *(data->iMinSAD) = sad;
665                    data->currentMV->x = x; data->currentMV->y = y;
666                    *data->dir = Direction;
667            }
668    }
669    
670                          if (deviation < (sad16 - INTER_BIAS))  
671    static void
672    CheckCandidateRD16(const int x, const int y, const SearchData * const data, const int Direction)
673                          {                          {
                                 pMB->mode = MODE_INTRA;  
                                 pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = 0;  
                                 pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = 0;  
674    
675                                  iIntra++;          int16_t *in = data->dctSpace, *coeff = data->dctSpace + 64;
676                                  if(iIntra >= iLimit)          int32_t rd = 0;
677                                          return 1;          VECTOR * current;
678            const uint8_t * ptr;
679            int i, cbp = 0, t, xc, yc;
680    
681                                  continue;          if ( (x > data->max_dx) || (x < data->min_dx)
682                    || (y > data->max_dy) || (y < data->min_dy) ) return;
683    
684            if (!data->qpel_precision) {
685                    ptr = GetReference(x, y, data);
686                    current = data->currentMV;
687                    xc = x; yc = y;
688            } else { /* x and y are in 1/4 precision */
689                    ptr = Interpolate16x16qpel(x, y, 0, data);
690                    current = data->currentQMV;
691                    xc = x/2; yc = y/2;
692                          }                          }
693    
694                          if (pParam->global_flags & XVID_INTER4V)          for(i = 0; i < 4; i++) {
695                          {                  int s = 8*((i&1) + (i>>1)*data->iEdgedWidth);
696                                  pMB->sad8[0] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,                  transfer_8to16subro(in, data->Cur + s, ptr + s, data->iEdgedWidth);
697                                                         2 * j, 2 * i, mv16.x, mv16.y, pParam->motion_flags,                  rd += data->temp[i] = Block_CalcBits(coeff, in, data->dctSpace + 128, data->iQuant, data->quant_type, &cbp, i);
698                                                         pParam, pMBs, &pMB->mvs[0], &pMB->pmvs[0]);          }
699    
700            rd += t = BITS_MULT*d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
701    
702            if (data->temp[0] + t < data->iMinSAD[1]) {
703                    data->iMinSAD[1] = data->temp[0] + t; current[1].x = x; current[1].y = y; data->cbp[1] = (data->cbp[1]&~32) | (cbp&32); }
704            if (data->temp[1] < data->iMinSAD[2]) {
705                    data->iMinSAD[2] = data->temp[1]; current[2].x = x; current[2].y = y; data->cbp[1] = (data->cbp[1]&~16) | (cbp&16); }
706            if (data->temp[2] < data->iMinSAD[3]) {
707                    data->iMinSAD[3] = data->temp[2]; current[3].x = x; current[3].y = y; data->cbp[1] = (data->cbp[1]&~8) | (cbp&8); }
708            if (data->temp[3] < data->iMinSAD[4]) {
709                    data->iMinSAD[4] = data->temp[3]; current[4].x = x; current[4].y = y; data->cbp[1] = (data->cbp[1]&~4) | (cbp&4); }
710    
711            rd += BITS_MULT*xvid_cbpy_tab[15-(cbp>>2)].len;
712    
713            if (rd >= data->iMinSAD[0]) return;
714    
715                                  pMB->sad8[1] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,          /* chroma */
716                                                         2 * j + 1, 2 * i, mv16.x, mv16.y, pParam->motion_flags,          xc = (xc >> 1) + roundtab_79[xc & 0x3];
717                                                         pParam, pMBs, &pMB->mvs[1], &pMB->pmvs[1]);          yc = (yc >> 1) + roundtab_79[yc & 0x3];
718    
719                                  pMB->sad8[2] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,          /* chroma U */
720                                                         2 * j, 2 * i + 1, mv16.x, mv16.y, pParam->motion_flags,          ptr = interpolate8x8_switch2(data->RefQ, data->RefP[4], 0, 0, xc, yc, data->iEdgedWidth/2, data->rounding);
721                                                         pParam, pMBs, &pMB->mvs[2], &pMB->pmvs[2]);          transfer_8to16subro(in, data->CurU, ptr, data->iEdgedWidth/2);
722            rd += Block_CalcBits(coeff, in, data->dctSpace + 128, data->iQuant, data->quant_type, &cbp, 4);
723            if (rd >= data->iMinSAD[0]) return;
724    
725                                  pMB->sad8[3] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,          /* chroma V */
726                                                         2 * j + 1, 2 * i + 1, mv16.x, mv16.y, pParam->motion_flags,          ptr = interpolate8x8_switch2(data->RefQ, data->RefP[5], 0, 0, xc, yc, data->iEdgedWidth/2, data->rounding);
727                                                         pParam, pMBs, &pMB->mvs[3], &pMB->pmvs[3]);          transfer_8to16subro(in, data->CurV, ptr, data->iEdgedWidth/2);
728            rd += Block_CalcBits(coeff, in, data->dctSpace + 128, data->iQuant, data->quant_type, &cbp, 5);
729    
730                                  sad8 = pMB->sad8[0] + pMB->sad8[1] + pMB->sad8[2] + pMB->sad8[3];          rd += BITS_MULT*mcbpc_inter_tab[(MODE_INTER & 7) | ((cbp & 3) << 3)].len;
731    
732            if (rd < data->iMinSAD[0]) {
733                    data->iMinSAD[0] = rd;
734                    current[0].x = x; current[0].y = y;
735                    *data->dir = Direction;
736                    *data->cbp = cbp;
737            }
738                          }                          }
739    
740    static void
741    CheckCandidateRD8(const int x, const int y, const SearchData * const data, const int Direction)
742    {
743    
744                          /* decide: MODE_INTER or MODE_INTER4V          int16_t *in = data->dctSpace, *coeff = data->dctSpace + 64;
745                             mpeg4:   if (sad8 < sad16 - nb/2+1) use_inter4v          int32_t rd;
746                          */          VECTOR * current;
747            const uint8_t * ptr;
748            int cbp = 0;
749    
750                          if (pMB->dquant == NO_CHANGE) {          if ( (x > data->max_dx) || (x < data->min_dx)
751                                  if (((pParam->global_flags & XVID_INTER4V)==0) ||                  || (y > data->max_dy) || (y < data->min_dy) ) return;
                                     (sad16 < (sad8 + (int32_t)(IMV16X16 * pParam->quant)))) {  
752    
753                                          sad8 = sad16;          if (!data->qpel_precision) {
754                                          pMB->mode = MODE_INTER;                  ptr = GetReference(x, y, data);
755                                          pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = mv16.x;                  current = data->currentMV;
756                                          pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = mv16.y;          } else { /* x and y are in 1/4 precision */
757                                          pMB->pmvs[0].x = pmv16.x;                  ptr = Interpolate8x8qpel(x, y, 0, 0, data);
758                                          pMB->pmvs[0].y = pmv16.y;                  current = data->currentQMV;
759                                  }                                  }
760                                  else  
761                                          pMB->mode = MODE_INTER4V;          transfer_8to16subro(in, data->Cur, ptr, data->iEdgedWidth);
762            rd = Block_CalcBits(coeff, in, data->dctSpace + 128, data->iQuant, data->quant_type, &cbp, 5);
763            rd += BITS_MULT*d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
764    
765            if (rd < data->iMinSAD[0]) {
766                    *data->cbp = cbp;
767                    data->iMinSAD[0] = rd;
768                    current[0].x = x; current[0].y = y;
769                    *data->dir = Direction;
770                          }                          }
771                          else  }
772    
773    /* CHECK_CANDIATE FUNCTIONS END */
774    
775    /* MAINSEARCH FUNCTIONS START */
776    
777    static void
778    AdvDiamondSearch(int x, int y, const SearchData * const data, int bDirection, CheckFunc * const CheckCandidate)
779                          {                          {
780                                  sad8 = sad16;  
781                                  pMB->mode = MODE_INTER;  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
782                                  pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = mv16.x;  
783                                  pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = mv16.y;          unsigned int * const iDirection = data->dir;
784                                  pMB->pmvs[0].x = pmv16.x;  
785                                  pMB->pmvs[0].y = pmv16.y;          for(;;) { /* forever */
786                    *iDirection = 0;
787                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
788                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
789                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
790                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
791    
792                    /* now we're doing diagonal checks near our candidate */
793    
794                    if (*iDirection) {              /* if anything found */
795                            bDirection = *iDirection;
796                            *iDirection = 0;
797                            x = data->currentMV->x; y = data->currentMV->y;
798                            if (bDirection & 3) {   /* our candidate is left or right */
799                                    CHECK_CANDIDATE(x, y + iDiamondSize, 8);
800                                    CHECK_CANDIDATE(x, y - iDiamondSize, 4);
801                            } else {                        /* what remains here is up or down */
802                                    CHECK_CANDIDATE(x + iDiamondSize, y, 2);
803                                    CHECK_CANDIDATE(x - iDiamondSize, y, 1);
804                            }
805    
806                            if (*iDirection) {
807                                    bDirection += *iDirection;
808                                    x = data->currentMV->x; y = data->currentMV->y;
809                            }
810                    } else {                                /* about to quit, eh? not so fast.... */
811                            switch (bDirection) {
812                            case 2:
813                                    CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
814                                    CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
815                                    break;
816                            case 1:
817                                    CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
818                                    CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
819                                    break;
820                            case 2 + 4:
821                                    CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
822                                    CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
823                                    CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
824                                    break;
825                            case 4:
826                                    CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
827                                    CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
828                                    break;
829                            case 8:
830                                    CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
831                                    CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
832                                    break;
833                            case 1 + 4:
834                                    CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
835                                    CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
836                                    CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
837                                    break;
838                            case 2 + 8:
839                                    CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
840                                    CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
841                                    CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
842                                    break;
843                            case 1 + 8:
844                                    CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
845                                    CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
846                                    CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
847                                    break;
848                            default:                /* 1+2+4+8 == we didn't find anything at all */
849                                    CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
850                                    CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
851                                    CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
852                                    CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
853                                    break;
854                            }
855                            if (!*iDirection) break;                /* ok, the end. really */
856                            bDirection = *iDirection;
857                            x = data->currentMV->x; y = data->currentMV->y;
858                    }
859                          }                          }
860                  }                  }
861    
862          return 0;  static void
863    SquareSearch(int x, int y, const SearchData * const data, int bDirection, CheckFunc * const CheckCandidate)
864    {
865            unsigned int * const iDirection = data->dir;
866    
867            do {
868                    *iDirection = 0;
869                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);
870                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);
871                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);
872                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128);
873                    if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64);
874                    if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128);
875                    if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128);
876                    if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128);
877    
878                    bDirection = *iDirection;
879                    x = data->currentMV->x; y = data->currentMV->y;
880            } while (*iDirection);
881  }  }
882    
883  #define MVzero(A) ( ((A).x)==(0) && ((A).y)==(0) )  static void
884    DiamondSearch(int x, int y, const SearchData * const data, int bDirection, CheckFunc * const CheckCandidate)
885    {
886    
887    /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
888    
889  #define MVequal(A,B) ( ((A).x)==((B).x) && ((A).y)==((B).y) )          unsigned int * const iDirection = data->dir;
890    
891            do {
892                    *iDirection = 0;
893                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
894                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
895                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
896                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
897    
898  #define CHECK_MV16_ZERO {\                  /* now we're doing diagonal checks near our candidate */
899    if ( (0 <= max_dx) && (0 >= min_dx) \  
900      && (0 <= max_dy) && (0 >= min_dy) ) \                  if (*iDirection) {              /* checking if anything found */
901    { \                          bDirection = *iDirection;
902      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \                          *iDirection = 0;
903      iSAD += calc_delta_16(-pmv[0].x, -pmv[0].y, (uint8_t)iFcode) * iQuant;\                          x = data->currentMV->x; y = data->currentMV->y;
904      if (iSAD <= iQuant * 96)    \                          if (bDirection & 3) {   /* our candidate is left or right */
905          iSAD -= MV16_00_BIAS; \                                  CHECK_CANDIDATE(x, y + iDiamondSize, 8);
906      if (iSAD < iMinSAD) \                                  CHECK_CANDIDATE(x, y - iDiamondSize, 4);
907      {  iMinSAD=iSAD; currMV->x=0; currMV->y=0; }  }     \                          } else {                        /* what remains here is up or down */
908  }                                  CHECK_CANDIDATE(x + iDiamondSize, y, 2);
909                                    CHECK_CANDIDATE(x - iDiamondSize, y, 1);
910  #define NOCHECK_MV16_CANDIDATE(X,Y) { \                          }
911      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \                          bDirection += *iDirection;
912      iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode) * iQuant;\                          x = data->currentMV->x; y = data->currentMV->y;
913      if (iSAD < iMinSAD) \                  }
914      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \          }
915  }          while (*iDirection);
   
 #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; } } \  
916  }  }
917    
918  /* too slow and not fully functional at the moment */  /* MAINSEARCH FUNCTIONS END */
919  /*  
920  int32_t ZeroSearch16(  static void
921                                          const uint8_t * const pRef,  SubpelRefine(const SearchData * const data, CheckFunc * const CheckCandidate)
922                                          const uint8_t * const pRefH,  {
923                                          const uint8_t * const pRefV,  /* Do a half-pel or q-pel refinement */
924                                          const uint8_t * const pRefHV,          const VECTOR centerMV = data->qpel_precision ? *data->currentQMV : *data->currentMV;
925                                          const IMAGE * const pCur,  
926            CHECK_CANDIDATE(centerMV.x, centerMV.y - 1, 0);
927            CHECK_CANDIDATE(centerMV.x + 1, centerMV.y - 1, 0);
928            CHECK_CANDIDATE(centerMV.x + 1, centerMV.y, 0);
929            CHECK_CANDIDATE(centerMV.x + 1, centerMV.y + 1, 0);
930            CHECK_CANDIDATE(centerMV.x, centerMV.y + 1, 0);
931            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y + 1, 0);
932            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y, 0);
933            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y - 1, 0);
934    }
935    
936    static __inline int
937    SkipDecisionP(const IMAGE * current, const IMAGE * reference,
938                                          const int x, const int y,                                          const int x, const int y,
939                                          const uint32_t MotionFlags,                                                          const uint32_t stride, const uint32_t iQuant, int rrv)
940                                          MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
941  {  {
942          const int32_t iEdgedWidth = pParam->edged_width;          int offset = (x + y*stride)*8;
943          const int32_t iQuant = pParam->quant;          if(!rrv) {
944          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;                  uint32_t sadC = sad8(current->u + offset,
945          int32_t iSAD;                                                  reference->u + offset, stride);
946          int32_t pred_x,pred_y;                  if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
947                    sadC += sad8(current->v + offset,
948          get_pmv(pMBs, x, y, pParam->mb_width, 0, &pred_x, &pred_y);                                                  reference->v + offset, stride);
949                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
950          iSAD = sad16( cur,                  return 1;
                 get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth),  
                 iEdgedWidth, MV_MAX_ERROR);  
         if (iSAD <= iQuant * 96)  
                 iSAD -= MV16_00_BIAS;  
   
         currMV->x = 0;  
         currMV->y = 0;  
         currPMV->x = -pred_x;  
         currPMV->y = -pred_y;  
951    
952          return iSAD;          } else {
953                    uint32_t sadC = sad16(current->u + 2*offset,
954                                                    reference->u + 2*offset, stride, 256*4096);
955                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
956                    sadC += sad16(current->v + 2*offset,
957                                                    reference->v + 2*offset, stride, 256*4096);
958                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
959                    return 1;
960            }
961    }
962    
963    static __inline void
964    ZeroMacroblockP(MACROBLOCK *pMB, const int32_t sad)
965    {
966            pMB->mode = MODE_INTER;
967            pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = zeroMV;
968            pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] = pMB->qmvs[3] = zeroMV;
969            pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
970  }  }
 */  
971    
972  int32_t Diamond16_MainSearch(  static __inline void
973          const uint8_t * const pRef,  ModeDecision(SearchData * const Data,
974          const uint8_t * const pRefH,                          MACROBLOCK * const pMB,
975          const uint8_t * const pRefV,                          const MACROBLOCK * const pMBs,
         const uint8_t * const pRefHV,  
         const uint8_t * const cur,  
976          const int x, const int y,          const int x, const int y,
977          int32_t startx, int32_t starty,                          const MBParam * const pParam,
978          int32_t iMinSAD,                          const uint32_t MotionFlags,
979          VECTOR * const currMV,                          const uint32_t VopFlags,
980          const VECTOR * const pmv,                          const uint32_t VolFlags,
981          const int32_t min_dx, const int32_t max_dx,                          const IMAGE * const pCurrent,
982          const int32_t min_dy, const int32_t max_dy,                          const IMAGE * const pRef,
983          const int32_t iEdgedWidth,                          const IMAGE * const vGMC,
984          const int32_t iDiamondSize,                          const int coding_type)
         const int32_t iFcode,  
         const int32_t iQuant,  
         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iDirection=0;  
         int32_t iSAD;  
         VECTOR backupMV;  
         backupMV.x = startx;  
         backupMV.y = starty;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         CHECK_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);  
   
         if (iDirection)  
                 while (!iFound)  
                 {  
                         iFound = 1;  
                         backupMV=*currMV;  
   
                         if ( iDirection != 2)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x-iDiamondSize,backupMV.y,1);  
                         if ( iDirection != 1)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x+iDiamondSize,backupMV.y,2);  
                         if ( iDirection != 4)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,backupMV.y-iDiamondSize,3);  
                         if ( iDirection != 3)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,backupMV.y+iDiamondSize,4);  
                 }  
         else  
985          {          {
986                  currMV->x = startx;          int mode = MODE_INTER;
987                  currMV->y = starty;          int mcsel = 0;
988            int inter4v = (VopFlags & XVID_VOP_INTER4V) && (pMB->dquant == 0);
989            const uint32_t iQuant = pMB->quant;
990    
991            const int skip_possible = (coding_type == P_VOP) && (pMB->dquant == 0);
992    
993            pMB->mcsel = 0;
994    
995            if (!(VopFlags & XVID_VOP_MODEDECISION_RD)) { /* normal, fast, SAD-based mode decision */
996                    int sad;
997                    int InterBias = MV16_INTER_BIAS;
998                    if (inter4v == 0 || Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
999                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant) {
1000                            mode = MODE_INTER;
1001                            sad = Data->iMinSAD[0];
1002                    } else {
1003                            mode = MODE_INTER4V;
1004                            sad = Data->iMinSAD[1] + Data->iMinSAD[2] +
1005                                                    Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant;
1006                            Data->iMinSAD[0] = sad;
1007          }          }
1008          return iMinSAD;  
1009                    /* final skip decision, a.k.a. "the vector you found, really that good?" */
1010                    if (skip_possible && (pMB->sad16 < (int)iQuant * MAX_SAD00_FOR_SKIP))
1011                            if ( (100*sad)/(pMB->sad16+1) > FINAL_SKIP_THRESH)
1012                                    if (Data->chroma || SkipDecisionP(pCurrent, pRef, x, y, Data->iEdgedWidth/2, iQuant, Data->rrv)) {
1013                                            mode = MODE_NOT_CODED;
1014                                            sad = 0;
1015  }  }
1016    
1017  int32_t Square16_MainSearch(                  /* mcsel */
1018                                          const uint8_t * const pRef,                  if (coding_type == S_VOP) {
                                         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)  
 {  
 /* Do a square search around given starting point, return SAD of best */  
   
         int32_t iDirection=0;  
         int32_t iSAD;  
         VECTOR backupMV;  
         backupMV.x = startx;  
         backupMV.y = starty;  
   
 /* It's one search with full square pattern, and new parts for all following diamonds */  
   
 /*   new direction are extra, so 1-4 is normal diamond  
       537  
       1*2  
       648  
 */  
1019    
1020          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y,1);                          int32_t iSAD = sad16(Data->Cur,
1021          CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);                                  vGMC->y + 16*y*Data->iEdgedWidth + 16*x, Data->iEdgedWidth, 65536);
         CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);  
1022    
1023          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);                          if (Data->chroma) {
1024          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);                                  iSAD += sad8(Data->CurU, vGMC->u + 8*y*(Data->iEdgedWidth/2) + 8*x, Data->iEdgedWidth/2);
1025          CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);                                  iSAD += sad8(Data->CurV, vGMC->v + 8*y*(Data->iEdgedWidth/2) + 8*x, Data->iEdgedWidth/2);
1026          CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);                          }
1027    
1028                            if (iSAD <= sad) {              /* mode decision GMC */
1029                                    mode = MODE_INTER;
1030                                    mcsel = 1;
1031                                    sad = iSAD;
1032                            }
1033    
1034          if (iDirection)                  }
                 while (!iFound)  
                 {  
                         iFound = 1;  
                         backupMV=*currMV;  
1035    
1036                          switch (iDirection)                  /* intra decision */
                         {  
                                 case 1:  
                                         CHECK_MV16_CANDIDATE_FOUND(backupMV.x-iDiamondSize,backupMV.y,1);  
                                         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;  
1037    
1038                                  case 3:                  if (iQuant > 8) InterBias += 100 * (iQuant - 8); /* to make high quants work */
1039                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);                  if (y != 0)
1040                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);                          if ((pMB - pParam->mb_width)->mode == MODE_INTRA ) InterBias -= 80;
1041                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);                  if (x != 0)
1042                                          break;                          if ((pMB - 1)->mode == MODE_INTRA ) InterBias -= 80;
1043    
1044                                  case 4:                  if (Data->chroma) InterBias += 50; /* dev8(chroma) ??? <-- yes, we need dev8 (no big difference though) */
1045                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);                  if (Data->rrv) InterBias *= 4;
                                         CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);  
                                         CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);  
                                         break;  
1046    
1047                                  case 5:                  if (InterBias < sad) {
1048                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y,1);                          int32_t deviation;
1049                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);                          if (!Data->rrv)
1050                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);                                  deviation = dev16(Data->Cur, Data->iEdgedWidth);
1051                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);                          else
1052                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);                                  deviation = dev16(Data->Cur, Data->iEdgedWidth) + /* dev32() */
1053                                          break;                                                          dev16(Data->Cur+16, Data->iEdgedWidth) +
1054                                                            dev16(Data->Cur + 16*Data->iEdgedWidth, Data->iEdgedWidth) +
1055                                                            dev16(Data->Cur+16+16*Data->iEdgedWidth, Data->iEdgedWidth);
1056    
1057                                  case 6:                          if (deviation < (sad - InterBias)) mode = MODE_INTRA;
1058                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);                  }
                                         CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);  
1059    
1060                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);                  pMB->cbp = 63;
1061                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
                                         CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);  
1062    
1063                                          break;          } else { /* Rate-Distortion */
1064    
1065                                  case 7:                  int min_rd, intra_rd, i, cbp, c[2] = {0, 0};
1066                                          CHECK_MV16_CANDIDATE_FOUND(backupMV.x-iDiamondSize,backupMV.y,1);                  VECTOR backup[5], *v;
1067                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);                  Data->iQuant = iQuant;
1068                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);                  Data->cbp = c;
                                         CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);  
                                         CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);  
                                         break;  
1069    
1070                                  case 8:                  v = Data->qpel ? Data->currentQMV : Data->currentMV;
1071                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);                  for (i = 0; i < 5; i++) {
1072                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);                          Data->iMinSAD[i] = 256*4096;
1073                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);                          backup[i] = v[i];
                                         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;  
1074                          }                          }
1075    
1076                    min_rd = findRDinter(Data, pMBs, x, y, pParam, MotionFlags);
1077                    cbp = *Data->cbp;
1078    
1079                    if (coding_type == S_VOP) {
1080                            int gmc_rd;
1081                            *Data->iMinSAD = min_rd += BITS_MULT*1; /* mcsel */
1082                            gmc_rd = findRDgmc(Data, vGMC, x, y);
1083                            if (gmc_rd < min_rd) {
1084                                    mcsel = 1;
1085                                    *Data->iMinSAD = min_rd = gmc_rd;
1086                                    mode = MODE_INTER;
1087                                    cbp = *Data->cbp;
1088                  }                  }
         else  
                 {  
                         currMV->x = startx;  
                         currMV->y = starty;  
1089                  }                  }
1090          return iMinSAD;  
1091                    if (inter4v) {
1092                            int v4_rd;
1093                            v4_rd = findRDinter4v(Data, pMB, pMBs, x, y, pParam, MotionFlags, backup);
1094                            if (v4_rd < min_rd) {
1095                                    Data->iMinSAD[0] = min_rd = v4_rd;
1096                                    mode = MODE_INTER4V;
1097                                    cbp = *Data->cbp;
1098                            }
1099  }  }
1100    
1101                    intra_rd = findRDintra(Data);
1102                    if (intra_rd < min_rd) {
1103                            *Data->iMinSAD = min_rd = intra_rd;
1104                            mode = MODE_INTRA;
1105                    }
1106    
1107  int32_t Full16_MainSearch(                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = 0;
1108                                          const uint8_t * const pRef,                  pMB->cbp = cbp;
1109                                          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)  
 {  
         int32_t iSAD;  
         int32_t dx,dy;  
         VECTOR backupMV;  
         backupMV.x = startx;  
         backupMV.y = starty;  
   
         for (dx = min_dx; dx<=max_dx; dx+=iDiamondSize)  
                 for (dy = min_dy; dy<= max_dy; dy+=iDiamondSize)  
                         NOCHECK_MV16_CANDIDATE(dx,dy);  
1110    
1111          return iMinSAD;          if (Data->rrv) {
1112                            Data->currentMV[0].x = RRV_MV_SCALEDOWN(Data->currentMV[0].x);
1113                            Data->currentMV[0].y = RRV_MV_SCALEDOWN(Data->currentMV[0].y);
1114  }  }
1115    
1116  int32_t Full8_MainSearch(          if (mode == MODE_INTER && mcsel == 0) {
1117                                          const uint8_t * const pRef,                  pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x, const int y,  
                                         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)  
 {  
         int32_t iSAD;  
         int32_t dx,dy;  
         VECTOR backupMV;  
         backupMV.x = startx;  
         backupMV.y = starty;  
   
         for (dx = min_dx; dx<=max_dx; dx+=iDiamondSize)  
                 for (dy = min_dy; dy<= max_dy; dy+=iDiamondSize)  
                         NOCHECK_MV8_CANDIDATE(dx,dy);  
1118    
1119          return iMinSAD;                  if(Data->qpel) {
1120                            pMB->qmvs[0] = pMB->qmvs[1]
1121                                    = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1122                            pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1123                            pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;
1124                    } else {
1125                            pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1126                            pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
1127  }  }
1128    
1129            } else if (mode == MODE_INTER ) { // but mcsel == 1
1130    
1131                    pMB->mcsel = 1;
1132                    if (Data->qpel) {
1133                            pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] = pMB->qmvs[3] = pMB->amv;
1134                            pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = pMB->amv.x/2;
1135                            pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = pMB->amv.y/2;
1136                    } else
1137                            pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->amv;
1138    
1139  int32_t Halfpel16_Refine(          } else
1140          const uint8_t * const pRef,                  if (mode == MODE_INTER4V) ; /* anything here? */
1141          const uint8_t * const pRefH,          else    /* INTRA, NOT_CODED */
1142          const uint8_t * const pRefV,                  ZeroMacroblockP(pMB, 0);
1143          const uint8_t * const pRefHV,  
1144          const uint8_t * const cur,          pMB->mode = mode;
1145          const int x, const int y,  }
1146          VECTOR * const currMV,  
1147          int32_t iMinSAD,  bool
1148          const VECTOR * const pmv,  MotionEstimation(MBParam * const pParam,
1149          const int32_t min_dx, const int32_t max_dx,                                   FRAMEINFO * const current,
1150          const int32_t min_dy, const int32_t max_dy,                                   FRAMEINFO * const reference,
1151          const int32_t iFcode,                                   const IMAGE * const pRefH,
1152          const int32_t iQuant,                                   const IMAGE * const pRefV,
1153          const int32_t iEdgedWidth)                                   const IMAGE * const pRefHV,
1154                                    const IMAGE * const pGMC,
1155                                     const uint32_t iLimit)
1156  {  {
1157  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */          MACROBLOCK *const pMBs = current->mbs;
1158            const IMAGE *const pCurrent = &current->image;
1159            const IMAGE *const pRef = &reference->image;
1160    
1161            uint32_t mb_width = pParam->mb_width;
1162            uint32_t mb_height = pParam->mb_height;
1163            const uint32_t iEdgedWidth = pParam->edged_width;
1164            const uint32_t MotionFlags = MakeGoodMotionFlags(current->motion_flags, current->vop_flags, current->vol_flags);
1165    
1166            uint32_t x, y;
1167            uint32_t iIntra = 0;
1168            int32_t sad00;
1169            int skip_thresh = INITIAL_SKIP_THRESH * \
1170                    (current->vop_flags & XVID_VOP_REDUCED ? 4:1) * \
1171                    (current->vop_flags & XVID_VOP_MODEDECISION_RD ? 2:1);
1172    
1173            /* some pre-initialized thingies for SearchP */
1174            int32_t temp[8]; uint32_t dir;
1175            VECTOR currentMV[5];
1176            VECTOR currentQMV[5];
1177            int32_t iMinSAD[5];
1178            DECLARE_ALIGNED_MATRIX(dct_space, 3, 64, int16_t, CACHE_LINE);
1179            SearchData Data;
1180            memset(&Data, 0, sizeof(SearchData));
1181            Data.iEdgedWidth = iEdgedWidth;
1182            Data.currentMV = currentMV;
1183            Data.currentQMV = currentQMV;
1184            Data.iMinSAD = iMinSAD;
1185            Data.temp = temp;
1186            Data.dir = &dir;
1187            Data.iFcode = current->fcode;
1188            Data.rounding = pParam->m_rounding_type;
1189            Data.qpel = (current->vol_flags & XVID_VOL_QUARTERPEL ? 1:0);
1190            Data.chroma = MotionFlags & XVID_ME_CHROMA_PVOP;
1191            Data.rrv = (current->vop_flags & XVID_VOP_REDUCED) ? 1:0;
1192            Data.dctSpace = dct_space;
1193            Data.quant_type = !(pParam->vol_flags & XVID_VOL_MPEGQUANT);
1194    
1195            if ((current->vop_flags & XVID_VOP_REDUCED)) {
1196                    mb_width = (pParam->width + 31) / 32;
1197                    mb_height = (pParam->height + 31) / 32;
1198                    Data.qpel = 0;
1199            }
1200    
1201            Data.RefQ = pRefV->u; /* a good place, also used in MC (for similar purpose) */
1202            if (sadInit) (*sadInit) ();
1203    
1204            for (y = 0; y < mb_height; y++) {
1205                    for (x = 0; x < mb_width; x++)  {
1206                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1207    
1208                            if (!Data.rrv) pMB->sad16 =
1209                                    sad16v(pCurrent->y + (x + y * iEdgedWidth) * 16,
1210                                                            pRef->y + (x + y * iEdgedWidth) * 16,
1211                                                            pParam->edged_width, pMB->sad8 );
1212    
1213                            else pMB->sad16 =
1214                                    sad32v_c(pCurrent->y + (x + y * iEdgedWidth) * 32,
1215                                                            pRef->y + (x + y * iEdgedWidth) * 32,
1216                                                            pParam->edged_width, pMB->sad8 );
1217    
1218                            if (Data.chroma) {
1219                                    Data.temp[7] = sad8(pCurrent->u + x*8 + y*(iEdgedWidth/2)*8,
1220                                                                            pRef->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2)
1221                                                                    + sad8(pCurrent->v + (x + y*(iEdgedWidth/2))*8,
1222                                                                            pRef->v + (x + y*(iEdgedWidth/2))*8, iEdgedWidth/2);
1223                                    pMB->sad16 += Data.temp[7];
1224                            }
1225    
1226                            sad00 = pMB->sad16;
1227    
1228                            /* initial skip decision */
1229                            /* no early skip for GMC (global vector = skip vector is unknown!)  */
1230                            if (current->coding_type != S_VOP)      { /* no fast SKIP for S(GMC)-VOPs */
1231                                    if (pMB->dquant == 0 && sad00 < pMB->quant * skip_thresh)
1232                                            if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, iEdgedWidth/2, pMB->quant, Data.rrv)) {
1233                                                    ZeroMacroblockP(pMB, sad00);
1234                                                    pMB->mode = MODE_NOT_CODED;
1235                                                    continue;
1236                                            }
1237                            }
1238    
1239          int32_t iSAD;                          if ((current->vop_flags & XVID_VOP_CARTOON) &&
1240          VECTOR backupMV = *currMV;                                  (sad00 < pMB->quant * 4 * skip_thresh)) { /* favorize (0,0) vector for cartoons */
1241                                    ZeroMacroblockP(pMB, sad00);
1242                                    continue;
1243                            }
1244    
1245          CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y-1);                          SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1246          CHECK_MV16_CANDIDATE(backupMV.x  ,backupMV.y-1);                                          y, MotionFlags, current->vop_flags, current->vol_flags,
1247          CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y-1);                                          &Data, pParam, pMBs, reference->mbs, pMB);
1248          CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y);  
1249          CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y);                          ModeDecision(&Data, pMB, pMBs, x, y, pParam,
1250          CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y+1);                                                   MotionFlags, current->vop_flags, current->vol_flags,
1251          CHECK_MV16_CANDIDATE(backupMV.x  ,backupMV.y+1);                                                   pCurrent, pRef, pGMC, current->coding_type);
         CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y+1);  
1252    
1253          return iMinSAD;                          if (pMB->mode == MODE_INTRA)
1254                                    if (++iIntra > iLimit) return 1;
1255                    }
1256  }  }
1257    
1258  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)          return 0;
1259    }
1260    
1261    /* check if given vector is equal to any vector checked before */
1262    static __inline int
1263    vector_repeats(const VECTOR * const pmv, const int i)
1264    {
1265            unsigned int j;
1266            for (j = 0; j < i; j++)
1267                    if (MVequal(pmv[i], pmv[j])) return 1; /* same vector has been checked already */
1268            return 0;
1269    }
1270    
1271  int32_t PMVfastSearch16(  /*      make a binary mask that prevents diamonds/squares
1272                                          const uint8_t * const pRef,          from checking a vector which has been checked as a prediction */
1273    static __inline int
1274    make_mask(const VECTOR * const pmv, const int i, const int current)
1275    {
1276            unsigned int mask = 255, j;
1277            for (j = 0; j < i; j++) {
1278                    if (pmv[current].x == pmv[j].x) {
1279                            if (pmv[current].y == pmv[j].y + iDiamondSize) mask &= ~4;
1280                            else if (pmv[current].y == pmv[j].y - iDiamondSize) mask &= ~8;
1281                    } else
1282                            if (pmv[current].y == pmv[j].y) {
1283                                    if (pmv[current].x == pmv[j].x + iDiamondSize) mask &= ~1;
1284                                    else if (pmv[current].x == pmv[j].x - iDiamondSize) mask &= ~2;
1285                            }
1286            }
1287            return mask;
1288    }
1289    
1290    static __inline void
1291    PreparePredictionsP(VECTOR * const pmv, int x, int y, int iWcount,
1292                            int iHcount, const MACROBLOCK * const prevMB, int rrv)
1293    {
1294            /* this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself */
1295            if (rrv) { iWcount /= 2; iHcount /= 2; }
1296    
1297            if ( (y != 0) && (x < (iWcount-1)) ) {          /* [5] top-right neighbour */
1298                    pmv[5].x = EVEN(pmv[3].x);
1299                    pmv[5].y = EVEN(pmv[3].y);
1300            } else pmv[5].x = pmv[5].y = 0;
1301    
1302            if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }/* pmv[3] is left neighbour */
1303            else pmv[3].x = pmv[3].y = 0;
1304    
1305            if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }/* [4] top neighbour */
1306            else pmv[4].x = pmv[4].y = 0;
1307    
1308            /* [1] median prediction */
1309            pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
1310    
1311            pmv[0].x = pmv[0].y = 0; /* [0] is zero; not used in the loop (checked before) but needed here for make_mask */
1312    
1313            pmv[2].x = EVEN(prevMB->mvs[0].x); /* [2] is last frame */
1314            pmv[2].y = EVEN(prevMB->mvs[0].y);
1315    
1316            if ((x < iWcount-1) && (y < iHcount-1)) {
1317                    pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); /* [6] right-down neighbour in last frame */
1318                    pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
1319            } else pmv[6].x = pmv[6].y = 0;
1320    
1321            if (rrv) {
1322                    int i;
1323                    for (i = 0; i < 7; i++) {
1324                            pmv[i].x = RRV_MV_SCALEUP(pmv[i].x);
1325                            pmv[i].y = RRV_MV_SCALEUP(pmv[i].y);
1326                    }
1327            }
1328    }
1329    
1330    static void
1331    SearchP(const IMAGE * const pRef,
1332                                          const uint8_t * const pRefH,                                          const uint8_t * const pRefH,
1333                                          const uint8_t * const pRefV,                                          const uint8_t * const pRefV,
1334                                          const uint8_t * const pRefHV,                                          const uint8_t * const pRefHV,
1335                                          const IMAGE * const pCur,                                          const IMAGE * const pCur,
1336                                          const int x, const int y,                  const int x,
1337                    const int y,
1338                                          const uint32_t MotionFlags,                                          const uint32_t MotionFlags,
1339                    const uint32_t VopFlags,
1340                    const uint32_t VolFlags,
1341                    SearchData * const Data,
1342                                          const MBParam * const pParam,                                          const MBParam * const pParam,
1343                                          MACROBLOCK * const pMBs,                  const MACROBLOCK * const pMBs,
1344                                          VECTOR * const currMV,                  const MACROBLOCK * const prevMBs,
1345                                          VECTOR * const currPMV)                  MACROBLOCK * const pMB)
1346  {  {
1347          const uint32_t iWcount = pParam->mb_width;  
1348          const int32_t iFcode = pParam->fixed_code;          int i, threshA;
1349          const int32_t iQuant = pParam->quant;          VECTOR pmv[7];
1350          const int32_t iWidth = pParam->width;          int inter4v = (VopFlags & XVID_VOP_INTER4V) && (pMB->dquant == 0);
1351          const int32_t iHeight = pParam->height;          CheckFunc * CheckCandidate;
1352          const int32_t iEdgedWidth = pParam->edged_width;  
1353            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
1354                                                    pParam->width, pParam->height, Data->iFcode - Data->qpel, 1, Data->rrv);
1355    
1356            get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);
1357    
1358            Data->temp[5] = Data->temp[6] = 0; /* chroma-sad cache */
1359            i = Data->rrv ? 2 : 1;
1360            Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16*i;
1361            Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1362            Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1363    
1364            Data->RefP[0] = pRef->y + (x + Data->iEdgedWidth*y) * 16*i;
1365            Data->RefP[2] = pRefH + (x + Data->iEdgedWidth*y) * 16*i;
1366            Data->RefP[1] = pRefV + (x + Data->iEdgedWidth*y) * 16*i;
1367            Data->RefP[3] = pRefHV + (x + Data->iEdgedWidth*y) * 16*i;
1368            Data->RefP[4] = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1369            Data->RefP[5] = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1370    
1371            Data->lambda16 = lambda_vec16[pMB->quant];
1372            Data->lambda8 = lambda_vec8[pMB->quant];
1373            Data->qpel_precision = 0;
1374            *Data->dir = 0;
1375    
1376            memset(Data->currentMV, 0, 5*sizeof(VECTOR));
1377    
1378            if (Data->qpel) Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1379            else Data->predMV = pmv[0];
1380    
1381            i = d_mv_bits(0, 0, Data->predMV, Data->iFcode, 0, 0);
1382            Data->iMinSAD[0] = pMB->sad16 + ((Data->lambda16 * i * pMB->sad16)>>10);
1383            Data->iMinSAD[1] = pMB->sad8[0] + ((Data->lambda8 * i * (pMB->sad8[0]+NEIGH_8X8_BIAS)) >> 10);
1384            Data->iMinSAD[2] = pMB->sad8[1];
1385            Data->iMinSAD[3] = pMB->sad8[2];
1386            Data->iMinSAD[4] = pMB->sad8[3];
1387    
1388          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;          if ((!(VopFlags & XVID_VOP_MODEDECISION_RD)) && (x | y)) {
1389                    threshA = Data->temp[0]; /* that's where we keep this SAD atm */
1390                    if (threshA < 512) threshA = 512;
1391                    else if (threshA > 1024) threshA = 1024;
1392            } else
1393                    threshA = 512;
1394    
1395          int32_t iDiamondSize;          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
1396                                            prevMBs + x + y * pParam->mb_width, Data->rrv);
1397    
1398          int32_t min_dx;          if (!Data->rrv) {
1399          int32_t max_dx;                  if (inter4v) CheckCandidate = CheckCandidate16;
1400          int32_t min_dy;                          else CheckCandidate = CheckCandidate16no4v; /* for extra speed */
1401          int32_t max_dy;          } else CheckCandidate = CheckCandidate32;
1402    
1403          int32_t iFound;  /* main loop. checking all predictions (but first, which is 0,0 and has been checked in MotionEstimation())*/
1404    
1405          VECTOR newMV;          for (i = 1; i < 7; i++)
1406          VECTOR backupMV;        /* just for PMVFAST */                  if (!vector_repeats(pmv, i)) {
1407                            CheckCandidate(pmv[i].x, pmv[i].y, Data, i);
1408                            if (Data->iMinSAD[0] <= threshA) { i++; break; }
1409                    }
1410    
1411          VECTOR pmv[4];          if ((Data->iMinSAD[0] <= threshA) ||
1412          int32_t psad[4];                          (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
1413                            (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16)))
1414                    inter4v = 0;
1415            else {
1416    
1417          MACROBLOCK * const pMB = pMBs + x + y * iWcount;                  MainSearchFunc * MainSearchPtr;
1418                    int mask = make_mask(pmv, i, *Data->dir); // all vectors pmv[0..i-1] have been checked
1419    
1420          static int32_t threshA,threshB;                  if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1421          int32_t bPredEq;                  else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1422          int32_t iMinSAD,iSAD;                          else MainSearchPtr = DiamondSearch;
1423    
1424  /* Get maximum range */                  MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, mask, CheckCandidate);
         get_range(&min_dx, &max_dx, &min_dy, &max_dy,  
                   x, y, 16, iWidth, iHeight, iFcode);  
1425    
1426  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  /* extended search, diamond starting in 0,0 and in prediction.
1427            note that this search is/might be done in halfpel positions,
1428            which makes it more different than the diamond above */
1429    
1430          if (!(MotionFlags & PMV_HALFPEL16 ))                  if (MotionFlags & XVID_ME_EXTSEARCH16) {
1431          { min_dx = EVEN(min_dx);                          int32_t bSAD;
1432          max_dx = EVEN(max_dx);                          VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
1433          min_dy = EVEN(min_dy);                          if (Data->rrv) {
1434          max_dy = EVEN(max_dy);                                  startMV.x = RRV_MV_SCALEUP(startMV.x);
1435          }               /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */                                  startMV.y = RRV_MV_SCALEUP(startMV.y);
1436                            }
1437                            if (!(MVequal(startMV, backupMV))) {
1438                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1439    
1440                                    CheckCandidate(startMV.x, startMV.y, Data, 255);
1441                                    MainSearchPtr(startMV.x, startMV.y, Data, 255, CheckCandidate);
1442                                    if (bSAD < Data->iMinSAD[0]) {
1443                                            Data->currentMV[0] = backupMV;
1444                                            Data->iMinSAD[0] = bSAD; }
1445                            }
1446    
1447          bPredEq  = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);                          backupMV = Data->currentMV[0];
1448                            startMV.x = startMV.y = 1;
1449                            if (!(MVequal(startMV, backupMV))) {
1450                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1451    
1452          if ((x==0) && (y==0) )                                  CheckCandidate(startMV.x, startMV.y, Data, 255);
1453          {                                  MainSearchPtr(startMV.x, startMV.y, Data, 255, CheckCandidate);
1454                  threshA =  512;                                  if (bSAD < Data->iMinSAD[0]) {
1455                  threshB = 1024;                                          Data->currentMV[0] = backupMV;
1456                                            Data->iMinSAD[0] = bSAD;
1457                                    }
1458                            }
1459                    }
1460            }
1461    
1462            if (MotionFlags & XVID_ME_HALFPELREFINE16)
1463                            SubpelRefine(Data, CheckCandidate);
1464    
1465            for(i = 0; i < 5; i++) {
1466                    Data->currentQMV[i].x = 2 * Data->currentMV[i].x; /* initialize qpel vectors */
1467                    Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
1468            }
1469    
1470            if (Data->qpel) {
1471                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
1472                                    pParam->width, pParam->height, Data->iFcode, 2, 0);
1473                    Data->qpel_precision = 1;
1474                    if (MotionFlags & XVID_ME_QUARTERPELREFINE16)
1475                            SubpelRefine(Data, CheckCandidate);
1476            }
1477    
1478            if (Data->iMinSAD[0] < (int32_t)pMB->quant * 30)
1479                    inter4v = 0;
1480    
1481            if (inter4v) {
1482                    SearchData Data8;
1483                    memcpy(&Data8, Data, sizeof(SearchData)); /* quick copy of common data */
1484    
1485                    Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
1486                    Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
1487                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
1488                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
1489    
1490                    if ((Data->chroma) && (!(VopFlags & XVID_VOP_MODEDECISION_RD))) {
1491                            /* chroma is only used for comparsion to INTER. if the comparsion will be done in BITS domain, it will not be used */
1492                            int sumx = 0, sumy = 0;
1493    
1494                            if (Data->qpel)
1495                                    for (i = 1; i < 5; i++) {
1496                                            sumx += Data->currentQMV[i].x/2;
1497                                            sumy += Data->currentQMV[i].y/2;
1498          }          }
1499          else          else
1500                                    for (i = 1; i < 5; i++) {
1501                                            sumx += Data->currentMV[i].x;
1502                                            sumy += Data->currentMV[i].y;
1503                                    }
1504    
1505                            Data->iMinSAD[1] += ChromaSAD(  (sumx >> 3) + roundtab_76[sumx & 0xf],
1506                                                                                            (sumy >> 3) + roundtab_76[sumy & 0xf], Data);
1507                    }
1508            } else Data->iMinSAD[1] = 4096*256;
1509    }
1510    
1511    static void
1512    Search8(const SearchData * const OldData,
1513                    const int x, const int y,
1514                    const uint32_t MotionFlags,
1515                    const MBParam * const pParam,
1516                    MACROBLOCK * const pMB,
1517                    const MACROBLOCK * const pMBs,
1518                    const int block,
1519                    SearchData * const Data)
1520          {          {
1521                  threshA = psad[0];          int i = 0;
1522                  threshB = threshA+256;          CheckFunc * CheckCandidate;
1523                  if (threshA< 512) threshA =  512;          Data->iMinSAD = OldData->iMinSAD + 1 + block;
1524                  if (threshA>1024) threshA = 1024;          Data->currentMV = OldData->currentMV + 1 + block;
1525                  if (threshB>1792) threshB = 1792;          Data->currentQMV = OldData->currentQMV + 1 + block;
1526    
1527            if(Data->qpel) {
1528                    Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1529                    if (block != 0) i = d_mv_bits(  Data->currentQMV->x, Data->currentQMV->y,
1530                                                                                    Data->predMV, Data->iFcode, 0, 0);
1531            } else {
1532                    Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1533                    if (block != 0) i = d_mv_bits(  Data->currentMV->x, Data->currentMV->y,
1534                                                                                    Data->predMV, Data->iFcode, 0, Data->rrv);
1535          }          }
1536    
1537          iFound=0;          *(Data->iMinSAD) += (Data->lambda8 * i * (*Data->iMinSAD + NEIGH_8X8_BIAS))>>10;
1538    
1539  /* Step 2: Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion          if (MotionFlags & (XVID_ME_EXTSEARCH8|XVID_ME_HALFPELREFINE8|XVID_ME_QUARTERPELREFINE8)) {
    vector of the median.  
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
1540    
1541          if ((bPredEq) && (MVequal(pmv[0],pMB->mvs[0]) ) )                  if (Data->rrv) i = 16; else i = 8;
                 iFound=2;  
1542    
1543  /* Step 3: If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.                  Data->RefP[0] = OldData->RefP[0] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1544     Otherwise select large Diamond Search.                  Data->RefP[1] = OldData->RefP[1] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1545  */                  Data->RefP[2] = OldData->RefP[2] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1546                    Data->RefP[3] = OldData->RefP[3] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1547    
1548          if ( (pmv[0].x != 0) || (pmv[0].y != 0) || (threshB<1536) || (bPredEq) )                  Data->Cur = OldData->Cur + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1549                  iDiamondSize=1; // halfpel!                  Data->qpel_precision = 0;
         else  
                 iDiamondSize=2; // halfpel!  
1550    
1551          if (!(MotionFlags & PMV_HALFPELDIAMOND16) )                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 3,
1552                  iDiamondSize*=2;                                          pParam->width, pParam->height, Data->iFcode - Data->qpel, 1, Data->rrv);
1553    
1554  /* Step 4: Calculate SAD around the Median prediction.                  if (!Data->rrv) CheckCandidate = CheckCandidate8;
1555     MinSAD=SAD                  else CheckCandidate = CheckCandidate16no4v;
1556     If Motion Vector equal to Previous frame motion vector  
1557     and MinSAD<PrevFrmSAD goto Step 10.                  if (MotionFlags & XVID_ME_EXTSEARCH8 && (!(MotionFlags & XVID_ME_EXTSEARCH_RD))) {
1558     If SAD<=256 goto Step 10.                          int32_t temp_sad = *(Data->iMinSAD); /* store current MinSAD */
 */  
1559    
1560                            MainSearchFunc *MainSearchPtr;
1561                            if (MotionFlags & XVID_ME_USESQUARES8) MainSearchPtr = SquareSearch;
1562                                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1563                                            else MainSearchPtr = DiamondSearch;
1564    
1565  // Prepare for main loop                          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, 255, CheckCandidate);
1566    
1567          *currMV=pmv[0];         /* current best := prediction */                          if(*(Data->iMinSAD) < temp_sad) {
1568          if (!(MotionFlags & PMV_HALFPEL16 ))                                          Data->currentQMV->x = 2 * Data->currentMV->x; /* update our qpel vector */
1569          {       /* This should NOT be necessary! */                                          Data->currentQMV->y = 2 * Data->currentMV->y;
1570                  currMV->x = EVEN(currMV->x);                          }
                 currMV->y = EVEN(currMV->y);  
1571          }          }
1572    
1573          if (currMV->x > max_dx)                  if (MotionFlags & XVID_ME_HALFPELREFINE8) {
1574          {                          int32_t temp_sad = *(Data->iMinSAD); /* store current MinSAD */
1575                  currMV->x=max_dx;  
1576                            SubpelRefine(Data, CheckCandidate); /* perform halfpel refine of current best vector */
1577    
1578                            if(*(Data->iMinSAD) < temp_sad) { /* we have found a better match */
1579                                    Data->currentQMV->x = 2 * Data->currentMV->x; /* update our qpel vector */
1580                                    Data->currentQMV->y = 2 * Data->currentMV->y;
1581          }          }
         if (currMV->x < min_dx)  
         {  
                 currMV->x=min_dx;  
1582          }          }
1583          if (currMV->y > max_dy)  
1584                    if (Data->qpel && MotionFlags & XVID_ME_QUARTERPELREFINE8) {
1585                                    Data->qpel_precision = 1;
1586                                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 3,
1587                                            pParam->width, pParam->height, Data->iFcode, 2, 0);
1588                                    SubpelRefine(Data, CheckCandidate);
1589                    }
1590            }
1591    
1592            if (Data->rrv) {
1593                            Data->currentMV->x = RRV_MV_SCALEDOWN(Data->currentMV->x);
1594                            Data->currentMV->y = RRV_MV_SCALEDOWN(Data->currentMV->y);
1595            }
1596    
1597            if(Data->qpel) {
1598                    pMB->pmvs[block].x = Data->currentQMV->x - Data->predMV.x;
1599                    pMB->pmvs[block].y = Data->currentQMV->y - Data->predMV.y;
1600                    pMB->qmvs[block] = *Data->currentQMV;
1601            } else {
1602                    pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1603                    pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
1604            }
1605    
1606            pMB->mvs[block] = *Data->currentMV;
1607            pMB->sad8[block] = 4 * *Data->iMinSAD;
1608    }
1609    
1610    /* motion estimation for B-frames */
1611    
1612    static __inline VECTOR
1613    ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1614          {          {
1615                  currMV->y=max_dy;  /* the stupidiest function ever */
1616            return (mode == MODE_FORWARD ? pMB->mvs[0] : pMB->b_mvs[0]);
1617          }          }
1618          if (currMV->y < min_dy)  
1619    static void __inline
1620    PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
1621                                                            const uint32_t iWcount,
1622                                                            const MACROBLOCK * const pMB,
1623                                                            const uint32_t mode_curr)
1624          {          {
1625                  currMV->y=min_dy;  
1626            /* [0] is prediction */
1627            pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
1628    
1629            pmv[1].x = pmv[1].y = 0; /* [1] is zero */
1630    
1631            pmv[2] = ChoosePred(pMB, mode_curr);
1632            pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
1633    
1634            if ((y != 0)&&(x != (int)(iWcount+1))) {                        /* [3] top-right neighbour */
1635                    pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
1636                    pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
1637            } else pmv[3].x = pmv[3].y = 0;
1638    
1639            if (y != 0) {
1640                    pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
1641                    pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
1642            } else pmv[4].x = pmv[4].y = 0;
1643    
1644            if (x != 0) {
1645                    pmv[5] = ChoosePred(pMB-1, mode_curr);
1646                    pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1647            } else pmv[5].x = pmv[5].y = 0;
1648    
1649            if (x != 0 && y != 0) {
1650                    pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
1651                    pmv[6].x = EVEN(pmv[6].x); pmv[6].y = EVEN(pmv[6].y);
1652            } else pmv[6].x = pmv[6].y = 0;
1653    }
1654    
1655    
1656    /* search backward or forward */
1657    static void
1658    SearchBF(       const IMAGE * const pRef,
1659                            const uint8_t * const pRefH,
1660                            const uint8_t * const pRefV,
1661                            const uint8_t * const pRefHV,
1662                            const IMAGE * const pCur,
1663                            const int x, const int y,
1664                            const uint32_t MotionFlags,
1665                            const uint32_t iFcode,
1666                            const MBParam * const pParam,
1667                            MACROBLOCK * const pMB,
1668                            const VECTOR * const predMV,
1669                            int32_t * const best_sad,
1670                            const int32_t mode_current,
1671                            SearchData * const Data)
1672    {
1673    
1674            int i;
1675            VECTOR pmv[7];
1676            MainSearchFunc *MainSearchPtr;
1677            *Data->iMinSAD = MV_MAX_ERROR;
1678            Data->iFcode = iFcode;
1679            Data->qpel_precision = 0;
1680            Data->temp[5] = Data->temp[6] = Data->temp[7] = 256*4096; /* reset chroma-sad cache */
1681    
1682            Data->RefP[0] = pRef->y + (x + Data->iEdgedWidth*y) * 16;
1683            Data->RefP[2] = pRefH + (x + Data->iEdgedWidth*y) * 16;
1684            Data->RefP[1] = pRefV + (x + Data->iEdgedWidth*y) * 16;
1685            Data->RefP[3] = pRefHV + (x + Data->iEdgedWidth*y) * 16;
1686            Data->RefP[4] = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8;
1687            Data->RefP[5] = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8;
1688    
1689            Data->predMV = *predMV;
1690    
1691            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
1692                                    pParam->width, pParam->height, iFcode - Data->qpel, 1, 0);
1693    
1694            pmv[0] = Data->predMV;
1695            if (Data->qpel) { pmv[0].x /= 2; pmv[0].y /= 2; }
1696    
1697            PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);
1698    
1699            Data->currentMV->x = Data->currentMV->y = 0;
1700    
1701            /* main loop. checking all predictions */
1702            for (i = 0; i < 7; i++)
1703                    if (!vector_repeats(pmv, i) )
1704                            CheckCandidate16no4v(pmv[i].x, pmv[i].y, Data, i);
1705    
1706            if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1707            else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1708                    else MainSearchPtr = DiamondSearch;
1709    
1710            if (*Data->iMinSAD > 512) {
1711                    unsigned int mask = make_mask(pmv, 7, *Data->dir);
1712                    MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, mask, CheckCandidate16no4v);
1713            }
1714    
1715            SubpelRefine(Data, CheckCandidate16no4v);
1716    
1717            if (Data->qpel && *Data->iMinSAD < *best_sad + 300) {
1718                    Data->currentQMV->x = 2*Data->currentMV->x;
1719                    Data->currentQMV->y = 2*Data->currentMV->y;
1720                    Data->qpel_precision = 1;
1721                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
1722                                            pParam->width, pParam->height, iFcode, 2, 0);
1723                    SubpelRefine(Data, CheckCandidate16no4v);
1724            }
1725    
1726            /* three bits are needed to code backward mode. four for forward */
1727    
1728            if (mode_current == MODE_FORWARD) *Data->iMinSAD += 4 * Data->lambda16;
1729            else *Data->iMinSAD += 3 * Data->lambda16;
1730    
1731            if (*Data->iMinSAD < *best_sad) {
1732                    *best_sad = *Data->iMinSAD;
1733                    pMB->mode = mode_current;
1734                    if (Data->qpel) {
1735                            pMB->pmvs[0].x = Data->currentQMV->x - predMV->x;
1736                            pMB->pmvs[0].y = Data->currentQMV->y - predMV->y;
1737                            if (mode_current == MODE_FORWARD)
1738                                    pMB->qmvs[0] = *Data->currentQMV;
1739                            else
1740                                    pMB->b_qmvs[0] = *Data->currentQMV;
1741                    } else {
1742                            pMB->pmvs[0].x = Data->currentMV->x - predMV->x;
1743                            pMB->pmvs[0].y = Data->currentMV->y - predMV->y;
1744                    }
1745                    if (mode_current == MODE_FORWARD) pMB->mvs[0] = *Data->currentMV;
1746                    else pMB->b_mvs[0] = *Data->currentMV;
1747          }          }
1748    
1749          iMinSAD = sad16( cur,          if (mode_current == MODE_FORWARD) *(Data->currentMV+2) = *Data->currentMV;
1750                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV, iEdgedWidth),          else *(Data->currentMV+1) = *Data->currentMV; /* we store currmv for interpolate search */
1751                           iEdgedWidth, MV_MAX_ERROR);  }
         iMinSAD += calc_delta_16(currMV->x-pmv[0].x, currMV->y-pmv[0].y, (uint8_t)iFcode) * iQuant;  
1752    
1753          if ( (iMinSAD < 256 ) || ( (MVequal(*currMV,pMB->mvs[0])) && (iMinSAD < pMB->sad16) ) )  static void
1754    SkipDecisionB(const IMAGE * const pCur,
1755                                    const IMAGE * const f_Ref,
1756                                    const IMAGE * const b_Ref,
1757                                    MACROBLOCK * const pMB,
1758                                    const uint32_t x, const uint32_t y,
1759                                    const SearchData * const Data)
1760          {          {
1761            int dx = 0, dy = 0, b_dx = 0, b_dy = 0;
1762            int32_t sum;
1763            int k;
1764            const uint32_t stride = Data->iEdgedWidth/2;
1765            /* this is not full chroma compensation, only it's fullpel approximation. should work though */
1766    
1767            for (k = 0; k < 4; k++) {
1768                    dy += Data->directmvF[k].y >> Data->qpel;
1769                    dx += Data->directmvF[k].x >> Data->qpel;
1770                    b_dy += Data->directmvB[k].y >> Data->qpel;
1771                    b_dx += Data->directmvB[k].x >> Data->qpel;
1772            }
1773    
1774            dy = (dy >> 3) + roundtab_76[dy & 0xf];
1775            dx = (dx >> 3) + roundtab_76[dx & 0xf];
1776            b_dy = (b_dy >> 3) + roundtab_76[b_dy & 0xf];
1777            b_dx = (b_dx >> 3) + roundtab_76[b_dx & 0xf];
1778    
1779            sum = sad8bi(pCur->u + 8 * x + 8 * y * stride,
1780                                            f_Ref->u + (y*8 + dy/2) * stride + x*8 + dx/2,
1781                                            b_Ref->u + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1782                                            stride);
1783    
1784            if (sum >= MAX_CHROMA_SAD_FOR_SKIP * Data->iQuant) return; /* no skip */
1785    
1786            sum += sad8bi(pCur->v + 8*x + 8 * y * stride,
1787                                            f_Ref->v + (y*8 + dy/2) * stride + x*8 + dx/2,
1788                                            b_Ref->v + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1789                                            stride);
1790    
1791            if (sum < MAX_CHROMA_SAD_FOR_SKIP * Data->iQuant) {
1792                    pMB->mode = MODE_DIRECT_NONE_MV; /* skipped */
1793                    for (k = 0; k < 4; k++) {
1794                            pMB->qmvs[k] = pMB->mvs[k];
1795                            pMB->b_qmvs[k] = pMB->b_mvs[k];
1796                    }
1797            }
1798    }
1799    
1800                  if (MotionFlags & PMV_QUICKSTOP16)  static __inline uint32_t
1801                          goto PMVfast16_Terminate_without_Refine;  SearchDirect(const IMAGE * const f_Ref,
1802                  if (MotionFlags & PMV_EARLYSTOP16)                                  const uint8_t * const f_RefH,
1803                          goto PMVfast16_Terminate_with_Refine;                                  const uint8_t * const f_RefV,
1804                                    const uint8_t * const f_RefHV,
1805                                    const IMAGE * const b_Ref,
1806                                    const uint8_t * const b_RefH,
1807                                    const uint8_t * const b_RefV,
1808                                    const uint8_t * const b_RefHV,
1809                                    const IMAGE * const pCur,
1810                                    const int x, const int y,
1811                                    const uint32_t MotionFlags,
1812                                    const int32_t TRB, const int32_t TRD,
1813                                    const MBParam * const pParam,
1814                                    MACROBLOCK * const pMB,
1815                                    const MACROBLOCK * const b_mb,
1816                                    int32_t * const best_sad,
1817                                    SearchData * const Data)
1818    
1819    {
1820            int32_t skip_sad;
1821            int k = (x + Data->iEdgedWidth*y) * 16;
1822            MainSearchFunc *MainSearchPtr;
1823            CheckFunc * CheckCandidate;
1824    
1825            *Data->iMinSAD = 256*4096;
1826            Data->RefP[0] = f_Ref->y + k;
1827            Data->RefP[2] = f_RefH + k;
1828            Data->RefP[1] = f_RefV + k;
1829            Data->RefP[3] = f_RefHV + k;
1830            Data->b_RefP[0] = b_Ref->y + k;
1831            Data->b_RefP[2] = b_RefH + k;
1832            Data->b_RefP[1] = b_RefV + k;
1833            Data->b_RefP[3] = b_RefHV + k;
1834            Data->RefP[4] = f_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1835            Data->RefP[5] = f_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1836            Data->b_RefP[4] = b_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1837            Data->b_RefP[5] = b_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1838    
1839            k = Data->qpel ? 4 : 2;
1840            Data->max_dx = k * (pParam->width - x * 16);
1841            Data->max_dy = k * (pParam->height - y * 16);
1842            Data->min_dx = -k * (16 + x * 16);
1843            Data->min_dy = -k * (16 + y * 16);
1844    
1845            Data->referencemv = Data->qpel ? b_mb->qmvs : b_mb->mvs;
1846            Data->qpel_precision = 0;
1847    
1848            for (k = 0; k < 4; k++) {
1849                    pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);
1850                    pMB->b_mvs[k].x = Data->directmvB[k].x = ((TRB - TRD) * Data->referencemv[k].x) / TRD;
1851                    pMB->mvs[k].y = Data->directmvF[k].y = ((TRB * Data->referencemv[k].y) / TRD);
1852                    pMB->b_mvs[k].y = Data->directmvB[k].y = ((TRB - TRD) * Data->referencemv[k].y) / TRD;
1853    
1854                    if ( (pMB->b_mvs[k].x > Data->max_dx) | (pMB->b_mvs[k].x < Data->min_dx)
1855                            | (pMB->b_mvs[k].y > Data->max_dy) | (pMB->b_mvs[k].y < Data->min_dy) ) {
1856    
1857                            *best_sad = 256*4096; /* in that case, we won't use direct mode */
1858                            pMB->mode = MODE_DIRECT; /* just to make sure it doesn't say "MODE_DIRECT_NONE_MV" */
1859                            pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;
1860                            return 256*4096;
1861                    }
1862                    if (b_mb->mode != MODE_INTER4V) {
1863                            pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mvs[0];
1864                            pMB->b_mvs[1] = pMB->b_mvs[2] = pMB->b_mvs[3] = pMB->b_mvs[0];
1865                            Data->directmvF[1] = Data->directmvF[2] = Data->directmvF[3] = Data->directmvF[0];
1866                            Data->directmvB[1] = Data->directmvB[2] = Data->directmvB[3] = Data->directmvB[0];
1867                            break;
1868                    }
1869          }          }
1870    
1871            CheckCandidate = b_mb->mode == MODE_INTER4V ? CheckCandidateDirect : CheckCandidateDirectno4v;
1872    
1873            CheckCandidate(0, 0, Data, 255);
1874    
1875            /* initial (fast) skip decision */
1876            if (*Data->iMinSAD < Data->iQuant * INITIAL_SKIP_THRESH * (Data->chroma?3:2)) {
1877                    /* possible skip */
1878                    if (Data->chroma) {
1879                            pMB->mode = MODE_DIRECT_NONE_MV;
1880                            return *Data->iMinSAD; /* skip. */
1881                    } else {
1882                            SkipDecisionB(pCur, f_Ref, b_Ref, pMB, x, y, Data);
1883                            if (pMB->mode == MODE_DIRECT_NONE_MV) return *Data->iMinSAD; /* skip. */
1884                    }
1885            }
1886    
1887            *Data->iMinSAD += Data->lambda16;
1888            skip_sad = *Data->iMinSAD;
1889    
1890  /*  /*
1891     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.           * DIRECT MODE DELTA VECTOR SEARCH.
1892     Also calculate (0,0) but do not subtract offset.           * This has to be made more effective, but at the moment I'm happy it's running at all
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset. ******** WHAT'S THIS 'OFFSET' ??? ***********  
1893  */  */
1894    
1895  // (0,0) is always possible          if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1896                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1897          CHECK_MV16_ZERO;                          else MainSearchPtr = DiamondSearch;
1898    
1899  // previous frame MV is always possible          MainSearchPtr(0, 0, Data, 255, CheckCandidate);
1900          CHECK_MV16_CANDIDATE(pMB->mvs[0].x,pMB->mvs[0].y);  
1901            SubpelRefine(Data, CheckCandidate);
1902  // left neighbour, if allowed  
1903          if (x != 0)          *best_sad = *Data->iMinSAD;
1904          {  
1905                  if (!(MotionFlags & PMV_HALFPEL16 ))          if (Data->qpel || b_mb->mode == MODE_INTER4V) pMB->mode = MODE_DIRECT;
1906                  {       pmv[1].x = EVEN(pmv[1].x);          else pMB->mode = MODE_DIRECT_NO4V; /* for faster compensation */
1907                  pmv[1].y = EVEN(pmv[1].y);  
1908            pMB->pmvs[3] = *Data->currentMV;
1909    
1910            for (k = 0; k < 4; k++) {
1911                    pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
1912                    pMB->b_mvs[k].x = (     (Data->currentMV->x == 0)
1913                                                            ? Data->directmvB[k].x
1914                                                            :pMB->mvs[k].x - Data->referencemv[k].x);
1915                    pMB->mvs[k].y = (Data->directmvF[k].y + Data->currentMV->y);
1916                    pMB->b_mvs[k].y = ((Data->currentMV->y == 0)
1917                                                            ? Data->directmvB[k].y
1918                                                            : pMB->mvs[k].y - Data->referencemv[k].y);
1919                    if (Data->qpel) {
1920                            pMB->qmvs[k].x = pMB->mvs[k].x; pMB->mvs[k].x /= 2;
1921                            pMB->b_qmvs[k].x = pMB->b_mvs[k].x; pMB->b_mvs[k].x /= 2;
1922                            pMB->qmvs[k].y = pMB->mvs[k].y; pMB->mvs[k].y /= 2;
1923                            pMB->b_qmvs[k].y = pMB->b_mvs[k].y; pMB->b_mvs[k].y /= 2;
1924                    }
1925    
1926                    if (b_mb->mode != MODE_INTER4V) {
1927                            pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1928                            pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1929                            pMB->qmvs[3] = pMB->qmvs[2] = pMB->qmvs[1] = pMB->qmvs[0];
1930                            pMB->b_qmvs[3] = pMB->b_qmvs[2] = pMB->b_qmvs[1] = pMB->b_qmvs[0];
1931                            break;
1932                  }                  }
1933                  CHECK_MV16_CANDIDATE(pmv[1].x,pmv[1].y);          }
1934            return skip_sad;
1935          }          }
1936    
1937  // top neighbour, if allowed  static void
1938          if (y != 0)  SearchInterpolate(const IMAGE * const f_Ref,
1939          {                                  const uint8_t * const f_RefH,
1940                  if (!(MotionFlags & PMV_HALFPEL16 ))                                  const uint8_t * const f_RefV,
1941                  {       pmv[2].x = EVEN(pmv[2].x);                                  const uint8_t * const f_RefHV,
1942                  pmv[2].y = EVEN(pmv[2].y);                                  const IMAGE * const b_Ref,
1943                                    const uint8_t * const b_RefH,
1944                                    const uint8_t * const b_RefV,
1945                                    const uint8_t * const b_RefHV,
1946                                    const IMAGE * const pCur,
1947                                    const int x, const int y,
1948                                    const uint32_t fcode,
1949                                    const uint32_t bcode,
1950                                    const uint32_t MotionFlags,
1951                                    const MBParam * const pParam,
1952                                    const VECTOR * const f_predMV,
1953                                    const VECTOR * const b_predMV,
1954                                    MACROBLOCK * const pMB,
1955                                    int32_t * const best_sad,
1956                                    SearchData * const fData)
1957    
1958    {
1959    
1960            int i, j;
1961            SearchData bData;
1962    
1963            fData->qpel_precision = 0;
1964            memcpy(&bData, fData, sizeof(SearchData)); /* quick copy of common data */
1965            *fData->iMinSAD = 4096*256;
1966            bData.currentMV++; bData.currentQMV++;
1967            fData->iFcode = bData.bFcode = fcode; fData->bFcode = bData.iFcode = bcode;
1968    
1969            i = (x + y * fData->iEdgedWidth) * 16;
1970    
1971            bData.b_RefP[0] = fData->RefP[0] = f_Ref->y + i;
1972            bData.b_RefP[2] = fData->RefP[2] = f_RefH + i;
1973            bData.b_RefP[1] = fData->RefP[1] = f_RefV + i;
1974            bData.b_RefP[3] = fData->RefP[3] = f_RefHV + i;
1975            bData.RefP[0] = fData->b_RefP[0] = b_Ref->y + i;
1976            bData.RefP[2] = fData->b_RefP[2] = b_RefH + i;
1977            bData.RefP[1] = fData->b_RefP[1] = b_RefV + i;
1978            bData.RefP[3] = fData->b_RefP[3] = b_RefHV + i;
1979            bData.b_RefP[4] = fData->RefP[4] = f_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
1980            bData.b_RefP[5] = fData->RefP[5] = f_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
1981            bData.RefP[4] = fData->b_RefP[4] = b_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
1982            bData.RefP[5] = fData->b_RefP[5] = b_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
1983            bData.dir = fData->dir;
1984    
1985            bData.bpredMV = fData->predMV = *f_predMV;
1986            fData->bpredMV = bData.predMV = *b_predMV;
1987            fData->currentMV[0] = fData->currentMV[2];
1988    
1989            get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 4, pParam->width, pParam->height, fcode - fData->qpel, 1, 0);
1990            get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 4, pParam->width, pParam->height, bcode - fData->qpel, 1, 0);
1991    
1992            if (fData->currentMV[0].x > fData->max_dx) fData->currentMV[0].x = fData->max_dx;
1993            if (fData->currentMV[0].x < fData->min_dx) fData->currentMV[0].x = fData->min_dx;
1994            if (fData->currentMV[0].y > fData->max_dy) fData->currentMV[0].y = fData->max_dy;
1995            if (fData->currentMV[0].y < fData->min_dy) fData->currentMV[0].y = fData->min_dy;
1996    
1997            if (fData->currentMV[1].x > bData.max_dx) fData->currentMV[1].x = bData.max_dx;
1998            if (fData->currentMV[1].x < bData.min_dx) fData->currentMV[1].x = bData.min_dx;
1999            if (fData->currentMV[1].y > bData.max_dy) fData->currentMV[1].y = bData.max_dy;
2000            if (fData->currentMV[1].y < bData.min_dy) fData->currentMV[1].y = bData.min_dy;
2001    
2002            CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, fData, 255);
2003    
2004            /* diamond */
2005            do {
2006                    *fData->dir = 255;
2007                    /* forward MV moves */
2008                    i = fData->currentMV[0].x; j = fData->currentMV[0].y;
2009    
2010                    CheckCandidateInt(i + 1, j, fData, 0);
2011                    CheckCandidateInt(i, j + 1, fData, 0);
2012                    CheckCandidateInt(i - 1, j, fData, 0);
2013                    CheckCandidateInt(i, j - 1, fData, 0);
2014    
2015                    /* backward MV moves */
2016                    i = fData->currentMV[1].x; j = fData->currentMV[1].y;
2017                    fData->currentMV[2] = fData->currentMV[0];
2018                    CheckCandidateInt(i + 1, j, &bData, 0);
2019                    CheckCandidateInt(i, j + 1, &bData, 0);
2020                    CheckCandidateInt(i - 1, j, &bData, 0);
2021                    CheckCandidateInt(i, j - 1, &bData, 0);
2022    
2023            } while (!(*fData->dir));
2024    
2025            /* qpel refinement */
2026            if (fData->qpel) {
2027                    if (*fData->iMinSAD > *best_sad + 500) return;
2028                    fData->qpel_precision = bData.qpel_precision = 1;
2029                    get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 4, pParam->width, pParam->height, fcode, 2, 0);
2030                    get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 4, pParam->width, pParam->height, bcode, 2, 0);
2031                    fData->currentQMV[2].x = fData->currentQMV[0].x = 2 * fData->currentMV[0].x;
2032                    fData->currentQMV[2].y = fData->currentQMV[0].y = 2 * fData->currentMV[0].y;
2033                    fData->currentQMV[1].x = 2 * fData->currentMV[1].x;
2034                    fData->currentQMV[1].y = 2 * fData->currentMV[1].y;
2035                    SubpelRefine(fData, CheckCandidateInt);
2036                    if (*fData->iMinSAD > *best_sad + 300) return;
2037                    fData->currentQMV[2] = fData->currentQMV[0];
2038                    SubpelRefine(&bData, CheckCandidateInt);
2039            }
2040    
2041            *fData->iMinSAD += (2+3) * fData->lambda16; /* two bits are needed to code interpolate mode. */
2042    
2043            if (*fData->iMinSAD < *best_sad) {
2044                    *best_sad = *fData->iMinSAD;
2045                    pMB->mvs[0] = fData->currentMV[0];
2046                    pMB->b_mvs[0] = fData->currentMV[1];
2047                    pMB->mode = MODE_INTERPOLATE;
2048                    if (fData->qpel) {
2049                            pMB->qmvs[0] = fData->currentQMV[0];
2050                            pMB->b_qmvs[0] = fData->currentQMV[1];
2051                            pMB->pmvs[1].x = pMB->qmvs[0].x - f_predMV->x;
2052                            pMB->pmvs[1].y = pMB->qmvs[0].y - f_predMV->y;
2053                            pMB->pmvs[0].x = pMB->b_qmvs[0].x - b_predMV->x;
2054                            pMB->pmvs[0].y = pMB->b_qmvs[0].y - b_predMV->y;
2055                    } else {
2056                            pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;
2057                            pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;
2058                            pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;
2059                            pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;
2060                    }
2061            }
2062    }
2063    
2064    void
2065    MotionEstimationBVOP(MBParam * const pParam,
2066                                             FRAMEINFO * const frame,
2067                                             const int32_t time_bp,
2068                                             const int32_t time_pp,
2069                                             /* forward (past) reference */
2070                                             const MACROBLOCK * const f_mbs,
2071                                             const IMAGE * const f_ref,
2072                                             const IMAGE * const f_refH,
2073                                             const IMAGE * const f_refV,
2074                                             const IMAGE * const f_refHV,
2075                                             /* backward (future) reference */
2076                                             const FRAMEINFO * const b_reference,
2077                                             const IMAGE * const b_ref,
2078                                             const IMAGE * const b_refH,
2079                                             const IMAGE * const b_refV,
2080                                             const IMAGE * const b_refHV)
2081    {
2082            uint32_t i, j;
2083            int32_t best_sad;
2084            uint32_t skip_sad;
2085            int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;
2086            const MACROBLOCK * const b_mbs = b_reference->mbs;
2087    
2088            VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
2089    
2090            const int32_t TRB = time_pp - time_bp;
2091            const int32_t TRD = time_pp;
2092    
2093            /* some pre-inintialized data for the rest of the search */
2094    
2095            SearchData Data;
2096            int32_t iMinSAD;
2097            uint32_t dir;
2098            VECTOR currentMV[3];
2099            VECTOR currentQMV[3];
2100            int32_t temp[8];
2101            memset(&Data, 0, sizeof(SearchData));
2102            Data.iEdgedWidth = pParam->edged_width;
2103            Data.currentMV = currentMV; Data.currentQMV = currentQMV;
2104            Data.iMinSAD = &iMinSAD;
2105            Data.lambda16 = lambda_vec16[MAX(frame->quant-2, 2)];
2106            Data.qpel = pParam->vol_flags & XVID_VOL_QUARTERPEL ? 1 : 0;
2107            Data.rounding = 0;
2108            Data.chroma = frame->motion_flags & XVID_ME_CHROMA_BVOP;
2109            Data.temp = temp;
2110            Data.dir = &dir;
2111            Data.iQuant = frame->quant;
2112    
2113            Data.RefQ = f_refV->u; /* a good place, also used in MC (for similar purpose) */
2114    
2115            /* note: i==horizontal, j==vertical */
2116            for (j = 0; j < pParam->mb_height; j++) {
2117    
2118                    f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
2119    
2120                    for (i = 0; i < pParam->mb_width; i++) {
2121                            MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
2122                            const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
2123    
2124    /* special case, if collocated block is SKIPed in P-VOP: encoding is forward (0,0), cpb=0 without further ado */
2125                            if (b_reference->coding_type != S_VOP)
2126                                    if (b_mb->mode == MODE_NOT_CODED) {
2127                                            pMB->mode = MODE_NOT_CODED;
2128                                            continue;
2129                  }                  }
                 CHECK_MV16_CANDIDATE(pmv[2].x,pmv[2].y);  
2130    
2131  // top right neighbour, if allowed                          Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
2132                  if (x != (iWcount-1))                          Data.CurU = frame->image.u + (j * Data.iEdgedWidth/2 + i) * 8;
2133                  {                          Data.CurV = frame->image.v + (j * Data.iEdgedWidth/2 + i) * 8;
2134                          if (!(MotionFlags & PMV_HALFPEL16 ))  
2135                          {       pmv[3].x = EVEN(pmv[3].x);  /* direct search comes first, because it (1) checks for SKIP-mode
2136                          pmv[3].y = EVEN(pmv[3].y);          and (2) sets very good predictions for forward and backward search */
2137                            skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2138                                                                            b_ref, b_refH->y, b_refV->y, b_refHV->y,
2139                                                                            &frame->image,
2140                                                                            i, j,
2141                                                                            frame->motion_flags,
2142                                                                            TRB, TRD,
2143                                                                            pParam,
2144                                                                            pMB, b_mb,
2145                                                                            &best_sad,
2146                                                                            &Data);
2147    
2148                            if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
2149    
2150                            /* forward search */
2151                            SearchBF(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2152                                                    &frame->image, i, j,
2153                                                    frame->motion_flags,
2154                                                    frame->fcode, pParam,
2155                                                    pMB, &f_predMV, &best_sad,
2156                                                    MODE_FORWARD, &Data);
2157    
2158                            /* backward search */
2159                            SearchBF(b_ref, b_refH->y, b_refV->y, b_refHV->y,
2160                                                    &frame->image, i, j,
2161                                                    frame->motion_flags,
2162                                                    frame->bcode, pParam,
2163                                                    pMB, &b_predMV, &best_sad,
2164                                                    MODE_BACKWARD, &Data);
2165    
2166                            /* interpolate search comes last, because it uses data from forward and backward as prediction */
2167                            SearchInterpolate(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2168                                                    b_ref, b_refH->y, b_refV->y, b_refHV->y,
2169                                                    &frame->image,
2170                                                    i, j,
2171                                                    frame->fcode, frame->bcode,
2172                                                    frame->motion_flags,
2173                                                    pParam,
2174                                                    &f_predMV, &b_predMV,
2175                                                    pMB, &best_sad,
2176                                                    &Data);
2177    
2178                            /* final skip decision */
2179                            if ( (skip_sad < Data.iQuant * MAX_SAD00_FOR_SKIP * 2)
2180                                            && ((100*best_sad)/(skip_sad+1) > FINAL_SKIP_THRESH) )
2181                                    SkipDecisionB(&frame->image, f_ref, b_ref, pMB, i, j, &Data);
2182    
2183                            switch (pMB->mode) {
2184                                    case MODE_FORWARD:
2185                                            f_count++;
2186                                            f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2187                                            break;
2188                                    case MODE_BACKWARD:
2189                                            b_count++;
2190                                            b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2191                                            break;
2192                                    case MODE_INTERPOLATE:
2193                                            i_count++;
2194                                            f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2195                                            b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2196                                            break;
2197                                    case MODE_DIRECT:
2198                                    case MODE_DIRECT_NO4V:
2199                                            d_count++;
2200                                    default:
2201                                            break;
2202                            }
2203                          }                          }
                         CHECK_MV16_CANDIDATE(pmv[3].x,pmv[3].y);  
2204                  }                  }
2205          }          }
2206    
2207  /* Step 6: If MinSAD <= thresa goto Step 10.  static __inline void
2208     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  MEanalyzeMB (   const uint8_t * const pRef,
2209  */                                  const uint8_t * const pCur,
2210                                    const int x,
2211          if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[0]) && (iMinSAD < pMB->sad16) ) )                                  const int y,
2212                                    const MBParam * const pParam,
2213                                    MACROBLOCK * const pMBs,
2214                                    SearchData * const Data)
2215          {          {
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
         }  
2216    
2217            int i;
2218            VECTOR pmv[3];
2219            MACROBLOCK * const pMB = &pMBs[x + y * pParam->mb_width];
2220    
2221  /************ (Diamond Search)  **************/          unsigned int simplicity = 0;
 /*  
    Step 7: Perform Diamond search, with either the small or large diamond.  
    If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
    Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
    If center then goto step 10.  
    Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
    Refine by using small diamond and goto step 10.  
 */  
2222    
2223          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */          for (i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;
2224    
2225  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
2226          iSAD = Diamond16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,                          pParam->width, pParam->height, Data->iFcode - Data->qpel - 1, 0, 0);
                                           x, y,  
                                           currMV->x, currMV->y, iMinSAD, &newMV,  
                                           pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);  
2227    
2228          if (iSAD < iMinSAD)          Data->Cur = pCur + (x + y * pParam->edged_width) * 16;
2229          {          Data->RefP[0] = pRef + (x + y * pParam->edged_width) * 16;
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
2230    
2231          if (MotionFlags & PMV_EXTSEARCH16)          pmv[0].x = pMB->mvs[0].x;
2232          {          pmv[0].y = pMB->mvs[0].y;
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
2233    
2234                  if (!(MVequal(pmv[0],backupMV)) )          CheckCandidate32I(pmv[0].x, pmv[0].y, Data, 0);
                 {       iSAD = Diamond16_MainSearch(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);  
2235    
2236                  if (iSAD < iMinSAD)          if (*Data->iMinSAD > 200) {
                 {  
                         *currMV = newMV;  
                         iMinSAD = iSAD;  
                 }  
                 }  
2237    
2238                  if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )                  pmv[1].x = pmv[1].y = 0;
                 {       iSAD = Diamond16_MainSearch(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);  
2239    
2240                  if (iSAD < iMinSAD)                  /* median is only used as prediction. it doesn't have to be real */
2241                  {                  if (x == 1 && y == 1) Data->predMV.x = Data->predMV.y = 0;
2242                          *currMV = newMV;                  else
2243                          iMinSAD = iSAD;                          if (x == 1) /* left macroblock does not have any vector now */
2244                                    Data->predMV = (pMB - pParam->mb_width)->mvs[0]; /* top instead of median */
2245                            else if (y == 1) /* top macroblock doesn't have it's vector */
2246                                    Data->predMV = (pMB - 1)->mvs[0]; /* left instead of median */
2247                            else Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); /* else median */
2248    
2249                    pmv[2].x = Data->predMV.x;
2250                    pmv[2].y = Data->predMV.y;
2251    
2252                    if (!vector_repeats(pmv, 1))
2253                            CheckCandidate32I(pmv[1].x, pmv[1].y, Data, 1);
2254                    if (!vector_repeats(pmv, 2))
2255                            CheckCandidate32I(pmv[2].x, pmv[2].y, Data, 2);
2256    
2257                    if (*Data->iMinSAD > 500) { /* diamond only if needed */
2258                            unsigned int mask = make_mask(pmv, 3, *Data->dir);
2259                            DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, mask, CheckCandidate32I);
2260                    } else simplicity++;
2261    
2262                    if (*Data->iMinSAD > 500) /* refinement from 2-pixel to 1-pixel */
2263                            SubpelRefine(Data, CheckCandidate32I);
2264                    else simplicity++;
2265            } else simplicity++;
2266    
2267            for (i = 0; i < 4; i++) {
2268                    MACROBLOCK * MB = &pMBs[x + (i&1) + (y+(i>>1)) * pParam->mb_width];
2269                    MB->mvs[0] = MB->mvs[1] = MB->mvs[2] = MB->mvs[3] = Data->currentMV[i];
2270                    MB->mode = MODE_INTER;
2271                    /* if we skipped some search steps, we have to assume that SAD would be lower with them */
2272                    MB->sad16 = Data->iMinSAD[i+1] - (simplicity<<7);
2273                  }                  }
2274                  }                  }
2275    
2276    #define INTRA_THRESH    2200
2277    #define INTER_THRESH    40
2278    #define INTRA_THRESH2   95
2279    
2280    int
2281    MEanalysis(     const IMAGE * const pRef,
2282                            const FRAMEINFO * const Current,
2283                            const MBParam * const pParam,
2284                            const int maxIntra, //maximum number if non-I frames
2285                            const int intraCount, //number of non-I frames after last I frame; 0 if we force P/B frame
2286                            const int bCount, // number of B frames in a row
2287                            const int b_thresh)
2288    {
2289            uint32_t x, y, intra = 0;
2290            int sSAD = 0;
2291            MACROBLOCK * const pMBs = Current->mbs;
2292            const IMAGE * const pCurrent = &Current->image;
2293            int IntraThresh = INTRA_THRESH, InterThresh = INTER_THRESH + b_thresh;
2294            int blocks = 0;
2295            int complexity = 0;
2296    
2297            int32_t iMinSAD[5], temp[5];
2298            uint32_t dir;
2299            VECTOR currentMV[5];
2300            SearchData Data;
2301            Data.iEdgedWidth = pParam->edged_width;
2302            Data.currentMV = currentMV;
2303            Data.iMinSAD = iMinSAD;
2304            Data.iFcode = Current->fcode;
2305            Data.temp = temp;
2306            Data.dir = &dir;
2307            Data.qpel = (pParam->vol_flags & XVID_VOL_QUARTERPEL)? 1: 0;
2308            Data.qpel_precision = 0;
2309    
2310            if (intraCount != 0) {
2311                    if (intraCount < 10) // we're right after an I frame
2312                            IntraThresh += 15* (intraCount - 10) * (intraCount - 10);
2313                    else
2314                            if ( 5*(maxIntra - intraCount) < maxIntra) // we're close to maximum. 2 sec when max is 10 sec
2315                                    IntraThresh -= (IntraThresh * (maxIntra - 8*(maxIntra - intraCount)))/maxIntra;
2316          }          }
2317    
2318  /*          InterThresh -= 20 * bCount;
2319     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.          if (InterThresh < 10 + b_thresh) InterThresh = 10 + b_thresh;
 */  
2320    
2321  PMVfast16_Terminate_with_Refine:          if (sadInit) (*sadInit) ();
         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);  
2322    
2323  PMVfast16_Terminate_without_Refine:          for (y = 1; y < pParam->mb_height-1; y += 2) {
2324          currPMV->x = currMV->x - pmv[0].x;                  for (x = 1; x < pParam->mb_width-1; x += 2) {
2325          currPMV->y = currMV->y - pmv[0].y;                          int i;
2326          return iMinSAD;                          blocks += 10;
 }  
2327    
2328                            if (bCount == 0) pMBs[x + y * pParam->mb_width].mvs[0] = zeroMV;
2329                            else { //extrapolation of the vector found for last frame
2330                                    pMBs[x + y * pParam->mb_width].mvs[0].x =
2331                                            (pMBs[x + y * pParam->mb_width].mvs[0].x * (bCount+1) ) / bCount;
2332                                    pMBs[x + y * pParam->mb_width].mvs[0].y =
2333                                            (pMBs[x + y * pParam->mb_width].mvs[0].y * (bCount+1) ) / bCount;
2334                            }
2335    
2336                            MEanalyzeMB(pRef->y, pCurrent->y, x, y, pParam, pMBs, &Data);
2337    
2338                            for (i = 0; i < 4; i++) {
2339                                    int dev;
2340                                    MACROBLOCK *pMB = &pMBs[x+(i&1) + (y+(i>>1)) * pParam->mb_width];
2341                                    dev = dev16(pCurrent->y + (x + (i&1) + (y + (i>>1)) * pParam->edged_width) * 16,
2342                                                                    pParam->edged_width);
2343    
2344                                    complexity += MAX(dev, 300);
2345                                    if (dev + IntraThresh < pMB->sad16) {
2346                                            pMB->mode = MODE_INTRA;
2347                                            if (++intra > ((pParam->mb_height-2)*(pParam->mb_width-2))/2) return I_VOP;
2348                                    }
2349    
2350                                    if (pMB->mvs[0].x == 0 && pMB->mvs[0].y == 0)
2351                                            if (dev > 1000 && pMB->sad16 < 1000)
2352                                                    sSAD += 1000;
2353    
2354  int32_t Diamond8_MainSearch(                                  sSAD += (dev < 4000) ? pMB->sad16 : pMB->sad16/2; /* blocks with big contrast differences usually have large SAD - while they look very good in b-frames */
         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)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iDirection=0;  
         int32_t iSAD;  
         VECTOR backupMV;  
         backupMV.x = startx;  
         backupMV.y = starty;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         CHECK_MV8_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y,1);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);  
   
         if (iDirection)  
                 while (!iFound)  
                 {  
                         iFound = 1;  
                         backupMV=*currMV;       // since iDirection!=0, this is well defined!  
   
                         if ( iDirection != 2)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x-iDiamondSize,backupMV.y,1);  
                         if ( iDirection != 1)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x+iDiamondSize,backupMV.y,2);  
                         if ( iDirection != 4)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,backupMV.y-iDiamondSize,3);  
                         if ( iDirection != 3)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,backupMV.y+iDiamondSize,4);  
2355                  }                  }
         else  
         {  
                 currMV->x = startx;  
                 currMV->y = starty;  
2356          }          }
         return iMinSAD;  
2357  }  }
2358            complexity >>= 7;
2359    
2360  int32_t Halfpel8_Refine(          sSAD /= complexity + 4*blocks;
         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);  
2361    
2362          return iMinSAD;          if (intraCount > 80 && sSAD > INTRA_THRESH2 ) return I_VOP;
2363            if (sSAD > InterThresh ) return P_VOP;
2364            emms();
2365            return B_VOP;
2366  }  }
2367    
2368    
2369  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)  /* functions which perform BITS-based search/bitcount */
2370    
2371  int32_t PMVfastSearch8(  static int
2372                                          const uint8_t * const pRef,  findRDinter(SearchData * const Data,
2373                                          const uint8_t * const pRefH,                          const MACROBLOCK * const pMBs, const int x, const int y,
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const IMAGE * const pCur,  
                                         const int x, const int y,  
                                         const int start_x, int start_y,  
                                         const uint32_t MotionFlags,  
2374                                          const MBParam * const pParam,                                          const MBParam * const pParam,
2375                                          MACROBLOCK * const pMBs,                          const uint32_t MotionFlags)
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
2376  {  {
2377          const uint32_t iWcount = pParam->mb_width;          int i;
2378            int32_t bsad[5];
2379    
2380          const int32_t iFcode = pParam->fixed_code;          if (Data->qpel) {
2381          const int32_t iQuant = pParam->quant;                  for(i = 0; i < 5; i++) {
2382          const int32_t iWidth = pParam->width;                          Data->currentMV[i].x = Data->currentQMV[i].x/2;
2383          const int32_t iHeight = pParam->height;                          Data->currentMV[i].y = Data->currentQMV[i].y/2;
2384          const int32_t iEdgedWidth = pParam->edged_width;                  }
2385                    Data->qpel_precision = 1;
2386                    CheckCandidateRD16(Data->currentQMV[0].x, Data->currentQMV[0].y, Data, 255);
2387    
2388          const uint8_t * cur = pCur->y + x*8 + y*8*iEdgedWidth;                  if (MotionFlags & (XVID_ME_HALFPELREFINE16_RD | XVID_ME_EXTSEARCH_RD)) { /* we have to prepare for halfpixel-precision search */
2389                            for(i = 0; i < 5; i++) bsad[i] = Data->iMinSAD[i];
2390                            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
2391                                                    pParam->width, pParam->height, Data->iFcode - Data->qpel, 1, Data->rrv);
2392                            Data->qpel_precision = 0;
2393                            if (Data->currentQMV->x & 1 || Data->currentQMV->y & 1)
2394                                    CheckCandidateRD16(Data->currentMV[0].x, Data->currentMV[0].y, Data, 255);
2395                    }
2396    
2397          int32_t iDiamondSize;          } else { /* not qpel */
2398    
2399          int32_t min_dx;                  CheckCandidateRD16(Data->currentMV[0].x, Data->currentMV[0].y, Data, 255);
2400          int32_t max_dx;          }
         int32_t min_dy;  
         int32_t max_dy;  
2401    
2402          VECTOR pmv[4];          if (MotionFlags&XVID_ME_EXTSEARCH_RD)
2403          int32_t psad[4];                  SquareSearch(Data->currentMV->x, Data->currentMV->y, Data, 255, CheckCandidateRD16);
         VECTOR newMV;  
         VECTOR backupMV;  
2404    
2405          MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          if (MotionFlags&XVID_ME_HALFPELREFINE16_RD)
2406                    SubpelRefine(Data, CheckCandidateRD16);
2407    
2408          static int32_t threshA,threshB;          if (Data->qpel) {
2409          int32_t iFound,bPredEq;                  if (MotionFlags&(XVID_ME_EXTSEARCH_RD | XVID_ME_HALFPELREFINE16_RD)) { /* there was halfpel-precision search */
2410          int32_t iMinSAD,iSAD;                          for(i = 0; i < 5; i++) if (bsad[i] > Data->iMinSAD[i]) {
2411                                    Data->currentQMV[i].x = 2 * Data->currentMV[i].x; /* we have found a better match */
2412                                    Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
2413                            }
2414    
2415          int32_t iSubBlock = ((y&1)<<1) + (x&1);                          /* preparing for qpel-precision search */
2416                            Data->qpel_precision = 1;
2417                            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
2418                                            pParam->width, pParam->height, Data->iFcode, 2, 0);
2419                    }
2420                    if (MotionFlags&XVID_ME_QUARTERPELREFINE16_RD)
2421                            SubpelRefine(Data, CheckCandidateRD16);
2422            }
2423    
2424  /* Get maximum range */          if (MotionFlags&XVID_ME_CHECKPREDICTION_RD) { /* let's check vector equal to prediction */
2425          get_range(&min_dx, &max_dx, &min_dy, &max_dy,                  VECTOR * v = Data->qpel ? Data->currentQMV : Data->currentMV;
2426                    x, y, 8, iWidth, iHeight, iFcode);                  if (!(Data->predMV.x == v->x && Data->predMV.y == v->y))
2427                            CheckCandidateRD16(Data->predMV.x, Data->predMV.y, Data, 255);
2428            }
2429            return Data->iMinSAD[0];
2430    }
2431    
2432  /* we work with abs. MVs, not relative to prediction, so range is relative to 0,0 */  static int
2433    findRDinter4v(const SearchData * const Data,
2434                                    MACROBLOCK * const pMB, const MACROBLOCK * const pMBs,
2435                                    const int x, const int y,
2436                                    const MBParam * const pParam, const uint32_t MotionFlags,
2437                                    const VECTOR * const backup)
2438    {
2439    
2440          if (!(MotionFlags & PMV_HALFPELDIAMOND8 ))          int cbp = 0, bits = 0, t = 0, i;
2441          { min_dx = EVEN(min_dx);          SearchData Data2, *Data8 = &Data2;
2442          max_dx = EVEN(max_dx);          int sumx = 0, sumy = 0;
2443          min_dy = EVEN(min_dy);          int16_t *in = Data->dctSpace, *coeff = Data->dctSpace + 64;
2444          max_dy = EVEN(max_dy);          uint8_t * ptr;
         }               /* because we might use IF (dx>max_dx) THEN dx=max_dx; */  
2445    
2446            memcpy(Data8, Data, sizeof(SearchData));
2447    
2448          bPredEq  = get_pmvdata(pMBs, (x>>1), (y>>1), iWcount, iSubBlock, pmv, psad);          for (i = 0; i < 4; i++) { /* for all luma blocks */
2449    
2450          if ((x==0) && (y==0) )                  Data8->iMinSAD = Data->iMinSAD + i + 1;
2451          {                  Data8->currentMV = Data->currentMV + i + 1;
2452                  threshA =  512/4;                  Data8->currentQMV = Data->currentQMV + i + 1;
2453                  threshB = 1024/4;                  Data8->Cur = Data->Cur + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2454                    Data8->RefP[0] = Data->RefP[0] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2455                    Data8->RefP[2] = Data->RefP[2] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2456                    Data8->RefP[1] = Data->RefP[1] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2457                    Data8->RefP[3] = Data->RefP[3] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2458                    *Data8->cbp = (Data->cbp[1] & (1<<(5-i))) ? 1:0; // copy corresponding cbp bit
2459    
2460          }                  if(Data->qpel) {
2461          else                          Data8->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, i);
2462          {                          if (i != 0)     t = d_mv_bits(  Data8->currentQMV->x, Data8->currentQMV->y,
2463                  threshA = psad[0]/4;                    /* good estimate */                                                                                  Data8->predMV, Data8->iFcode, 0, 0);
2464                  threshB = threshA+256/4;                  } else {
2465                  if (threshA< 512/4) threshA =  512/4;                          Data8->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, i);
2466                  if (threshA>1024/4) threshA = 1024/4;                          if (i != 0)     t = d_mv_bits(  Data8->currentMV->x, Data8->currentMV->y,
2467                  if (threshB>1792/4) threshB = 1792/4;                                                                                  Data8->predMV, Data8->iFcode, 0, 0);
2468          }          }
2469    
2470          iFound=0;                  get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 3,
2471                                            pParam->width, pParam->height, Data8->iFcode, Data8->qpel+1, 0);
 /* Step 2: Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  
    vector of the median.  
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
2472    
2473          if ((bPredEq) && (MVequal(pmv[0],pMB->mvs[iSubBlock]) ) )                  *Data8->iMinSAD += BITS_MULT*t;
                 iFound=2;  
2474    
2475  /* Step 3: If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.                  Data8->qpel_precision = Data8->qpel;
2476     Otherwise select large Diamond Search.                  /* checking the vector which has been found by SAD-based 8x8 search (if it's different than the one found so far) */
2477  */                  {
2478                            VECTOR *v = Data8->qpel ? Data8->currentQMV : Data8->currentMV;
2479                            if (!MVequal (*v, backup[i+1]) )
2480                                    CheckCandidateRD8(backup[i+1].x, backup[i+1].y, Data8, 255);
2481                    }
2482    
2483          if ( (pmv[0].x != 0) || (pmv[0].y != 0) || (threshB<1536/4) || (bPredEq) )                  if (Data8->qpel) {
2484                  iDiamondSize=1; // 1 halfpel!                          if (MotionFlags&XVID_ME_HALFPELREFINE8_RD || (MotionFlags&XVID_ME_EXTSEARCH8 && MotionFlags&XVID_ME_EXTSEARCH_RD)) { /* halfpixel motion search follows */
2485          else                                  int32_t s = *Data8->iMinSAD;
2486                  iDiamondSize=2; // 2 halfpel = 1 full pixel!                                  Data8->currentMV->x = Data8->currentQMV->x/2;
2487                                    Data8->currentMV->y = Data8->currentQMV->y/2;
2488                                    Data8->qpel_precision = 0;
2489                                    get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 3,
2490                                                            pParam->width, pParam->height, Data8->iFcode - 1, 1, 0);
2491    
2492          if (!(MotionFlags & PMV_HALFPELDIAMOND8) )                                  if (Data8->currentQMV->x & 1 || Data8->currentQMV->y & 1)
2493                  iDiamondSize*=2;                                          CheckCandidateRD8(Data8->currentMV->x, Data8->currentMV->y, Data8, 255);
2494    
2495  /* Step 4: Calculate SAD around the Median prediction.                                  if (MotionFlags & XVID_ME_EXTSEARCH8 && MotionFlags & XVID_ME_EXTSEARCH_RD)
2496     MinSAD=SAD                                          SquareSearch(Data8->currentMV->x, Data8->currentMV->x, Data8, 255, CheckCandidateRD8);
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
2497    
2498                                    if (MotionFlags & XVID_ME_HALFPELREFINE8_RD)
2499                                            SubpelRefine(Data8, CheckCandidateRD8);
2500    
2501  // Prepare for main loop                                  if(s > *Data8->iMinSAD) { /* we have found a better match */
2502                                            Data8->currentQMV->x = 2*Data8->currentMV->x;
2503                                            Data8->currentQMV->y = 2*Data8->currentMV->y;
2504                                    }
2505    
2506          currMV->x=start_x;              /* start with mv16 */                                  Data8->qpel_precision = 1;
2507          currMV->y=start_y;                                  get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 3,
2508                                                            pParam->width, pParam->height, Data8->iFcode, 2, 0);
2509    
         iMinSAD = sad8( cur,  
                         get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV, iEdgedWidth),  
                         iEdgedWidth);  
         iMinSAD += calc_delta_8(currMV->x - pmv[0].x, currMV->y - pmv[0].y, (uint8_t)iFcode) * iQuant;  
   
         if ( (iMinSAD < 256/4 ) || ( (MVequal(*currMV,pMB->mvs[iSubBlock])) && (iMinSAD < pMB->sad8[iSubBlock]) ) )  
         {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
2510          }          }
2511                            if (MotionFlags & XVID_ME_QUARTERPELREFINE8_RD)
2512                                    SubpelRefine(Data8, CheckCandidateRD8);
2513    
2514                    } else { /* not qpel */
2515    
2516  /*                          if (MotionFlags & XVID_ME_EXTSEARCH8 && MotionFlags & XVID_ME_EXTSEARCH_RD) /* extsearch */
2517     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.                                  SquareSearch(Data8->currentMV->x, Data8->currentMV->x, Data8, 255, CheckCandidateRD8);
    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. ******** WHAT'S THIS 'OFFSET' ??? ***********  
 */  
2518    
2519  // the prediction might be even better than mv16                          if (MotionFlags & XVID_ME_HALFPELREFINE8_RD)
2520          CHECK_MV8_CANDIDATE(pmv[0].x,pmv[0].y);                                  SubpelRefine(Data8, CheckCandidateRD8); /* halfpel refinement */
2521                    }
2522    
2523  // (0,0) is always possible                  /* checking vector equal to predicion */
2524          CHECK_MV8_ZERO;                  if (i != 0 && MotionFlags & XVID_ME_CHECKPREDICTION_RD) {
2525                            const VECTOR * v = Data->qpel ? Data8->currentQMV : Data8->currentMV;
2526                            if (!MVequal(*v, Data8->predMV))
2527                                    CheckCandidateRD8(Data8->predMV.x, Data8->predMV.y, Data8, 255);
2528                    }
2529    
2530  // previous frame MV is always possible                  bits += *Data8->iMinSAD;
2531          CHECK_MV8_CANDIDATE(pMB->mvs[iSubBlock].x,pMB->mvs[iSubBlock].y);                  if (bits >= Data->iMinSAD[0]) return bits; /* no chances for INTER4V */
2532    
2533  // left neighbour, if allowed                  /* MB structures for INTER4V mode; we have to set them here, we don't have predictor anywhere else */
2534          if (psad[1] != MV_MAX_ERROR)                  if(Data->qpel) {
2535          {                          pMB->pmvs[i].x = Data8->currentQMV->x - Data8->predMV.x;
2536                  if (!(MotionFlags & PMV_HALFPEL8 ))                          pMB->pmvs[i].y = Data8->currentQMV->y - Data8->predMV.y;
2537                  {       pmv[1].x = EVEN(pmv[1].x);                          pMB->qmvs[i] = *Data8->currentQMV;
2538                  pmv[1].y = EVEN(pmv[1].y);                          sumx += Data8->currentQMV->x/2;
2539                  }                          sumy += Data8->currentQMV->y/2;
2540                  CHECK_MV8_CANDIDATE(pmv[1].x,pmv[1].y);                  } else {
2541                            pMB->pmvs[i].x = Data8->currentMV->x - Data8->predMV.x;
2542                            pMB->pmvs[i].y = Data8->currentMV->y - Data8->predMV.y;
2543                            sumx += Data8->currentMV->x;
2544                            sumy += Data8->currentMV->y;
2545          }          }
2546                    pMB->mvs[i] = *Data8->currentMV;
2547                    pMB->sad8[i] = 4 * *Data8->iMinSAD;
2548                    if (Data8->cbp[0]) cbp |= 1 << (5 - i);
2549    
2550  // top neighbour, if allowed          } /* end - for all luma blocks */
         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);  
2551    
2552  // top right neighbour, if allowed          bits += BITS_MULT*xvid_cbpy_tab[15-(cbp>>2)].len;
                 if (psad[3] != MV_MAX_ERROR)  
                 {  
                         if (!(MotionFlags & PMV_HALFPEL8 ))  
                         {       pmv[3].x = EVEN(pmv[3].x);  
                         pmv[3].y = EVEN(pmv[3].y);  
                         }  
                         CHECK_MV8_CANDIDATE(pmv[3].x,pmv[3].y);  
                 }  
         }  
2553    
2554  /* Step 6: If MinSAD <= thresa goto Step 10.          /* let's check chroma */
2555     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.          sumx = (sumx >> 3) + roundtab_76[sumx & 0xf];
2556  */          sumy = (sumy >> 3) + roundtab_76[sumy & 0xf];
2557    
2558          if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[iSubBlock]) && (iMinSAD < pMB->sad8[iSubBlock]) ) )          /* chroma U */
2559          {          ptr = interpolate8x8_switch2(Data->RefQ + 64, Data->RefP[4], 0, 0, sumx, sumy, Data->iEdgedWidth/2, Data->rounding);
2560                  if (MotionFlags & PMV_QUICKSTOP16)          transfer_8to16subro(in, Data->CurU, ptr, Data->iEdgedWidth/2);
2561                          goto PMVfast8_Terminate_without_Refine;          bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 4);
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
2562    
2563  /************ (Diamond Search)  **************/          if (bits >= *Data->iMinSAD) return bits;
 /*  
    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.  
 */  
2564    
2565          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */          /* chroma V */
2566            ptr = interpolate8x8_switch2(Data->RefQ + 64, Data->RefP[5], 0, 0, sumx, sumy, Data->iEdgedWidth/2, Data->rounding);
2567            transfer_8to16subro(in, Data->CurV, ptr, Data->iEdgedWidth/2);
2568            bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 5);
2569    
2570  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTER4V & 7) | ((cbp & 3) << 3)].len;
         iSAD = Diamond8_MainSearch(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);  
2571    
2572          if (iSAD < iMinSAD)          *Data->cbp = cbp;
2573          {          return bits;
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
2574          }          }
2575    
2576          if (MotionFlags & PMV_EXTSEARCH8)  static int
2577    findRDintra(const SearchData * const Data)
2578          {          {
2579  /* extended: search (up to) two more times: orignal prediction and (0,0) */          int bits = BITS_MULT*1; /* this one is ac/dc prediction flag bit */
2580            int cbp = 0, i, dc = 0;
2581            int16_t *in = Data->dctSpace, * coeff = Data->dctSpace + 64;
2582    
2583                  if (!(MVequal(pmv[0],backupMV)) )          for(i = 0; i < 4; i++) {
2584                  {       iSAD = Diamond16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,                  int s = 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2585                                                            x, y,                  transfer_8to16copy(in, Data->Cur + s, Data->iEdgedWidth);
2586                                                            pmv[0].x, pmv[0].y, iMinSAD, &newMV,                  bits += Block_CalcBitsIntra(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, i, &dc);
                                                           pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);  
2587    
2588                  if (iSAD < iMinSAD)                  if (bits >= Data->iMinSAD[0]) return bits;
                 {  
                         *currMV = newMV;  
                         iMinSAD = iSAD;  
2589                  }                  }
                 }  
   
                 if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )  
                 {       iSAD = Diamond16_MainSearch(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);  
2590    
2591                  if (iSAD < iMinSAD)          bits += BITS_MULT*xvid_cbpy_tab[cbp>>2].len;
                 {  
                         *currMV = newMV;  
                         iMinSAD = iSAD;  
                 }  
                 }  
         }  
2592    
2593  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.          /*chroma U */
2594     By performing an optional local half-pixel search, we can refine this result even further.          transfer_8to16copy(in, Data->CurU, Data->iEdgedWidth/2);
2595  */          bits += Block_CalcBitsIntra(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 4, &dc);
2596    
2597  PMVfast8_Terminate_with_Refine:          if (bits >= Data->iMinSAD[0]) return bits;
         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);  
2598    
2599            /* chroma V */
2600            transfer_8to16copy(in, Data->CurV, Data->iEdgedWidth/2);
2601            bits += Block_CalcBitsIntra(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 5, &dc);
2602    
2603  PMVfast8_Terminate_without_Refine:          bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTRA & 7) | ((cbp & 3) << 3)].len;
         currPMV->x = currMV->x - pmv[0].x;  
         currPMV->y = currMV->y - pmv[0].y;  
2604    
2605          return iMinSAD;          return bits;
2606  }  }
2607    
2608  int32_t EPZSSearch16(  static int
2609                                          const uint8_t * const pRef,  findRDgmc(const SearchData * const Data, const IMAGE * const vGMC, const int x, const int y)
                                         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 MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
2610  {  {
2611          const uint32_t iWcount = pParam->mb_width;          int bits = BITS_MULT*1; /* this one is mcsel */
2612          const uint32_t iHcount = pParam->mb_height;          int cbp = 0, i;
2613          const int32_t iFcode = pParam->fixed_code;          int16_t *in = Data->dctSpace, * coeff = Data->dctSpace + 64;
         const int32_t iQuant = pParam->quant;  
2614    
2615          const int32_t iWidth = pParam->width;          for(i = 0; i < 4; i++) {
2616          const int32_t iHeight = pParam->height;                  int s = 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2617          const int32_t iEdgedWidth = pParam->edged_width;                  transfer_8to16subro(in, Data->Cur + s, vGMC->y + s + 16*(x+y*Data->iEdgedWidth), Data->iEdgedWidth);
2618                    bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, i);
2619          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;                  if (bits >= Data->iMinSAD[0]) return bits;
2620            }
2621    
2622          int32_t min_dx;          bits += BITS_MULT*xvid_cbpy_tab[15-(cbp>>2)].len;
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
2623    
2624          VECTOR newMV;          /*chroma U */
2625          VECTOR backupMV;          transfer_8to16subro(in, Data->CurU, vGMC->u + 8*(x+y*(Data->iEdgedWidth/2)), Data->iEdgedWidth/2);
2626            bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 4);
2627    
2628          VECTOR pmv[4];          if (bits >= Data->iMinSAD[0]) return bits;
         int32_t psad[8];  
2629    
2630          static MACROBLOCK * oldMBs = NULL;          /* chroma V */
2631          MACROBLOCK * const pMB = pMBs + x + y * iWcount;          transfer_8to16subro(in, Data->CurV , vGMC->v + 8*(x+y*(Data->iEdgedWidth/2)), Data->iEdgedWidth/2);
2632          MACROBLOCK * oldMB = NULL;          bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 5);
2633    
2634          static int32_t thresh2;          bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTER & 7) | ((cbp & 3) << 3)].len;
         int32_t bPredEq;  
         int32_t iMinSAD,iSAD=9999;  
2635    
2636          MainSearch16FuncPtr EPZSMainSearchPtr;          *Data->cbp = cbp;
2637    
2638          if (oldMBs == NULL)          return bits;
         {       oldMBs = (MACROBLOCK*) calloc(1,iWcount*iHcount*sizeof(MACROBLOCK));  
                 fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));  
2639          }          }
         oldMB = oldMBs + x + y * iWcount;  
2640    
 /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy,  
                         x, y, 16, iWidth, iHeight, iFcode);  
2641    
 /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  
2642    
         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; */  
2643    
2644          bPredEq  = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  static __inline void
2645    GMEanalyzeMB (  const uint8_t * const pCur,
2646                                    const uint8_t * const pRef,
2647                                    const uint8_t * const pRefH,
2648                                    const uint8_t * const pRefV,
2649                                    const uint8_t * const pRefHV,
2650                                    const int x,
2651                                    const int y,
2652                                    const MBParam * const pParam,
2653                                    MACROBLOCK * const pMBs,
2654                                    SearchData * const Data)
2655    {
2656    
2657  /* Step 4: Calculate SAD around the Median prediction.          int i=0;
2658          MinSAD=SAD          MACROBLOCK * const pMB = &pMBs[x + y * pParam->mb_width];
         If Motion Vector equal to Previous frame motion vector  
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
 */  
2659    
2660  // Prepare for main loop          Data->iMinSAD[0] = MV_MAX_ERROR;
2661    
2662          *currMV=pmv[0];         /* current best := median prediction */          Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
         if (!(MotionFlags & PMV_HALFPEL16))  
         {  
                 currMV->x = EVEN(currMV->x);  
                 currMV->y = EVEN(currMV->y);  
         }  
2663    
2664          if (currMV->x > max_dx)          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
2665                  currMV->x=max_dx;                                  pParam->width, pParam->height, 16, 1, 0);
         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;  
2666    
2667  /***************** This is predictor SET A: only median prediction ******************/          Data->Cur = pCur + 16*(x + y * pParam->edged_width);
2668            Data->RefP[0] = pRef + 16*(x + y * pParam->edged_width);
2669            Data->RefP[1] = pRefV + 16*(x + y * pParam->edged_width);
2670            Data->RefP[2] = pRefH + 16*(x + y * pParam->edged_width);
2671            Data->RefP[3] = pRefHV + 16*(x + y * pParam->edged_width);
2672    
2673          iMinSAD = sad16( cur,          Data->currentMV[0].x = Data->currentMV[0].y = 0;
2674                  get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV, iEdgedWidth),          CheckCandidate16I(0, 0, Data, 255);
                 iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD += calc_delta_16(currMV->x-pmv[0].x, currMV->y-pmv[0].y, (uint8_t)iFcode) * iQuant;  
2675    
2676  // thresh1 is fixed to 256          if ( (Data->predMV.x !=0) || (Data->predMV.y != 0) )
2677          if ( (iMinSAD < 256 ) || ( (MVequal(*currMV,pMB->mvs[0])) && (iMinSAD < pMB->sad16) ) )                  CheckCandidate16I(Data->predMV.x, Data->predMV.y, Data, 255);
                 {  
                         if (MotionFlags & PMV_QUICKSTOP16)  
                                 goto EPZS16_Terminate_without_Refine;  
                         if (MotionFlags & PMV_EARLYSTOP16)  
                                 goto EPZS16_Terminate_with_Refine;  
                 }  
2678    
2679  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/          DiamondSearch(Data->currentMV[0].x, Data->currentMV[0].y, Data, 255, CheckCandidate16I);
2680    
2681  // previous frame MV          SubpelRefine(Data, CheckCandidate16I);
         CHECK_MV16_CANDIDATE(pMB->mvs[0].x,pMB->mvs[0].y);  
2682    
 // set threshhold based on Min of Prediction and SAD of collocated block  
 // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want  
2683    
2684          if ((x==0) && (y==0) )          /* for QPel halfpel positions are worse than in halfpel mode :( */
2685          {  /*      if (Data->qpel) {
2686                  thresh2 =  512;                  Data->currentQMV->x = 2*Data->currentMV->x;
2687                    Data->currentQMV->y = 2*Data->currentMV->y;
2688                    Data->qpel_precision = 1;
2689                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
2690                                            pParam->width, pParam->height, iFcode, 2, 0);
2691                    SubpelRefine(Data);
2692          }          }
2693          else  */
         {  
 /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */  
2694    
2695                  thresh2 = MIN(psad[0],iSAD)*6/5 + 128;          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
2696            pMB->sad16 = Data->iMinSAD[0];
2697            pMB->mode = MODE_INTER;
2698            pMB->sad16 += 10*d_mv_bits(pMB->mvs[0].x, pMB->mvs[0].y, Data->predMV, Data->iFcode, 0, 0);
2699            return;
2700          }          }
2701    
2702  // MV=(0,0) is often a good choice  void
2703    GMEanalysis(const MBParam * const pParam,
2704                            const FRAMEINFO * const current,
2705                            const FRAMEINFO * const reference,
2706                            const IMAGE * const pRefH,
2707                            const IMAGE * const pRefV,
2708                            const IMAGE * const pRefHV)
2709    {
2710            uint32_t x, y;
2711            MACROBLOCK * const pMBs = current->mbs;
2712            const IMAGE * const pCurrent = &current->image;
2713            const IMAGE * const pReference = &reference->image;
2714    
2715          CHECK_MV16_ZERO;          int32_t iMinSAD[5], temp[5];
2716            VECTOR currentMV[5];
2717            uint32_t dir;
2718            SearchData Data;
2719            memset(&Data, 0, sizeof(SearchData));
2720    
2721            Data.iEdgedWidth = pParam->edged_width;
2722            Data.rounding = pParam->m_rounding_type;
2723    
2724  // left neighbour, if allowed          Data.currentMV = &currentMV[0];
2725          if (x != 0)          Data.iMinSAD = &iMinSAD[0];
2726          {          Data.iFcode = current->fcode;
2727                  if (!(MotionFlags & PMV_HALFPEL16 ))          Data.temp = temp;
2728                  {       pmv[1].x = EVEN(pmv[1].x);          Data.dir = &dir;
                         pmv[1].y = EVEN(pmv[1].y);  
                 }  
                 CHECK_MV16_CANDIDATE(pmv[1].x,pmv[1].y);  
         }  
2729    
2730  // top neighbour, if allowed          if (sadInit) (*sadInit) ();
         if (y != 0)  
         {  
                 if (!(MotionFlags & PMV_HALFPEL16 ))  
                 {       pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
                 }  
                 CHECK_MV16_CANDIDATE(pmv[2].x,pmv[2].y);  
2731    
2732  // top right neighbour, if allowed          for (y = 0; y < pParam->mb_height; y ++) {
2733                  if (x != (iWcount-1))                  for (x = 0; x < pParam->mb_width; x ++) {
2734                  {                          GMEanalyzeMB(pCurrent->y, pReference->y, pRefH->y, pRefV->y, pRefHV->y, x, y, pParam, pMBs, &Data);
                         if (!(MotionFlags & PMV_HALFPEL16 ))  
                         {       pmv[3].x = EVEN(pmv[3].x);  
                                 pmv[3].y = EVEN(pmv[3].y);  
2735                          }                          }
                         CHECK_MV16_CANDIDATE(pmv[3].x,pmv[3].y);  
2736                  }                  }
2737            return;
2738          }          }
2739    
 /* Terminate if MinSAD <= T_2  
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
2740    
2741          if ( (iMinSAD <= thresh2)  WARPPOINTS
2742                  || ( MVequal(*currMV,pMB->mvs[0]) && (iMinSAD <= pMB->sad16) ) )  GlobalMotionEst(MACROBLOCK * const pMBs,
2743                                    const MBParam * const pParam,
2744                                    const FRAMEINFO * const current,
2745                                    const FRAMEINFO * const reference,
2746                                    const IMAGE * const pRefH,
2747                                    const IMAGE * const pRefV,
2748                                    const IMAGE * const pRefHV)
2749                  {                  {
                         if (MotionFlags & PMV_QUICKSTOP16)  
                                 goto EPZS16_Terminate_without_Refine;  
                         if (MotionFlags & PMV_EARLYSTOP16)  
                                 goto EPZS16_Terminate_with_Refine;  
                 }  
   
 /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/  
2750    
2751          backupMV = pMB->mvs[0];                 // last MV          const int deltax=8;             // upper bound for difference between a MV and it's neighbour MVs
2752          backupMV.x += (pMB->mvs[0].x - oldMB->mvs[0].x );       // acceleration X          const int deltay=8;
2753          backupMV.y += (pMB->mvs[0].y - oldMB->mvs[0].y );       // acceleration Y          const unsigned int gradx=512;           // lower bound for gradient in MB (ignore "flat" blocks)
2754            const unsigned int grady=512;
2755    
2756          CHECK_MV16_CANDIDATE(backupMV.x,backupMV.y);          double sol[4] = { 0., 0., 0., 0. };
2757    
2758  // left neighbour          WARPPOINTS gmc;
         if (x != 0)  
                 CHECK_MV16_CANDIDATE((oldMB-1)->mvs[0].x,oldMB->mvs[0].y);  
   
 // top neighbour  
         if (y != 0)  
                 CHECK_MV16_CANDIDATE((oldMB-iWcount)->mvs[0].x,oldMB->mvs[0].y);  
   
 // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs  
2759    
2760          if (x != iWcount-1)          uint32_t mx, my;
                 CHECK_MV16_CANDIDATE((pMB+1)->mvs[0].x,oldMB->mvs[0].y);  
2761    
2762  // bottom neighbour, dito          int MBh = pParam->mb_height;
2763          if (y != iHcount-1)          int MBw = pParam->mb_width;
2764                  CHECK_MV16_CANDIDATE((pMB+iWcount)->mvs[0].x,oldMB->mvs[0].y);          const int minblocks = 9; //MBh*MBw/32+3;                /* just some reasonable number 3% + 3 */
2765            const int maxblocks = MBh*MBw/4;                /* just some reasonable number 3% + 3 */
2766    
2767  /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */          int num=0;
2768          if (iMinSAD <= thresh2)          int oldnum;
                 {  
                         if (MotionFlags & PMV_QUICKSTOP16)  
                                 goto EPZS16_Terminate_without_Refine;  
                         if (MotionFlags & PMV_EARLYSTOP16)  
                                 goto EPZS16_Terminate_with_Refine;  
                 }  
2769    
2770  /************ (if Diamond Search)  **************/          gmc.duv[0].x = gmc.duv[0].y = gmc.duv[1].x = gmc.duv[1].y = gmc.duv[2].x = gmc.duv[2].y = 0;
2771    
2772          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */          GMEanalysis(pParam,current, reference, pRefH, pRefV, pRefHV);
2773    
2774  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          /* block based ME isn't done, yet, so do a quick presearch */
   
         if (MotionFlags & PMV_USESQUARES16)  
                 EPZSMainSearchPtr = Square16_MainSearch;  
         else  
                 EPZSMainSearchPtr = Diamond16_MainSearch;  
2775    
2776          iSAD = (*EPZSMainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,  // filter mask of all blocks
                         x, y,  
                         currMV->x, currMV->y, iMinSAD, &newMV, pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                         2, iFcode, iQuant, 0);  
2777    
2778          if (iSAD < iMinSAD)          for (my = 0; my < (uint32_t)MBh; my++)
2779            for (mx = 0; mx < (uint32_t)MBw; mx++)
2780          {          {
2781                  *currMV = newMV;                  const int mbnum = mx + my * MBw;
2782                  iMinSAD = iSAD;                          pMBs[mbnum].mcsel = 0;
2783          }          }
2784    
2785    
2786          if (MotionFlags & PMV_EXTSEARCH16)          for (my = 1; my < (uint32_t)MBh-1; my++) /* ignore boundary blocks */
2787            for (mx = 1; mx < (uint32_t)MBw-1; mx++) /* theirs MVs are often wrong */
2788          {          {
2789  /* extended mode: search (up to) two more times: orignal prediction and (0,0) */                  const int mbnum = mx + my * MBw;
2790                    MACROBLOCK *const pMB = &pMBs[mbnum];
2791                    const VECTOR mv = pMB->mvs[0];
2792    
2793                  if (!(MVequal(pmv[0],backupMV)) )                  /* don't use object boundaries */
2794                  {                  if   ( (abs(mv.x -   (pMB-1)->mvs[0].x) < deltax)
2795                          iSAD = (*EPZSMainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,                          && (abs(mv.y -   (pMB-1)->mvs[0].y) < deltay)
2796                                  x, y,                          && (abs(mv.x -   (pMB+1)->mvs[0].x) < deltax)
2797                                  pmv[0].x, pmv[0].y, iMinSAD, &newMV,                          && (abs(mv.y -   (pMB+1)->mvs[0].y) < deltay)
2798                                  pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);                          && (abs(mv.x - (pMB-MBw)->mvs[0].x) < deltax)
2799                  }                          && (abs(mv.y - (pMB-MBw)->mvs[0].y) < deltay)
2800                            && (abs(mv.x - (pMB+MBw)->mvs[0].x) < deltax)
2801                  if (iSAD < iMinSAD)                          && (abs(mv.y - (pMB+MBw)->mvs[0].y) < deltay) )
2802                  {                  {       const int iEdgedWidth = pParam->edged_width;
2803                          *currMV = newMV;                          const uint8_t *const pCur = current->image.y + 16*(my*iEdgedWidth + mx);
2804                          iMinSAD = iSAD;                          if ( (sad16 ( pCur, pCur+1 , iEdgedWidth, 65536) >= gradx )
2805                             &&  (sad16 ( pCur, pCur+iEdgedWidth, iEdgedWidth, 65536) >= grady ) )
2806                             {      pMB->mcsel = 1;
2807                                    num++;
2808                  }                  }
2809    
2810                  if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )                  /* only use "structured" blocks */
                 {  
                         iSAD = (*EPZSMainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,  
                                 x, y,  
                         0, 0, iMinSAD, &newMV,  
                         pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, /*iDiamondSize*/ 2, iFcode, iQuant, 0);  
   
                         if (iSAD < iMinSAD)  
                         {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
2811                  }                  }
2812          }          }
2813            emms();
2814    
2815  /***************        Choose best MV found     **************/          /*      further filtering would be possible, but during iteration, remaining
2816                    outliers usually are removed, too */
2817    
2818  EPZS16_Terminate_with_Refine:          if (num>= minblocks)
2819          if (MotionFlags & PMV_HALFPELREFINE16)          // perform final half-pel step          do {            /* until convergence */
2820                  iMinSAD = Halfpel16_Refine( pRef, pRefH, pRefV, pRefHV, cur,                  double DtimesF[4];
2821                                  x, y,                  double a,b,c,n,invdenom;
2822                                  currMV, iMinSAD,                  double meanx,meany;
                                 pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);  
2823    
2824  EPZS16_Terminate_without_Refine:                  a = b = c = n = 0;
2825                    DtimesF[0] = DtimesF[1] = DtimesF[2] = DtimesF[3] = 0.;
2826          *oldMB = *pMB;                  for (my = 1; my < (uint32_t)MBh-1; my++)
2827                    for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2828          currPMV->x = currMV->x - pmv[0].x;                  {
2829          currPMV->y = currMV->y - pmv[0].y;                          const int mbnum = mx + my * MBw;
2830          return iMinSAD;                          const VECTOR mv = pMBs[mbnum].mvs[0];
 }  
2831    
2832                            if (!pMBs[mbnum].mcsel)
2833                                    continue;
2834    
2835  int32_t EPZSSearch8(                          n++;
2836                                          const uint8_t * const pRef,                          a += 16*mx+8;
2837                                          const uint8_t * const pRefH,                          b += 16*my+8;
2838                                          const uint8_t * const pRefV,                          c += (16*mx+8)*(16*mx+8)+(16*my+8)*(16*my+8);
                                         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 MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
 {  
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iFcode = pParam->fixed_code;  
         const int32_t iQuant = pParam->quant;  
2839    
2840          const int32_t iWidth = pParam->width;                          DtimesF[0] += (double)mv.x;
2841          const int32_t iHeight = pParam->height;                          DtimesF[1] += (double)mv.x*(16*mx+8) + (double)mv.y*(16*my+8);
2842          const int32_t iEdgedWidth = pParam->edged_width;                          DtimesF[2] += (double)mv.x*(16*my+8) - (double)mv.y*(16*mx+8);
2843                            DtimesF[3] += (double)mv.y;
2844                    }
2845    
2846          const uint8_t * cur = pCur->y + x*8 + y*8*iEdgedWidth;          invdenom = a*a+b*b-c*n;
2847    
2848          int32_t iDiamondSize=1;  /* Solve the system:    sol = (D'*E*D)^{-1} D'*E*F   */
2849    /* D'*E*F has been calculated in the same loop as matrix */
2850    
2851          int32_t min_dx;          sol[0] = -c*DtimesF[0] + a*DtimesF[1] + b*DtimesF[2];
2852          int32_t max_dx;          sol[1] =  a*DtimesF[0] - n*DtimesF[1]                           + b*DtimesF[3];
2853          int32_t min_dy;          sol[2] =  b*DtimesF[0]                          - n*DtimesF[2] - a*DtimesF[3];
2854          int32_t max_dy;          sol[3] =                                 b*DtimesF[1] - a*DtimesF[2] - c*DtimesF[3];
2855    
2856          VECTOR newMV;          sol[0] /= invdenom;
2857          VECTOR backupMV;          sol[1] /= invdenom;
2858            sol[2] /= invdenom;
2859            sol[3] /= invdenom;
2860    
2861          VECTOR pmv[4];          meanx = meany = 0.;
2862          int32_t psad[8];          oldnum = 0;
2863            for (my = 1; my < (uint32_t)MBh-1; my++)
2864                    for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2865                    {
2866                            const int mbnum = mx + my * MBw;
2867                            const VECTOR mv = pMBs[mbnum].mvs[0];
2868    
2869          const   int32_t iSubBlock = ((y&1)<<1) + (x&1);                          if (!pMBs[mbnum].mcsel)
2870                                    continue;
2871    
2872          MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;                          oldnum++;
2873                            meanx += fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - (double)mv.x );
2874                            meany += fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - (double)mv.y );
2875                    }
2876    
2877          int32_t bPredEq;          if (4*meanx > oldnum)   /* better fit than 0.25 (=1/4pel) is useless */
2878          int32_t iMinSAD,iSAD=9999;                  meanx /= oldnum;
2879            else
2880                    meanx = 0.25;
2881    
2882          MainSearch8FuncPtr EPZSMainSearchPtr;          if (4*meany > oldnum)
2883                    meany /= oldnum;
2884            else
2885                    meany = 0.25;
2886    
2887  /* Get maximum range */          num = 0;
2888          get_range(&min_dx, &max_dx, &min_dy, &max_dy,          for (my = 0; my < (uint32_t)MBh; my++)
2889                          x, y, 8, iWidth, iHeight, iFcode);                  for (mx = 0; mx < (uint32_t)MBw; mx++)
2890                    {
2891                            const int mbnum = mx + my * MBw;
2892                            const VECTOR mv = pMBs[mbnum].mvs[0];
2893    
2894  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */                          if (!pMBs[mbnum].mcsel)
2895                                    continue;
2896    
2897          if (!(MotionFlags & PMV_HALFPEL8 ))                          if  ( ( fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - (double)mv.x ) > meanx )
2898          { min_dx = EVEN(min_dx);                                  || ( fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - (double)mv.y ) > meany ) )
2899            max_dx = EVEN(max_dx);                                  pMBs[mbnum].mcsel=0;
2900            min_dy = EVEN(min_dy);                          else
2901            max_dy = EVEN(max_dy);                                  num++;
2902          }               /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */                  }
2903    
2904          bPredEq  = get_pmvdata(pMBs, x>>1, y>>1, iWcount, iSubBlock, pmv, psad);          } while ( (oldnum != num) && (num>= minblocks) );
2905    
2906            if (num < minblocks)
2907            {
2908                    const int iEdgedWidth = pParam->edged_width;
2909                    num = 0;
2910    
2911  /* Step 4: Calculate SAD around the Median prediction.  /*              fprintf(stderr,"Warning! Unreliable GME (%d/%d blocks), falling back to translation.\n",num,MBh*MBw);
         MinSAD=SAD  
         If Motion Vector equal to Previous frame motion vector  
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
2912  */  */
2913                    gmc.duv[0].x= gmc.duv[0].y= gmc.duv[1].x= gmc.duv[1].y= gmc.duv[2].x= gmc.duv[2].y=0;
2914    
2915  // Prepare for main loop                  if (!(current->motion_flags & XVID_ME_GME_REFINE))
2916                            return gmc;
2917    
2918                    for (my = 1; my < (uint32_t)MBh-1; my++) /* ignore boundary blocks */
2919          if (!(MotionFlags & PMV_HALFPEL8))                  for (mx = 1; mx < (uint32_t)MBw-1; mx++) /* theirs MVs are often wrong */
2920          {          {
2921                  currMV->x = EVEN(currMV->x);                          const int mbnum = mx + my * MBw;
2922                  currMV->y = EVEN(currMV->y);                          MACROBLOCK *const pMB = &pMBs[mbnum];
2923                            const uint8_t *const pCur = current->image.y + 16*(my*iEdgedWidth + mx);
2924                            if ( (sad16 ( pCur, pCur+1 , iEdgedWidth, 65536) >= gradx )
2925                             &&  (sad16 ( pCur, pCur+iEdgedWidth, iEdgedWidth, 65536) >= grady ) )
2926                             {      pMB->mcsel = 1;
2927                                    gmc.duv[0].x += pMB->mvs[0].x;
2928                                    gmc.duv[0].y += pMB->mvs[0].y;
2929                                    num++;
2930                             }
2931          }          }
2932    
2933          if (currMV->x > max_dx)                  if (gmc.duv[0].x)
2934                  currMV->x=max_dx;                          gmc.duv[0].x /= num;
2935          if (currMV->x < min_dx)                  if (gmc.duv[0].y)
2936                  currMV->x=min_dx;                          gmc.duv[0].y /= num;
2937          if (currMV->y > max_dy)          } else {
                 currMV->y=max_dy;  
         if (currMV->y < min_dy)  
                 currMV->y=min_dy;  
   
 /***************** This is predictor SET A: only median prediction ******************/  
   
2938    
2939          iMinSAD = sad8( cur,                  gmc.duv[0].x=(int)(sol[0]+0.5);
2940                  get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV, iEdgedWidth),                  gmc.duv[0].y=(int)(sol[3]+0.5);
                 iEdgedWidth);  
         iMinSAD += calc_delta_8(currMV->x-pmv[0].x, currMV->y-pmv[0].y, (uint8_t)iFcode) * iQuant;  
2941    
2942                    gmc.duv[1].x=(int)(sol[1]*pParam->width+0.5);
2943                    gmc.duv[1].y=(int)(-sol[2]*pParam->width+0.5);
2944    
2945  // thresh1 is fixed to 256                  gmc.duv[2].x=-gmc.duv[1].y;             /* two warp points only */
2946          if (iMinSAD < 256/4 )                  gmc.duv[2].y=gmc.duv[1].x;
2947            }
2948            if (num>maxblocks)
2949            {       for (my = 1; my < (uint32_t)MBh-1; my++)
2950                    for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2951                  {                  {
2952                          if (MotionFlags & PMV_QUICKSTOP8)                          const int mbnum = mx + my * MBw;
2953                                  goto EPZS8_Terminate_without_Refine;                          if (pMBs[mbnum-1].mcsel)
2954                          if (MotionFlags & PMV_EARLYSTOP8)                                  pMBs[mbnum].mcsel=0;
2955                                  goto EPZS8_Terminate_with_Refine;                          else
2956                                    if (pMBs[mbnum-MBw].mcsel)
2957                                            pMBs[mbnum].mcsel=0;
2958                    }
2959            }
2960            return gmc;
2961                  }                  }
2962    
2963  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/  int
2964    GlobalMotionEstRefine(
2965  // previous frame MV                                  WARPPOINTS *const startwp,
2966          CHECK_MV8_CANDIDATE(pMB->mvs[0].x,pMB->mvs[0].y);                                  MACROBLOCK * const pMBs,
2967                                    const MBParam * const pParam,
2968  // MV=(0,0) is often a good choice                                  const FRAMEINFO * const current,
2969                                    const FRAMEINFO * const reference,
2970          CHECK_MV8_ZERO;                                  const IMAGE * const pCurr,
2971                                    const IMAGE * const pRef,
2972  /* Terminate if MinSAD <= T_2                                  const IMAGE * const pRefH,
2973     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]                                  const IMAGE * const pRefV,
2974  */                                  const IMAGE * const pRefHV)
2975    {
2976            uint8_t* GMCblock = (uint8_t*)malloc(16*pParam->edged_width);
2977            WARPPOINTS bestwp=*startwp;
2978            WARPPOINTS centerwp,currwp;
2979            int gmcminSAD=0;
2980            int gmcSAD=0;
2981            int direction;
2982    //      int mx,my;
2983    
2984          if (iMinSAD < 512/4)    /* T_2 == 512/4 hardcoded */  /* use many blocks... */
2985    /*              for (my = 0; my < (uint32_t)pParam->mb_height; my++)
2986                    for (mx = 0; mx < (uint32_t)pParam->mb_width; mx++)
2987                  {                  {
2988                          if (MotionFlags & PMV_QUICKSTOP8)                          const int mbnum = mx + my * pParam->mb_width;
2989                                  goto EPZS8_Terminate_without_Refine;                          pMBs[mbnum].mcsel=1;
                         if (MotionFlags & PMV_EARLYSTOP8)  
                                 goto EPZS8_Terminate_with_Refine;  
2990                  }                  }
2991    */
2992    
2993  /************ (if Diamond Search)  **************/  /* or rather don't use too many blocks... */
2994    /*
2995          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */                  for (my = 1; my < (uint32_t)MBh-1; my++)
2996                    for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2997                    {
2998                            const int mbnum = mx + my * MBw;
2999                            if (MBmask[mbnum-1])
3000                                    MBmask[mbnum-1]=0;
3001                            else
3002                                    if (MBmask[mbnum-MBw])
3003                                            MBmask[mbnum-1]=0;
3004    
3005          if (!(MotionFlags & PMV_HALFPELDIAMOND8))                  }
3006                  iDiamondSize *= 2;  */
3007                    gmcminSAD = globalSAD(&bestwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3008    
3009  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                  if ( (reference->coding_type == S_VOP)
3010                            && ( (reference->warp.duv[1].x != bestwp.duv[1].x)
3011                              || (reference->warp.duv[1].y != bestwp.duv[1].y)
3012                              || (reference->warp.duv[0].x != bestwp.duv[0].x)
3013                              || (reference->warp.duv[0].y != bestwp.duv[0].y)
3014                              || (reference->warp.duv[2].x != bestwp.duv[2].x)
3015                              || (reference->warp.duv[2].y != bestwp.duv[2].y) ) )
3016                    {
3017                            gmcSAD = globalSAD(&reference->warp, pParam, pMBs,
3018                                                                    current, pRef, pCurr, GMCblock);
3019    
3020  //      if (MotionFlags & PMV_USESQUARES8)                          if (gmcSAD < gmcminSAD)
3021  //              EPZSMainSearchPtr = Square8_MainSearch;                          {       bestwp = reference->warp;
3022  //      else                                  gmcminSAD = gmcSAD;
3023                  EPZSMainSearchPtr = Diamond8_MainSearch;                          }
3024                    }
3025    
3026          iSAD = (*EPZSMainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,          do {
3027                  x, y,                  direction = 0;
3028                  currMV->x, currMV->y, iMinSAD, &newMV,                  centerwp = bestwp;
                 pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                 iDiamondSize, iFcode, iQuant, 00);  
3029    
3030                    currwp = centerwp;
3031    
3032          if (iSAD < iMinSAD)                  currwp.duv[0].x--;
3033          {                  gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3034                  *currMV = newMV;                  if (gmcSAD < gmcminSAD)
3035                  iMinSAD = iSAD;                  {       bestwp = currwp;
3036                            gmcminSAD = gmcSAD;
3037                            direction = 1;
3038          }          }
3039                    else
         if (MotionFlags & PMV_EXTSEARCH8)  
3040          {          {
3041  /* extended mode: search (up to) two more times: orignal prediction and (0,0) */                  currwp = centerwp; currwp.duv[0].x++;
3042                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3043                  if (!(MVequal(pmv[0],backupMV)) )                  if (gmcSAD < gmcminSAD)
3044                    {       bestwp = currwp;
3045                            gmcminSAD = gmcSAD;
3046                            direction = 2;
3047                    }
3048                    }
3049                    if (direction) continue;
3050    
3051                    currwp = centerwp; currwp.duv[0].y--;
3052                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3053                    if (gmcSAD < gmcminSAD)
3054                    {       bestwp = currwp;
3055                            gmcminSAD = gmcSAD;
3056                            direction = 4;
3057                    }
3058                    else
3059                  {                  {
3060                          iSAD = (*EPZSMainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,                  currwp = centerwp; currwp.duv[0].y++;
3061                                  x, y,                  gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3062                          pmv[0].x, pmv[0].y, iMinSAD, &newMV,                  if (gmcSAD < gmcminSAD)
3063                          pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, 0);                  {       bestwp = currwp;
3064                            gmcminSAD = gmcSAD;
3065                          if (iSAD < iMinSAD)                          direction = 8;
3066                    }
3067                    }
3068                    if (direction) continue;
3069    
3070                    currwp = centerwp; currwp.duv[1].x++;
3071                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3072                    if (gmcSAD < gmcminSAD)
3073                    {       bestwp = currwp;
3074                            gmcminSAD = gmcSAD;
3075                            direction = 32;
3076                    }
3077                    currwp.duv[2].y++;
3078                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3079                    if (gmcSAD < gmcminSAD)
3080                    {       bestwp = currwp;
3081                            gmcminSAD = gmcSAD;
3082                            direction = 1024;
3083                    }
3084    
3085                    currwp = centerwp; currwp.duv[1].x--;
3086                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3087                    if (gmcSAD < gmcminSAD)
3088                    {       bestwp = currwp;
3089                            gmcminSAD = gmcSAD;
3090                            direction = 16;
3091                    }
3092                    else
3093                          {                          {
3094                                  *currMV = newMV;                  currwp = centerwp; currwp.duv[1].x++;
3095                                  iMinSAD = iSAD;                  gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3096                    if (gmcSAD < gmcminSAD)
3097                    {       bestwp = currwp;
3098                            gmcminSAD = gmcSAD;
3099                            direction = 32;
3100                    }
3101                    }
3102                    if (direction) continue;
3103    
3104    
3105                    currwp = centerwp; currwp.duv[1].y--;
3106                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3107                    if (gmcSAD < gmcminSAD)
3108                    {       bestwp = currwp;
3109                            gmcminSAD = gmcSAD;
3110                            direction = 64;
3111                          }                          }
3112                    else
3113                    {
3114                    currwp = centerwp; currwp.duv[1].y++;
3115                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3116                    if (gmcSAD < gmcminSAD)
3117                    {       bestwp = currwp;
3118                            gmcminSAD = gmcSAD;
3119                            direction = 128;
3120                    }
3121                    }
3122                    if (direction) continue;
3123    
3124                    currwp = centerwp; currwp.duv[2].x--;
3125                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3126                    if (gmcSAD < gmcminSAD)
3127                    {       bestwp = currwp;
3128                            gmcminSAD = gmcSAD;
3129                            direction = 256;
3130                  }                  }
3131                    else
                 if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )  
3132                  {                  {
3133                          iSAD = (*EPZSMainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,                  currwp = centerwp; currwp.duv[2].x++;
3134                                  x, y,                  gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3135                          0, 0, iMinSAD, &newMV,                  if (gmcSAD < gmcminSAD)
3136                          pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, 0);                  {       bestwp = currwp;
3137                            gmcminSAD = gmcSAD;
3138                          if (iSAD < iMinSAD)                          direction = 512;
3139                    }
3140                    }
3141                    if (direction) continue;
3142    
3143                    currwp = centerwp; currwp.duv[2].y--;
3144                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3145                    if (gmcSAD < gmcminSAD)
3146                    {       bestwp = currwp;
3147                            gmcminSAD = gmcSAD;
3148                            direction = 1024;
3149                    }
3150                    else
3151                          {                          {
3152                                  *currMV = newMV;                  currwp = centerwp; currwp.duv[2].y++;
3153                                  iMinSAD = iSAD;                  gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3154                    if (gmcSAD < gmcminSAD)
3155                    {       bestwp = currwp;
3156                            gmcminSAD = gmcSAD;
3157                            direction = 2048;
3158                          }                          }
3159                  }                  }
3160            } while (direction);
3161            free(GMCblock);
3162    
3163            *startwp = bestwp;
3164    
3165            return gmcminSAD;
3166          }          }
3167    
3168  /***************        Choose best MV found     **************/  int
3169    globalSAD(const WARPPOINTS *const wp,
3170                      const MBParam * const pParam,
3171                      const MACROBLOCK * const pMBs,
3172                      const FRAMEINFO * const current,
3173                      const IMAGE * const pRef,
3174                      const IMAGE * const pCurr,
3175                      uint8_t *const GMCblock)
3176    {
3177            NEW_GMC_DATA gmc_data;
3178            int iSAD, gmcSAD=0;
3179            int num=0;
3180            unsigned int mx, my;
3181    
3182            generate_GMCparameters( 3, 3, wp, pParam->width, pParam->height, &gmc_data);
3183    
3184            for (my = 0; my < (uint32_t)pParam->mb_height; my++)
3185                    for (mx = 0; mx < (uint32_t)pParam->mb_width; mx++) {
3186    
3187  EPZS8_Terminate_with_Refine:                  const int mbnum = mx + my * pParam->mb_width;
3188          if (MotionFlags & PMV_HALFPELREFINE8)           // perform final half-pel step                  const int iEdgedWidth = pParam->edged_width;
                 iMinSAD = Halfpel8_Refine( pRef, pRefH, pRefV, pRefHV, cur,  
                                 x, y,  
                                 currMV, iMinSAD,  
                                 pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);  
3189    
3190  EPZS8_Terminate_without_Refine:                  if (!pMBs[mbnum].mcsel)
3191                            continue;
3192    
3193          currPMV->x = currMV->x - pmv[0].x;                  gmc_data.predict_16x16(&gmc_data, GMCblock,
3194          currPMV->y = currMV->y - pmv[0].y;                                                  pRef->y,
3195          return iMinSAD;                                                  iEdgedWidth,
3196                                                    iEdgedWidth,
3197                                                    mx, my,
3198                                                    pParam->m_rounding_type);
3199    
3200                    iSAD = sad16 ( pCurr->y + 16*(my*iEdgedWidth + mx),
3201                                                    GMCblock , iEdgedWidth, 65536);
3202                    iSAD -= pMBs[mbnum].sad16;
3203    
3204                    if (iSAD<0)
3205                            gmcSAD += iSAD;
3206                    num++;
3207            }
3208            return gmcSAD;
3209  }  }
3210    

Legend:
Removed from v.96  
changed lines
  Added in v.1135

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