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

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

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