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

Diff of /branches/dev-api-4/xvidcore/src/motion/motion_est.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

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

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