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

Legend:
Removed from v.117  
changed lines
  Added in v.1136

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