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

Legend:
Removed from v.115  
changed lines
  Added in v.1138

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