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

Legend:
Removed from v.141  
changed lines
  Added in v.1137

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