[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 252, Sun Jun 30 10:46:29 2002 UTC branches/dev-api-4/xvidcore/src/motion/motion_est.c revision 1081, Thu Jul 10 17:41:48 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.21 2003-07-10 17:41:48 edgomez 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), (D), &iDirection, data ); }
74    
75    /*****************************************************************************
76     * Code
77     ****************************************************************************/
78    
79  // very large value  static __inline uint32_t
80  #define MV_MAX_ERROR    (4096 * 256)  d_mv_bits(int x, int y, const VECTOR pred, const uint32_t iFcode, const int qpel, const int rrv)
81    {
82            int bits;
83            const int q = (1 << (iFcode - 1)) - 1;
84    
85  // stop search if sdelta < THRESHOLD          x <<= qpel;
86  #define MV16_THRESHOLD  192          y <<= qpel;
87  #define MV8_THRESHOLD   56          if (rrv) { x = RRV_MV_SCALEDOWN(x); y = RRV_MV_SCALEDOWN(y); }
88    
89            x -= pred.x;
90            bits = (x != 0 ? iFcode:0);
91            x = abs(x);
92            x += q;
93            x >>= (iFcode - 1);
94            bits += mvtab[x];
95    
96            y -= pred.y;
97            bits += (y != 0 ? iFcode:0);
98            y = abs(y);
99            y += q;
100            y >>= (iFcode - 1);
101            bits += mvtab[y];
102    
103            return bits;
104    }
105    
106    static int32_t ChromaSAD2(const int fx, const int fy, const int bx, const int by,
107                                                            const SearchData * const data)
108    {
109            int sad;
110            const uint32_t stride = data->iEdgedWidth/2;
111            uint8_t * f_refu = data->RefQ,
112                    * f_refv = data->RefQ + 8,
113                    * b_refu = data->RefQ + 16,
114                    * b_refv = data->RefQ + 24;
115            int offset = (fx>>1) + (fy>>1)*stride;
116    
117            switch (((fx & 1) << 1) | (fy & 1))     {
118                    case 0:
119                            f_refu = (uint8_t*)data->RefP[4] + offset;
120                            f_refv = (uint8_t*)data->RefP[5] + offset;
121                            break;
122                    case 1:
123                            interpolate8x8_halfpel_v(f_refu, data->RefP[4] + offset, stride, data->rounding);
124                            interpolate8x8_halfpel_v(f_refv, data->RefP[5] + offset, stride, data->rounding);
125                            break;
126                    case 2:
127                            interpolate8x8_halfpel_h(f_refu, data->RefP[4] + offset, stride, data->rounding);
128                            interpolate8x8_halfpel_h(f_refv, data->RefP[5] + offset, stride, data->rounding);
129                            break;
130                    default:
131                            interpolate8x8_halfpel_hv(f_refu, data->RefP[4] + offset, stride, data->rounding);
132                            interpolate8x8_halfpel_hv(f_refv, data->RefP[5] + offset, stride, data->rounding);
133                            break;
134            }
135    
136  #define NEIGH_MOVE_THRESH 0          offset = (bx>>1) + (by>>1)*stride;
137  // how much a block's MV must differ from his neighbour          switch (((bx & 1) << 1) | (by & 1))     {
138  // to be search for INTER4V. The more, the faster...                  case 0:
139                            b_refu = (uint8_t*)data->b_RefP[4] + offset;
140                            b_refv = (uint8_t*)data->b_RefP[5] + offset;
141                            break;
142                    case 1:
143                            interpolate8x8_halfpel_v(b_refu, data->b_RefP[4] + offset, stride, data->rounding);
144                            interpolate8x8_halfpel_v(b_refv, data->b_RefP[5] + offset, stride, data->rounding);
145                            break;
146                    case 2:
147                            interpolate8x8_halfpel_h(b_refu, data->b_RefP[4] + offset, stride, data->rounding);
148                            interpolate8x8_halfpel_h(b_refv, data->b_RefP[5] + offset, stride, data->rounding);
149                            break;
150                    default:
151                            interpolate8x8_halfpel_hv(b_refu, data->b_RefP[4] + offset, stride, data->rounding);
152                            interpolate8x8_halfpel_hv(b_refv, data->b_RefP[5] + offset, stride, data->rounding);
153                            break;
154            }
155    
156  /* sad16(0,0) bias; mpeg4 spec suggests nb/2+1 */          sad = sad8bi(data->CurU, b_refu, f_refu, stride);
157  /* nb  = vop pixels * 2^(bpp-8) */          sad += sad8bi(data->CurV, b_refv, f_refv, stride);
 #define MV16_00_BIAS    (128+1)  
 #define MV8_00_BIAS     (0)  
158    
159  /* INTER bias for INTER/INTRA decision; mpeg4 spec suggests 2*nb */          return sad;
160  #define MV16_INTER_BIAS 512  }
161    
162  /* Parameters which control inter/inter4v decision */  static int32_t
163  #define IMV16X16                        5  ChromaSAD(const int dx, const int dy, const SearchData * const data)
164    {
165            int sad;
166            const uint32_t stride = data->iEdgedWidth/2;
167            int offset = (dx>>1) + (dy>>1)*stride;
168    
169  /* vector map (vlc delta size) smoother parameters */          if (dx == data->temp[5] && dy == data->temp[6]) return data->temp[7]; /* it has been checked recently */
170  #define NEIGH_TEND_16X16        2          data->temp[5] = dx; data->temp[6] = dy; /* backup */
 #define NEIGH_TEND_8X8          2  
171    
172  // fast ((A)/2)*2          switch (((dx & 1) << 1) | (dy & 1))     {
173  #define EVEN(A)         (((A)<0?(A)+1:(A)) & ~1)                  case 0:
174                            sad = sad8(data->CurU, data->RefP[4] + offset, stride);
175                            sad += sad8(data->CurV, data->RefP[5] + offset, stride);
176                            break;
177                    case 1:
178                            sad = sad8bi(data->CurU, data->RefP[4] + offset, data->RefP[4] + offset + stride, stride);
179                            sad += sad8bi(data->CurV, data->RefP[5] + offset, data->RefP[5] + offset + stride, stride);
180                            break;
181                    case 2:
182                            sad = sad8bi(data->CurU, data->RefP[4] + offset, data->RefP[4] + offset + 1, stride);
183                            sad += sad8bi(data->CurV, data->RefP[5] + offset, data->RefP[5] + offset + 1, stride);
184                            break;
185                    default:
186                            interpolate8x8_halfpel_hv(data->RefQ, data->RefP[4] + offset, stride, data->rounding);
187                            sad = sad8(data->CurU, data->RefQ, stride);
188    
189  #define MVzero(A) ( ((A).x)==(0) && ((A).y)==(0) )                          interpolate8x8_halfpel_hv(data->RefQ, data->RefP[5] + offset, stride, data->rounding);
190  #define MVequal(A,B) ( ((A).x)==((B).x) && ((A).y)==((B).y) )                          sad += sad8(data->CurV, data->RefQ, stride);
191                            break;
192            }
193            data->temp[7] = sad; /* backup, part 2 */
194            return sad;
195    }
196    
197  int32_t PMVfastSearch16(const uint8_t * const pRef,  static __inline const uint8_t *
198                                                  const uint8_t * const pRefH,  GetReferenceB(const int x, const int y, const uint32_t dir, const SearchData * const data)
199                                                  const uint8_t * const pRefV,  {
200                                                  const uint8_t * const pRefHV,          /* dir : 0 = forward, 1 = backward */
201                                                  const IMAGE * const pCur,          const uint8_t *const *const direction = ( dir == 0 ? data->RefP : data->b_RefP );
202                                                  const int x,          const int picture = ((x&1)<<1) | (y&1);
203                                                  const int y,          const int offset = (x>>1) + (y>>1)*data->iEdgedWidth;
204                                                  const uint32_t MotionFlags,          return direction[picture] + offset;
205                                                  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);  
206    
207  int32_t EPZSSearch16(const uint8_t * const pRef,  /* this is a simpler copy of GetReferenceB, but as it's __inline anyway, we can keep the two separate */
208                                           const uint8_t * const pRefH,  static __inline const uint8_t *
209                                           const uint8_t * const pRefV,  GetReference(const int x, const int y, const SearchData * const data)
210                                           const uint8_t * const pRefHV,  {
211                                           const IMAGE * const pCur,          const int picture = ((x&1)<<1) | (y&1);
212                                           const int x,          const int offset = (x>>1) + (y>>1)*data->iEdgedWidth;
213                                           const int y,          return data->RefP[picture] + offset;
214                                           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);  
215    
216    static uint8_t *
217    Interpolate8x8qpel(const int x, const int y, const uint32_t block, const uint32_t dir, const SearchData * const data)
218    {
219            /* create or find a qpel-precision reference picture; return pointer to it */
220            uint8_t * Reference = data->RefQ + 16*dir;
221            const uint32_t iEdgedWidth = data->iEdgedWidth;
222            const uint32_t rounding = data->rounding;
223            const int halfpel_x = x/2;
224            const int halfpel_y = y/2;
225            const uint8_t *ref1, *ref2, *ref3, *ref4;
226    
227  int32_t PMVfastSearch8(const uint8_t * const pRef,          ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
228                                             const uint8_t * const pRefH,          ref1 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
229                                             const uint8_t * const pRefV,          switch( ((x&1)<<1) + (y&1) ) {
230                                             const uint8_t * const pRefHV,          case 3: /* x and y in qpel resolution - the "corners" (top left/right and */
231                                             const IMAGE * const pCur,                          /* bottom left/right) during qpel refinement */
232                                             const int x,                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
233                                             const int y,                  ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
234                                             const int start_x,                  ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);
235                                             const int start_y,                  ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
236                                             const uint32_t MotionFlags,                  ref3 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
237                                             const uint32_t iQuant,                  ref4 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
238                                             const uint32_t iFcode,                  interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
239                                             const MBParam * const pParam,                  break;
                                            const MACROBLOCK * const pMBs,  
                                            const MACROBLOCK * const prevMBs,  
                                            VECTOR * const currMV,  
                                            VECTOR * const currPMV);  
240    
241  int32_t EPZSSearch8(const uint8_t * const pRef,          case 1: /* x halfpel, y qpel - top or bottom during qpel refinement */
242                                          const uint8_t * const pRefH,                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
243                                          const uint8_t * const pRefV,                  ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
244                                          const uint8_t * const pRefHV,                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
245                                          const IMAGE * const pCur,                  break;
                                         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);  
246    
247            case 2: /* x qpel, y halfpel - left or right during qpel refinement */
248                    ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
249                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
250                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
251                    break;
252    
253  typedef int32_t(MainSearch16Func) (const uint8_t * const pRef,          default: /* pure halfpel position */
254                                                                     const uint8_t * const pRefH,                  return (uint8_t *) ref1;
                                                                    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);  
255    
256  typedef MainSearch16Func *MainSearch16FuncPtr;          }
257            return Reference;
258    }
259    
260    static uint8_t *
261    Interpolate16x16qpel(const int x, const int y, const uint32_t dir, const SearchData * const data)
262    {
263            /* create or find a qpel-precision reference picture; return pointer to it */
264            uint8_t * Reference = data->RefQ + 16*dir;
265            const uint32_t iEdgedWidth = data->iEdgedWidth;
266            const uint32_t rounding = data->rounding;
267            const int halfpel_x = x/2;
268            const int halfpel_y = y/2;
269            const uint8_t *ref1, *ref2, *ref3, *ref4;
270    
271  typedef int32_t(MainSearch8Func) (const uint8_t * const pRef,          ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
272                                                                    const uint8_t * const pRefH,          switch( ((x&1)<<1) + (y&1) ) {
273                                                                    const uint8_t * const pRefV,          case 3:
274                                                                    const uint8_t * const pRefHV,                  /*
275                                                                    const uint8_t * const cur,                   * x and y in qpel resolution - the "corners" (top left/right and
276                                                                    const int x,                   * bottom left/right) during qpel refinement
277                                                                    const int y,                   */
278                                                                    int32_t startx,                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
279                                                                    int32_t starty,                  ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
280                                                                    int32_t iMinSAD,                  ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);
281                                                                    VECTOR * const currMV,                  interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
282                                                                    const VECTOR * const pmv,                  interpolate8x8_avg4(Reference+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, rounding);
283                                                                    const int32_t min_dx,                  interpolate8x8_avg4(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, rounding);
284                                                                    const int32_t max_dx,                  interpolate8x8_avg4(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, rounding);
285                                                                    const int32_t min_dy,                  break;
                                                                   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 */  
286    
287            case 1: /* x halfpel, y qpel - top or bottom during qpel refinement */
288                    ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
289                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
290                    interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
291                    interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
292                    interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
293                    break;
294    
295            case 2: /* x qpel, y halfpel - left or right during qpel refinement */
296                    ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
297                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
298                    interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
299                    interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
300                    interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
301                    break;
302    
303  // mv.length table          default: /* pure halfpel position */
304  static const uint32_t mvtab[33] = {                  return (uint8_t *) ref1;
305          1, 2, 3, 4, 6, 7, 7, 7,          }
306          9, 9, 9, 10, 10, 10, 10, 10,          return Reference;
307          10, 10, 10, 10, 10, 10, 10, 10,  }
         10, 11, 11, 11, 11, 11, 11, 12, 12  
 };  
308    
309    /* CHECK_CANDIATE FUNCTIONS START */
310    
311  static __inline uint32_t  static void
312  mv_bits(int32_t component,  CheckCandidate16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                 const uint32_t iFcode)  
313  {  {
314          if (component == 0)          int xc, yc;
315                  return 1;          const uint8_t * Reference;
316            VECTOR * current;
317          if (component < 0)          int32_t sad; uint32_t t;
                 component = -component;  
318    
319          if (iFcode == 1) {          if ( (x > data->max_dx) || (x < data->min_dx)
320                  if (component > 32)                  || (y > data->max_dy) || (y < data->min_dy) ) return;
                         component = 32;  
321    
322                  return mvtab[component] + 1;          if (!data->qpel_precision) {
323                    Reference = GetReference(x, y, data);
324                    current = data->currentMV;
325                    xc = x; yc = y;
326            } else { /* x and y are in 1/4 precision */
327                    Reference = Interpolate16x16qpel(x, y, 0, data);
328                    xc = x/2; yc = y/2; /* for chroma sad */
329                    current = data->currentQMV;
330          }          }
331    
332          component += (1 << (iFcode - 1)) - 1;          sad = sad16v(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
333          component >>= (iFcode - 1);          t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
334    
335          if (component > 32)          sad += (data->lambda16 * t * sad)>>10;
336                  component = 32;          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;
337    
338          return mvtab[component] + 1 + iFcode - 1;          if (data->chroma) sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
339                                                                               (yc >> 1) + roundtab_79[yc & 0x3], data);
340    
341            if (sad < data->iMinSAD[0]) {
342                    data->iMinSAD[0] = sad;
343                    current[0].x = x; current[0].y = y;
344                    *dir = Direction;
345  }  }
346    
347            if (data->temp[1] < data->iMinSAD[1]) {
348                    data->iMinSAD[1] = data->temp[1]; current[1].x = x; current[1].y = y; }
349            if (data->temp[2] < data->iMinSAD[2]) {
350                    data->iMinSAD[2] = data->temp[2]; current[2].x = x; current[2].y = y; }
351            if (data->temp[3] < data->iMinSAD[3]) {
352                    data->iMinSAD[3] = data->temp[3]; current[3].x = x; current[3].y = y; }
353            if (data->temp[4] < data->iMinSAD[4]) {
354                    data->iMinSAD[4] = data->temp[4]; current[4].x = x; current[4].y = y; }
355    }
356    
357  static __inline uint32_t  static void
358  calc_delta_16(const int32_t dx,  CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                           const int32_t dy,  
                           const uint32_t iFcode,  
                           const uint32_t iQuant)  
359  {  {
360          return NEIGH_TEND_16X16 * lambda_vec16[iQuant] * (mv_bits(dx, iFcode) +          int32_t sad; uint32_t t;
361                                                                                                            mv_bits(dy, iFcode));          const uint8_t * Reference;
362            VECTOR * current;
363    
364            if ( (x > data->max_dx) || (x < data->min_dx)
365                    || (y > data->max_dy) || (y < data->min_dy) ) return;
366    
367            if (!data->qpel_precision) {
368                    Reference = GetReference(x, y, data);
369                    current = data->currentMV;
370            } else { /* x and y are in 1/4 precision */
371                    Reference = Interpolate8x8qpel(x, y, 0, 0, data);
372                    current = data->currentQMV;
373  }  }
374    
375  static __inline uint32_t          sad = sad8(data->Cur, Reference, data->iEdgedWidth);
376  calc_delta_8(const int32_t dx,          t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
377                           const int32_t dy,  
378                           const uint32_t iFcode,          sad += (data->lambda8 * t * (sad+NEIGH_8X8_BIAS))>>10;
379                           const uint32_t iQuant)  
380  {          if (sad < *(data->iMinSAD)) {
381          return NEIGH_TEND_8X8 * lambda_vec8[iQuant] * (mv_bits(dx, iFcode) +                  *(data->iMinSAD) = sad;
382                                                                                                     mv_bits(dy, iFcode));                  current->x = x; current->y = y;
383                    *dir = Direction;
384            }
385  }  }
386    
387    static void
388    CheckCandidate32(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
389    {
390            uint32_t t;
391            const uint8_t * Reference;
392    
393            if ( (!(x&1) && x !=0) || (!(y&1) && y !=0) || /* non-zero even value */
394                    (x > data->max_dx) || (x < data->min_dx)
395                    || (y > data->max_dy) || (y < data->min_dy) ) return;
396    
397            Reference = GetReference(x, y, data);
398            t = d_mv_bits(x, y, data->predMV, data->iFcode, 0, 1);
399    
400            data->temp[0] = sad32v_c(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
401    
402  #ifndef SEARCH16          data->temp[0] += (data->lambda16 * t * data->temp[0]) >> 10;
403  #define SEARCH16        PMVfastSearch16          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;
 //#define SEARCH16  FullSearch16  
 //#define SEARCH16  EPZSSearch16  
 #endif  
404    
405  #ifndef SEARCH8          if (data->temp[0] < data->iMinSAD[0]) {
406  #define SEARCH8         PMVfastSearch8                  data->iMinSAD[0] = data->temp[0];
407  //#define SEARCH8   EPZSSearch8                  data->currentMV[0].x = x; data->currentMV[0].y = y;
408  #endif                  *dir = Direction; }
409    
410  bool          if (data->temp[1] < data->iMinSAD[1]) {
411  MotionEstimation(MBParam * const pParam,                  data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
412                                   FRAMEINFO * const current,          if (data->temp[2] < data->iMinSAD[2]) {
413                                   FRAMEINFO * const reference,                  data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
414                                   const IMAGE * const pRefH,          if (data->temp[3] < data->iMinSAD[3]) {
415                                   const IMAGE * const pRefV,                  data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
416                                   const IMAGE * const pRefHV,          if (data->temp[4] < data->iMinSAD[4]) {
417                                   const uint32_t iLimit)                  data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
418  {  }
         const uint32_t iWcount = pParam->mb_width;  
         const uint32_t iHcount = pParam->mb_height;  
         MACROBLOCK *const pMBs = current->mbs;  
         MACROBLOCK *const prevMBs = reference->mbs;  
         const IMAGE *const pCurrent = &current->image;  
         const IMAGE *const pRef = &reference->image;  
419    
420          const VECTOR zeroMV = { 0, 0 };  static void
421    CheckCandidate16no4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
422    {
423            int32_t sad, xc, yc;
424            const uint8_t * Reference;
425            uint32_t t;
426            VECTOR * current;
427    
428          int32_t x, y;          if ( (x > data->max_dx) || ( x < data->min_dx)
429          int32_t iIntra = 0;                  || (y > data->max_dy) || (y < data->min_dy) ) return;
         VECTOR pmv;  
   
         if (sadInit)  
                 (*sadInit) ();  
   
         for (y = 0; y < iHcount; y++)  
                 for (x = 0; x < iWcount; x++) {  
                         MACROBLOCK *const pMB = &pMBs[x + y * iWcount];  
   
                         pMB->sad16 =  
                                 SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,  
                                                  y, current->motion_flags, current->quant,  
                                                  current->fcode, pParam, pMBs, prevMBs, &pMB->mv16,  
                                                  &pMB->pmvs[0]);  
430    
431                          if (0 < (pMB->sad16 - MV16_INTER_BIAS)) {          if (data->rrv && (!(x&1) && x !=0) | (!(y&1) && y !=0) ) return; /* non-zero even value */
                                 int32_t deviation;  
432    
433                                  deviation =          if (data->qpel_precision) { /* x and y are in 1/4 precision */
434                                          dev16(pCurrent->y + x * 16 + y * 16 * pParam->edged_width,                  Reference = Interpolate16x16qpel(x, y, 0, data);
435                                                    pParam->edged_width);                  current = data->currentQMV;
436                    xc = x/2; yc = y/2;
437            } else {
438                    Reference = GetReference(x, y, data);
439                    current = data->currentMV;
440                    xc = x; yc = y;
441            }
442            t = d_mv_bits(x, y, data->predMV, data->iFcode,
443                                            data->qpel^data->qpel_precision, data->rrv);
444    
445                                  if (deviation < (pMB->sad16 - MV16_INTER_BIAS)) {          sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
446                                          pMB->mode = MODE_INTRA;          sad += (data->lambda16 * t * sad)>>10;
                                         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;  
447    
448                                          iIntra++;          if (data->chroma) sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
449                                          if (iIntra >= iLimit)                                                                                  (yc >> 1) + roundtab_79[yc & 0x3], data);
                                                 return 1;  
450    
451                                          continue;          if (sad < *(data->iMinSAD)) {
452                    *(data->iMinSAD) = sad;
453                    current->x = x; current->y = y;
454                    *dir = Direction;
455                                  }                                  }
456                          }                          }
457    
458                          pmv = pMB->pmvs[0];  static void
459                          if (current->global_flags & XVID_INTER4V)  CheckCandidate16I(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
460                                  if ((!(current->global_flags & XVID_LUMIMASKING) ||  {
461                                           pMB->dquant == NO_CHANGE)) {          int sad;
462                                          int32_t sad8 = IMV16X16 * current->quant;  //      int xc, yc;
463            const uint8_t * Reference;
464                                          if (sad8 < pMB->sad16)  //      VECTOR * current;
465    
466                                                  sad8 += pMB->sad8[0] =          if ( (x > data->max_dx) || ( x < data->min_dx)
467                                                          SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,                  || (y > data->max_dy) || (y < data->min_dy) ) return;
                                                                         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]);  
468    
469                                          /* decide: MODE_INTER or MODE_INTER4V          Reference = GetReference(x, y, data);
470                                             mpeg4:   if (sad8 < pMB->sad16 - nb/2+1) use_inter4v  //      xc = x; yc = y;
471    
472            sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
473    //      sad += d_mv_bits(x, y, data->predMV, data->iFcode, 0, 0);
474    
475    /*      if (data->chroma) sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
476                                                                                    (yc >> 1) + roundtab_79[yc & 0x3], data);
477                                           */                                           */
478    
479                                          if (sad8 < pMB->sad16) {          if (sad < data->iMinSAD[0]) {
480                                                  pMB->mode = MODE_INTER4V;                  data->iMinSAD[0] = sad;
481                                                  pMB->sad8[0] *= 4;                  data->currentMV[0].x = x; data->currentMV[0].y = y;
482                                                  pMB->sad8[1] *= 4;                  *dir = Direction;
                                                 pMB->sad8[2] *= 4;  
                                                 pMB->sad8[3] *= 4;  
                                                 continue;  
483                                          }                                          }
   
484                                  }                                  }
485    
486                          pMB->mode = MODE_INTER;  static void
487                          pMB->pmvs[0] = pmv;     /* pMB->pmvs[1] = pMB->pmvs[2] = pMB->pmvs[3]  are not needed for INTER */  CheckCandidate32I(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
488                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mv16;  {
489                          pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] =          /* maximum speed - for P/B/I decision */
490                                  pMB->sad16;          int32_t sad;
491    
492            if ( (x > data->max_dx) || (x < data->min_dx)
493                    || (y > data->max_dy) || (y < data->min_dy) ) return;
494    
495            sad = sad32v_c(data->Cur, data->RefP[0] + (int)((x>>1) + (y>>1)*(data->iEdgedWidth)),
496                                            data->iEdgedWidth, data->temp+1);
497    
498            if (sad < *(data->iMinSAD)) {
499                    *(data->iMinSAD) = sad;
500                    data->currentMV[0].x = x; data->currentMV[0].y = y;
501                    *dir = Direction;
502                  }                  }
503          return 0;          if (data->temp[1] < data->iMinSAD[1]) {
504  }                  data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
505            if (data->temp[2] < data->iMinSAD[2]) {
506                    data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
507            if (data->temp[3] < data->iMinSAD[3]) {
508                    data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
509            if (data->temp[4] < data->iMinSAD[4]) {
510                    data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
511    
 #define CHECK_MV16_ZERO {\  
   if ( (0 <= max_dx) && (0 >= min_dx) \  
     && (0 <= max_dy) && (0 >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \  
     iSAD += calc_delta_16(-pmv[0].x, -pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=0; currMV->y=0; }  }     \  
 }  
   
 #define NOCHECK_MV16_CANDIDATE(X,Y) { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \  
 }  
   
 #define CHECK_MV16_CANDIDATE(X,Y) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_CANDIDATE_DIR(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \  
 }  
   
 #define CHECK_MV16_CANDIDATE_FOUND(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
 }  
   
   
 #define CHECK_MV8_ZERO {\  
   iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, 0, 0 , iEdgedWidth), iEdgedWidth); \  
   iSAD += calc_delta_8(-pmv[0].x, -pmv[0].y, (uint8_t)iFcode, iQuant);\  
   if (iSAD < iMinSAD) \  
   { iMinSAD=iSAD; currMV->x=0; currMV->y=0; } \  
 }  
   
 #define NOCHECK_MV8_CANDIDATE(X,Y) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \  
 }  
   
 #define CHECK_MV8_CANDIDATE(X,Y) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV8_CANDIDATE_DIR(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \  
 }  
   
 #define CHECK_MV8_CANDIDATE_FOUND(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
512  }  }
513    
514  /* too slow and not fully functional at the moment */  static void
515  /*  CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)
 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)  
516  {  {
517          const int32_t iEdgedWidth = pParam->edged_width;          int32_t sad, xb, yb, xcf, ycf, xcb, ycb;
518          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;          uint32_t t;
519          int32_t iSAD;          const uint8_t *ReferenceF, *ReferenceB;
520          int32_t pred_x,pred_y;          VECTOR *current;
   
         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;  
521    
522          return iSAD;          if ((xf > data->max_dx) || (xf < data->min_dx) ||
523                    (yf > data->max_dy) || (yf < data->min_dy))
524                    return;
525    
526            if (!data->qpel_precision) {
527                    ReferenceF = GetReference(xf, yf, data);
528                    xb = data->currentMV[1].x; yb = data->currentMV[1].y;
529                    ReferenceB = GetReferenceB(xb, yb, 1, data);
530                    current = data->currentMV;
531                    xcf = xf; ycf = yf;
532                    xcb = xb; ycb = yb;
533            } else {
534                    ReferenceF = Interpolate16x16qpel(xf, yf, 0, data);
535                    xb = data->currentQMV[1].x; yb = data->currentQMV[1].y;
536                    current = data->currentQMV;
537                    ReferenceB = Interpolate16x16qpel(xb, yb, 1, data);
538                    xcf = xf/2; ycf = yf/2;
539                    xcb = xb/2; ycb = yb/2;
540            }
541    
542            t = d_mv_bits(xf, yf, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0)
543                     + d_mv_bits(xb, yb, data->bpredMV, data->iFcode, data->qpel^data->qpel_precision, 0);
544    
545            sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
546            sad += (data->lambda16 * t * sad)>>10;
547    
548            if (data->chroma) sad += ChromaSAD2((xcf >> 1) + roundtab_79[xcf & 0x3],
549                                                                                    (ycf >> 1) + roundtab_79[ycf & 0x3],
550                                                                                    (xcb >> 1) + roundtab_79[xcb & 0x3],
551                                                                                    (ycb >> 1) + roundtab_79[ycb & 0x3], data);
552    
553            if (sad < *(data->iMinSAD)) {
554                    *(data->iMinSAD) = sad;
555                    current->x = xf; current->y = yf;
556                    *dir = Direction;
557            }
558  }  }
 */  
559    
560  int32_t  static void
561  Diamond16_MainSearch(const uint8_t * const pRef,  CheckCandidateDirect(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
562                                           const uint8_t * const pRefH,  {
563                                           const uint8_t * const pRefV,          int32_t sad = 0, xcf = 0, ycf = 0, xcb = 0, ycb = 0;
564                                           const uint8_t * const pRefHV,          uint32_t k;
565                                           const uint8_t * const cur,          const uint8_t *ReferenceF;
566                                           const int x,          const uint8_t *ReferenceB;
567                                           const int y,          VECTOR mvs, b_mvs;
568                                           int32_t startx,  
569                                           int32_t starty,          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
570                                           int32_t iMinSAD,  
571                                           VECTOR * const currMV,          for (k = 0; k < 4; k++) {
572                                           const VECTOR * const pmv,                  mvs.x = data->directmvF[k].x + x;
573                                           const int32_t min_dx,                  b_mvs.x = ((x == 0) ?
574                                           const int32_t max_dx,                          data->directmvB[k].x
575                                           const int32_t min_dy,                          : mvs.x - data->referencemv[k].x);
576                                           const int32_t max_dy,  
577                                           const int32_t iEdgedWidth,                  mvs.y = data->directmvF[k].y + y;
578                                           const int32_t iDiamondSize,                  b_mvs.y = ((y == 0) ?
579                                           const int32_t iFcode,                          data->directmvB[k].y
580                                           const int32_t iQuant,                          : mvs.y - data->referencemv[k].y);
581                                           int iFound)  
582  {                  if ((mvs.x > data->max_dx)   || (mvs.x < data->min_dx)   ||
583  /* Do a diamond search around given starting point, return SAD of best */                          (mvs.y > data->max_dy)   || (mvs.y < data->min_dy)   ||
584                            (b_mvs.x > data->max_dx) || (b_mvs.x < data->min_dx) ||
585          int32_t iDirection = 0;                          (b_mvs.y > data->max_dy) || (b_mvs.y < data->min_dy) )
586          int32_t iSAD;                          return;
587          VECTOR backupMV;  
588                    if (data->qpel) {
589          backupMV.x = startx;                          xcf += mvs.x/2; ycf += mvs.y/2;
590          backupMV.y = starty;                          xcb += b_mvs.x/2; ycb += b_mvs.y/2;
   
 /* 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);  
591          } else {          } else {
592                  currMV->x = startx;                          xcf += mvs.x; ycf += mvs.y;
593                  currMV->y = starty;                          xcb += b_mvs.x; ycb += b_mvs.y;
594                            mvs.x *= 2; mvs.y *= 2; /* we move to qpel precision anyway */
595                            b_mvs.x *= 2; b_mvs.y *= 2;
596          }          }
597          return iMinSAD;  
598                    ReferenceF = Interpolate8x8qpel(mvs.x, mvs.y, k, 0, data);
599                    ReferenceB = Interpolate8x8qpel(b_mvs.x, b_mvs.y, k, 1, data);
600    
601                    sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
602                                                    ReferenceF, ReferenceB, data->iEdgedWidth);
603                    if (sad > *(data->iMinSAD)) return;
604  }  }
605    
606  int32_t          sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;
 Square16_MainSearch(const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x,  
                                         const int y,  
                                         int32_t startx,  
                                         int32_t starty,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                         const VECTOR * const pmv,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a 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  
 */  
607    
608          CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);          if (data->chroma) sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],
609          CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);                                                                                  (ycf >> 3) + roundtab_76[ycf & 0xf],
610          CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);                                                                                  (xcb >> 3) + roundtab_76[xcb & 0xf],
611          CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);                                                                                  (ycb >> 3) + roundtab_76[ycb & 0xf], data);
   
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 5);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 6);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 7);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 8);  
   
   
         if (iDirection)  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;  
612    
613                          switch (iDirection) {          if (sad < *(data->iMinSAD)) {
614                          case 1:                  *(data->iMinSAD) = sad;
615                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  data->currentMV->x = x; data->currentMV->y = y;
616                                                                                     backupMV.y, 1);                  *dir = Direction;
617                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,          }
618                                                                                   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;  
619    
620                          case 3:  static void
621                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize,  CheckCandidateDirectno4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
622                                                                                   4);  {
623                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,          int32_t sad, xcf, ycf, xcb, ycb;
624                                                                                   backupMV.y - iDiamondSize, 7);          const uint8_t *ReferenceF;
625                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,          const uint8_t *ReferenceB;
626                                                                                   backupMV.y + iDiamondSize, 8);          VECTOR mvs, b_mvs;
                                 break;  
627    
628                          case 4:          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
                                 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;  
   
                         case 5:  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
   
                         case 6:  
                                 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 - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
629    
630                                  break;          mvs.x = data->directmvF[0].x + x;
631            b_mvs.x = ((x == 0) ?
632                    data->directmvB[0].x
633                    : mvs.x - data->referencemv[0].x);
634    
635                          case 7:          mvs.y = data->directmvF[0].y + y;
636                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          b_mvs.y = ((y == 0) ?
637                                                                                     backupMV.y, 1);                  data->directmvB[0].y
638                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize,                  : mvs.y - data->referencemv[0].y);
                                                                                  4);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
639    
640                          case 8:          if ( (mvs.x > data->max_dx) || (mvs.x < data->min_dx)
641                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y,                  || (mvs.y > data->max_dy) || (mvs.y < data->min_dy)
642                                                                                   2);                  || (b_mvs.x > data->max_dx) || (b_mvs.x < data->min_dx)
643                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize,                  || (b_mvs.y > data->max_dy) || (b_mvs.y < data->min_dy) ) return;
644                                                                                   4);  
645                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,          if (data->qpel) {
646                                                                                   backupMV.y + iDiamondSize, 6);                  xcf = 4*(mvs.x/2); ycf = 4*(mvs.y/2);
647                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,                  xcb = 4*(b_mvs.x/2); ycb = 4*(b_mvs.y/2);
648                                                                                   backupMV.y - iDiamondSize, 7);                  ReferenceF = Interpolate16x16qpel(mvs.x, mvs.y, 0, data);
649                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,                  ReferenceB = Interpolate16x16qpel(b_mvs.x, b_mvs.y, 1, data);
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         default:  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
   
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         }  
650          } else {          } else {
651                  currMV->x = startx;                  xcf = 4*mvs.x; ycf = 4*mvs.y;
652                  currMV->y = starty;                  xcb = 4*b_mvs.x; ycb = 4*b_mvs.y;
653                    ReferenceF = GetReference(mvs.x, mvs.y, data);
654                    ReferenceB = GetReferenceB(b_mvs.x, b_mvs.y, 1, data);
655            }
656    
657            sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
658            sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;
659    
660            if (data->chroma) sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],
661                                                                                    (ycf >> 3) + roundtab_76[ycf & 0xf],
662                                                                                    (xcb >> 3) + roundtab_76[xcb & 0xf],
663                                                                                    (ycb >> 3) + roundtab_76[ycb & 0xf], data);
664    
665            if (sad < *(data->iMinSAD)) {
666                    *(data->iMinSAD) = sad;
667                    data->currentMV->x = x; data->currentMV->y = y;
668                    *dir = Direction;
669          }          }
         return iMinSAD;  
670  }  }
671    
672    
673  int32_t  static void
674  Full16_MainSearch(const uint8_t * const pRef,  CheckCandidateBits16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
675                                    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_MV16_CANDIDATE(dx, dy);  
676    
677          return iMinSAD;          int16_t *in = data->dctSpace, *coeff = data->dctSpace + 64;
678            int32_t bits = 0;
679            VECTOR * current;
680            const uint8_t * ptr;
681            int i, cbp = 0, t, xc, yc;
682    
683            if ( (x > data->max_dx) || (x < data->min_dx)
684                    || (y > data->max_dy) || (y < data->min_dy) ) return;
685    
686            if (!data->qpel_precision) {
687                    ptr = GetReference(x, y, data);
688                    current = data->currentMV;
689                    xc = x; yc = y;
690            } else { /* x and y are in 1/4 precision */
691                    ptr = Interpolate16x16qpel(x, y, 0, data);
692                    current = data->currentQMV;
693                    xc = x/2; yc = y/2;
694  }  }
695    
696  int32_t          for(i = 0; i < 4; i++) {
697  AdvDiamond16_MainSearch(const uint8_t * const pRef,                  int s = 8*((i&1) + (i>>1)*data->iEdgedWidth);
698                                                  const uint8_t * const pRefH,                  transfer_8to16subro(in, data->Cur + s, ptr + s, data->iEdgedWidth);
699                                                  const uint8_t * const pRefV,                  bits += data->temp[i] = Block_CalcBits(coeff, in, data->dctSpace + 128, data->iQuant, data->quant_type, &cbp, i);
700                                                  const uint8_t * const pRefHV,          }
701                                                  const uint8_t * const cur,  
702                                                  const int x,          bits += t = BITS_MULT*d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
703                                                  const int y,  
704                                                  int32_t startx,          if (data->temp[0] + t < data->iMinSAD[1]) {
705                                                  int32_t starty,                  data->iMinSAD[1] = data->temp[0] + t; current[1].x = x; current[1].y = y; }
706                                                  int32_t iMinSAD,          if (data->temp[1] < data->iMinSAD[2]) {
707                                                  VECTOR * const currMV,                  data->iMinSAD[2] = data->temp[1]; current[2].x = x; current[2].y = y; }
708                                                  const VECTOR * const pmv,          if (data->temp[2] < data->iMinSAD[3]) {
709                                                  const int32_t min_dx,                  data->iMinSAD[3] = data->temp[2]; current[3].x = x; current[3].y = y; }
710                                                  const int32_t max_dx,          if (data->temp[3] < data->iMinSAD[4]) {
711                                                  const int32_t min_dy,                  data->iMinSAD[4] = data->temp[3]; current[4].x = x; current[4].y = y; }
712                                                  const int32_t max_dy,  
713                                                  const int32_t iEdgedWidth,          bits += BITS_MULT*xvid_cbpy_tab[15-(cbp>>2)].len;
714                                                  const int32_t iDiamondSize,  
715                                                  const int32_t iFcode,          if (bits >= data->iMinSAD[0]) return;
716                                                  const int32_t iQuant,  
717                                                  int iDirection)          /* chroma */
718            xc = (xc >> 1) + roundtab_79[xc & 0x3];
719            yc = (yc >> 1) + roundtab_79[yc & 0x3];
720    
721            /* chroma U */
722            ptr = interpolate8x8_switch2(data->RefQ + 64, data->RefP[4], 0, 0, xc, yc,  data->iEdgedWidth/2, data->rounding);
723            transfer_8to16subro(in, ptr, data->CurU, data->iEdgedWidth/2);
724            bits += Block_CalcBits(coeff, in, data->dctSpace + 128, data->iQuant, data->quant_type, &cbp, 4);
725            if (bits >= data->iMinSAD[0]) return;
726    
727            /* chroma V */
728            ptr = interpolate8x8_switch2(data->RefQ + 64, data->RefP[5], 0, 0, xc, yc,  data->iEdgedWidth/2, data->rounding);
729            transfer_8to16subro(in, ptr, data->CurV, data->iEdgedWidth/2);
730            bits += Block_CalcBits(coeff, in, data->dctSpace + 128, data->iQuant, data->quant_type, &cbp, 5);
731    
732            bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTER & 7) | ((cbp & 3) << 3)].len;
733    
734            if (bits < data->iMinSAD[0]) {
735                    data->iMinSAD[0] = bits;
736                    current[0].x = x; current[0].y = y;
737                    *dir = Direction;
738            }
739    }
740    
741    static void
742    CheckCandidateBits8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
743  {  {
744    
745          int32_t iSAD;          int16_t *in = data->dctSpace, *coeff = data->dctSpace + 64;
746            int32_t bits;
747            VECTOR * current;
748            const uint8_t * ptr;
749            int cbp = 0;
750    
751  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */          if ( (x > data->max_dx) || (x < data->min_dx)
752                    || (y > data->max_dy) || (y < data->min_dy) ) return;
753    
754          if (iDirection) {          if (!data->qpel_precision) {
755                  CHECK_MV16_CANDIDATE(startx - iDiamondSize, starty);                  ptr = GetReference(x, y, data);
756                  CHECK_MV16_CANDIDATE(startx + iDiamondSize, starty);                  current = data->currentMV;
757                  CHECK_MV16_CANDIDATE(startx, starty - iDiamondSize);          } else { /* x and y are in 1/4 precision */
758                  CHECK_MV16_CANDIDATE(startx, starty + iDiamondSize);                  ptr = Interpolate8x8qpel(x, y, 0, 0, data);
759          } else {                  current = data->currentQMV;
760                  int bDirection = 1 + 2 + 4 + 8;          }
761    
762                  do {          transfer_8to16subro(in, data->Cur, ptr, data->iEdgedWidth);
763                          iDirection = 0;          bits = Block_CalcBits(coeff, in, data->dctSpace + 128, data->iQuant, data->quant_type, &cbp, 5);
764                          if (bDirection & 1)     //we only want to check left if we came from the right (our last motion was to the left, up-left or down-left)          bits += BITS_MULT*d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
765                                  CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);  
766            if (bits < data->iMinSAD[0]) {
767                    data->temp[0] = cbp;
768                    data->iMinSAD[0] = bits;
769                    current[0].x = x; current[0].y = y;
770                    *dir = Direction;
771            }
772    }
773    
774    /* CHECK_CANDIATE FUNCTIONS END */
775    
776    /* MAINSEARCH FUNCTIONS START */
777    
778    static void
779    AdvDiamondSearch(int x, int y, const SearchData * const data, int bDirection)
780    {
781    
782                          if (bDirection & 2)  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
                                 CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);  
783    
784                          if (bDirection & 4)          int iDirection;
                                 CHECK_MV16_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);  
785    
786                          if (bDirection & 8)          for(;;) { /* forever */
787                                  CHECK_MV16_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);                  iDirection = 0;
788                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
789                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
790                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
791                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
792    
793                          /* now we're doing diagonal checks near our candidate */                          /* now we're doing diagonal checks near our candidate */
794    
795                          if (iDirection)         //checking if anything found                  if (iDirection) {               /* if anything found */
                         {  
796                                  bDirection = iDirection;                                  bDirection = iDirection;
797                                  iDirection = 0;                                  iDirection = 0;
798                                  startx = currMV->x;                          x = data->currentMV->x; y = data->currentMV->y;
799                                  starty = currMV->y;                          if (bDirection & 3) {   /* our candidate is left or right */
800                                  if (bDirection & 3)     //our candidate is left or right                                  CHECK_CANDIDATE(x, y + iDiamondSize, 8);
801                                  {                                  CHECK_CANDIDATE(x, y - iDiamondSize, 4);
802                                          CHECK_MV16_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);                          } else {                        /* what remains here is up or down */
803                                          CHECK_MV16_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y, 2);
804                                  } else                  // what remains here is up or down                                  CHECK_CANDIDATE(x - iDiamondSize, y, 1);
                                 {  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);  
805                                  }                                  }
806    
807                                  if (iDirection) {                                  if (iDirection) {
808                                          bDirection += iDirection;                                          bDirection += iDirection;
809                                          startx = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
                                         starty = currMV->y;  
810                                  }                                  }
811                          } else                          //about to quit, eh? not so fast....                  } else {                                /* about to quit, eh? not so fast.... */
                         {  
812                                  switch (bDirection) {                                  switch (bDirection) {
813                                  case 2:                                  case 2:
814                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
815                                                                                           starty - iDiamondSize, 2 + 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
816                                          break;                                          break;
817                                  case 1:                                  case 1:
818                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
819                                                                                           starty - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty + iDiamondSize, 1 + 8);  
820                                          break;                                          break;
821                                  case 2 + 4:                                  case 2 + 4:
822                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
823                                                                                           starty - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
824                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                          starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
825                                          break;                                          break;
826                                  case 4:                                  case 4:
827                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
828                                                                                           starty - iDiamondSize, 2 + 4);                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty - iDiamondSize, 1 + 4);  
829                                          break;                                          break;
830                                  case 8:                                  case 8:
831                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
832                                                                                           starty + iDiamondSize, 2 + 8);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty + iDiamondSize, 1 + 8);  
833                                          break;                                          break;
834                                  case 1 + 4:                                  case 1 + 4:
835                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
836                                                                                           starty + iDiamondSize, 1 + 8);                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
837                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
                                                                                          starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty - iDiamondSize, 2 + 4);  
838                                          break;                                          break;
839                                  case 2 + 8:                                  case 2 + 8:
840                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
841                                                                                           starty - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
842                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                          starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
843                                          break;                                          break;
844                                  case 1 + 8:                                  case 1 + 8:
845                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
846                                                                                           starty - iDiamondSize, 2 + 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
847                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
848                                                                                           starty + iDiamondSize, 2 + 8);                                  break;
849                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                          default:                /* 1+2+4+8 == we didn't find anything at all */
850                                                                                           starty + iDiamondSize, 1 + 8);                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
851                                          break;                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
852                                  default:                //1+2+4+8 == we didn't find anything at all                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
853                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                          starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
854                                          break;                                          break;
855                                  }                                  }
856                                  if (!iDirection)                          if (!iDirection) break;         /* ok, the end. really */
                                         break;          //ok, the end. really  
                                 else {  
857                                          bDirection = iDirection;                                          bDirection = iDirection;
858                                          startx = currMV->x;                          x = data->currentMV->x; y = data->currentMV->y;
                                         starty = currMV->y;  
                                 }  
859                          }                          }
860                  }                  }
                 while (1);                              //forever  
         }  
         return iMinSAD;  
861  }  }
862    
863  int32_t  static void
864  AdvDiamond8_MainSearch(const uint8_t * const pRef,  SquareSearch(int x, int y, const SearchData * const data, int bDirection)
                                            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 iDirection)  
865  {  {
866            int iDirection;
867    
868          int32_t iSAD;          do {
869                    iDirection = 0;
870                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);
871                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);
872                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);
873                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128);
874                    if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64);
875                    if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128);
876                    if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128);
877                    if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128);
878    
879                    bDirection = iDirection;
880                    x = data->currentMV->x; y = data->currentMV->y;
881            } while (iDirection);
882    }
883    
884    static void
885    DiamondSearch(int x, int y, const SearchData * const data, int bDirection)
886    {
887    
888  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
889    
890          if (iDirection) {          int iDirection;
                 CHECK_MV8_CANDIDATE(startx - iDiamondSize, starty);  
                 CHECK_MV8_CANDIDATE(startx + iDiamondSize, starty);  
                 CHECK_MV8_CANDIDATE(startx, starty - iDiamondSize);  
                 CHECK_MV8_CANDIDATE(startx, starty + iDiamondSize);  
         } else {  
                 int bDirection = 1 + 2 + 4 + 8;  
891    
892                  do {                  do {
893                          iDirection = 0;                          iDirection = 0;
894                          if (bDirection & 1)     //we only want to check left if we came from the right (our last motion was to the left, up-left or down-left)                  if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
895                                  CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);                  if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
896                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
897                          if (bDirection & 2)                  if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
                                 CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);  
   
                         if (bDirection & 4)  
                                 CHECK_MV8_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);  
   
                         if (bDirection & 8)  
                                 CHECK_MV8_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);  
898    
899                          /* now we're doing diagonal checks near our candidate */                          /* now we're doing diagonal checks near our candidate */
900    
901                          if (iDirection)         //checking if anything found                  if (iDirection) {               /* checking if anything found */
                         {  
902                                  bDirection = iDirection;                                  bDirection = iDirection;
903                                  iDirection = 0;                                  iDirection = 0;
904                                  startx = currMV->x;                          x = data->currentMV->x; y = data->currentMV->y;
905                                  starty = currMV->y;                          if (bDirection & 3) {   /* our candidate is left or right */
906                                  if (bDirection & 3)     //our candidate is left or right                                  CHECK_CANDIDATE(x, y + iDiamondSize, 8);
907                                  {                                  CHECK_CANDIDATE(x, y - iDiamondSize, 4);
908                                          CHECK_MV8_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);                          } else {                        /* what remains here is up or down */
909                                          CHECK_MV8_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y, 2);
910                                  } else                  // what remains here is up or down                                  CHECK_CANDIDATE(x - iDiamondSize, y, 1);
911                            }
912                            bDirection += iDirection;
913                            x = data->currentMV->x; y = data->currentMV->y;
914                    }
915            }
916            while (iDirection);
917    }
918    
919    /* MAINSEARCH FUNCTIONS END */
920    
921    static void
922    SubpelRefine(const SearchData * const data)
923                                  {                                  {
924                                          CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);  /* Do a half-pel or q-pel refinement */
925                                          CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);          const VECTOR centerMV = data->qpel_precision ? *data->currentQMV : *data->currentMV;
926            int iDirection; /* only needed because macro expects it */
927    
928            CHECK_CANDIDATE(centerMV.x, centerMV.y - 1, 0);
929            CHECK_CANDIDATE(centerMV.x + 1, centerMV.y - 1, 0);
930            CHECK_CANDIDATE(centerMV.x + 1, centerMV.y, 0);
931            CHECK_CANDIDATE(centerMV.x + 1, centerMV.y + 1, 0);
932            CHECK_CANDIDATE(centerMV.x, centerMV.y + 1, 0);
933            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y + 1, 0);
934            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y, 0);
935            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y - 1, 0);
936                                  }                                  }
937    
938                                  if (iDirection) {  static __inline int
939                                          bDirection += iDirection;  SkipDecisionP(const IMAGE * current, const IMAGE * reference,
940                                          startx = currMV->x;                                                          const int x, const int y,
941                                          starty = currMV->y;                                                          const uint32_t stride, const uint32_t iQuant, int rrv)
942    
943    {
944            int offset = (x + y*stride)*8;
945            if(!rrv) {
946                    uint32_t sadC = sad8(current->u + offset,
947                                                    reference->u + offset, stride);
948                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
949                    sadC += sad8(current->v + offset,
950                                                    reference->v + offset, stride);
951                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
952                    return 1;
953    
954            } else {
955                    uint32_t sadC = sad16(current->u + 2*offset,
956                                                    reference->u + 2*offset, stride, 256*4096);
957                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
958                    sadC += sad16(current->v + 2*offset,
959                                                    reference->v + 2*offset, stride, 256*4096);
960                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
961                    return 1;
962            }
963                                  }                                  }
964                          } else                          //about to quit, eh? not so fast....  
965    static __inline void
966    SkipMacroblockP(MACROBLOCK *pMB, const int32_t sad)
967                          {                          {
968                                  switch (bDirection) {          pMB->mode = MODE_NOT_CODED;
969                                  case 2:          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = zeroMV;
970                                          CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,          pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] = pMB->qmvs[3] = zeroMV;
971                                                                                          starty - iDiamondSize, 2 + 4);          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
972                                          CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  }
973                                                                                          starty + iDiamondSize, 2 + 8);  
974                                          break;  static __inline void
975                                  case 1:  ModeDecision(SearchData * const Data,
976                                          CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,                          MACROBLOCK * const pMB,
977                                                                                          starty - iDiamondSize, 1 + 4);                          const MACROBLOCK * const pMBs,
978                                          CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,                          const int x, const int y,
979                                                                                          starty + iDiamondSize, 1 + 8);                          const MBParam * const pParam,
980                                          break;                          const uint32_t MotionFlags,
981                                  case 2 + 4:                          const uint32_t VopFlags,
982                                          CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,                          const uint32_t VolFlags,
983                                                                                          starty - iDiamondSize, 1 + 4);                          const IMAGE * const pCurrent,
984                                          CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,                          const IMAGE * const pRef)
985                                                                                          starty - iDiamondSize, 2 + 4);  {
986                                          CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,          int mode = MODE_INTER;
987                                                                                          starty + iDiamondSize, 2 + 8);          int inter4v = (VopFlags & XVID_VOP_INTER4V) && (pMB->dquant == 0);
988                                          break;          const uint32_t iQuant = pMB->quant;
989                                  case 4:  
990                                          CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,          const int skip_possible = (!(VolFlags & XVID_VOL_GMC)) && (pMB->dquant == 0);
991                                                                                          starty - iDiamondSize, 2 + 4);  
992                                          CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,          if (!(VopFlags & XVID_VOP_MODEDECISION_BITS)) { /* normal, fast, SAD-based mode decision */
993                                                                                          starty - iDiamondSize, 1 + 4);                  int sad;
994                                          break;                  int InterBias = MV16_INTER_BIAS;
995                                  case 8:                  if (inter4v == 0 || Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
996                                          CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,                          Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant) {
997                                                                                          starty + iDiamondSize, 2 + 8);                          mode = MODE_INTER;
998                                          CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,                          sad = Data->iMinSAD[0];
999                                                                                          starty + iDiamondSize, 1 + 8);                  } else {
1000                                          break;                          mode = MODE_INTER4V;
1001                                  case 1 + 4:                          sad = Data->iMinSAD[1] + Data->iMinSAD[2] +
1002                                          CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,                                                  Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant;
1003                                                                                          starty + iDiamondSize, 1 + 8);                          Data->iMinSAD[0] = sad;
1004                                          CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,                  }
1005                                                                                          starty - iDiamondSize, 1 + 4);  
1006                                          CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,                  /* final skip decision, a.k.a. "the vector you found, really that good?" */
1007                                                                                          starty - iDiamondSize, 2 + 4);                  if (skip_possible && (pMB->sad16 < (int)iQuant * MAX_SAD00_FOR_SKIP))
1008                                          break;                          if ( (100*sad)/(pMB->sad16+1) > FINAL_SKIP_THRESH)
1009                                  case 2 + 8:                                  if (Data->chroma || SkipDecisionP(pCurrent, pRef, x, y, Data->iEdgedWidth/2, iQuant, Data->rrv)) {
1010                                          CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,                                          mode = MODE_NOT_CODED;
1011                                                                                          starty - iDiamondSize, 1 + 4);                                          sad = 0;
1012                                          CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,                                  }
1013                                                                                          starty + iDiamondSize, 1 + 8);  
1014                                          CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,                  /* intra decision */
1015                                                                                          starty + iDiamondSize, 2 + 8);  
1016                                          break;                  if (iQuant > 8) InterBias += 100 * (iQuant - 8); /* to make high quants work */
1017                                  case 1 + 8:                  if (y != 0)
1018                                          CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,                          if ((pMB - pParam->mb_width)->mode == MODE_INTRA ) InterBias -= 80;
1019                                                                                          starty - iDiamondSize, 2 + 4);                  if (x != 0)
1020                                          CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,                          if ((pMB - 1)->mode == MODE_INTRA ) InterBias -= 80;
1021                                                                                          starty + iDiamondSize, 2 + 8);  
1022                                          CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,                  if (Data->chroma) InterBias += 50; /* dev8(chroma) ??? */
1023                                                                                          starty + iDiamondSize, 1 + 8);                  if (Data->rrv) InterBias *= 4;
1024                                          break;  
1025                                  default:                //1+2+4+8 == we didn't find anything at all                  if (InterBias < pMB->sad16) {
1026                                          CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,                          int32_t deviation;
1027                                                                                          starty - iDiamondSize, 1 + 4);                          if (!Data->rrv) deviation = dev16(Data->Cur, Data->iEdgedWidth);
1028                                          CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,                          else deviation = dev16(Data->Cur, Data->iEdgedWidth) +
1029                                                                                          starty + iDiamondSize, 1 + 8);                                  dev16(Data->Cur+16, Data->iEdgedWidth) +
1030                                          CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,                                  dev16(Data->Cur + 16*Data->iEdgedWidth, Data->iEdgedWidth) +
1031                                                                                          starty - iDiamondSize, 2 + 4);                                  dev16(Data->Cur+16+16*Data->iEdgedWidth, Data->iEdgedWidth);
1032                                          CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
1033                                                                                          starty + iDiamondSize, 2 + 8);                          if (deviation < (sad - InterBias)) mode = MODE_INTRA;
                                         break;  
1034                                  }                                  }
1035                                  if (!(iDirection))  
1036                                          break;          //ok, the end. really          } else { /* BITS */
1037    
1038                    int bits, intra, i;
1039                    VECTOR backup[5], *v;
1040                    Data->iQuant = iQuant;
1041    
1042                    v = Data->qpel ? Data->currentQMV : Data->currentMV;
1043                    for (i = 0; i < 5; i++) {
1044                            Data->iMinSAD[i] = 256*4096;
1045                            backup[i] = v[i];
1046                    }
1047    
1048                    bits = CountMBBitsInter(Data, pMBs, x, y, pParam, MotionFlags);
1049                    if (bits == 0)
1050                            mode = MODE_INTER; /* quick stop */
1051                                  else {                                  else {
1052                                          bDirection = iDirection;                          if (inter4v) {
1053                                          startx = currMV->x;                                  int bits_inter4v = CountMBBitsInter4v(Data, pMB, pMBs, x, y, pParam, MotionFlags, backup);
1054                                          starty = currMV->y;                                  if (bits_inter4v < bits) { Data->iMinSAD[0] = bits = bits_inter4v; mode = MODE_INTER4V; }
1055                                  }                                  }
1056    
1057                            intra = CountMBBitsIntra(Data);
1058    
1059                            if (intra < bits) { *Data->iMinSAD = bits = intra; mode = MODE_INTRA; }
1060                          }                          }
1061                  }                  }
1062                  while (1);                              //forever  
1063            if (Data->rrv) {
1064                            Data->currentMV[0].x = RRV_MV_SCALEDOWN(Data->currentMV[0].x);
1065                            Data->currentMV[0].y = RRV_MV_SCALEDOWN(Data->currentMV[0].y);
1066          }          }
1067          return iMinSAD;  
1068            if (mode == MODE_INTER) {
1069                    pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
1070                    pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = Data->iMinSAD[0];
1071    
1072                    if(Data->qpel) {
1073                            pMB->qmvs[0] = pMB->qmvs[1]
1074                                    = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1075                            pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1076                            pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;
1077                    } else {
1078                            pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1079                            pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
1080  }  }
1081    
1082            } else if (mode == MODE_INTER4V)
1083                    pMB->sad16 = Data->iMinSAD[0];
1084            else /* INTRA, NOT_CODED */
1085                    SkipMacroblockP(pMB, 0);
1086    
1087  int32_t          pMB->mode = mode;
1088  Full8_MainSearch(const uint8_t * const pRef,  }
1089                                   const uint8_t * const pRefH,  
1090                                   const uint8_t * const pRefV,  bool
1091                                   const uint8_t * const pRefHV,  MotionEstimation(MBParam * const pParam,
1092                                   const uint8_t * const cur,                                   FRAMEINFO * const current,
1093                                   const int x,                                   FRAMEINFO * const reference,
1094                                   const int y,                                   const IMAGE * const pRefH,
1095                                   int32_t startx,                                   const IMAGE * const pRefV,
1096                                   int32_t starty,                                   const IMAGE * const pRefHV,
1097                                   int32_t iMinSAD,                                  const IMAGE * const pGMC,
1098                                   VECTOR * const currMV,                                   const uint32_t iLimit)
1099                                   const VECTOR * const pmv,  {
1100                                   const int32_t min_dx,          MACROBLOCK *const pMBs = current->mbs;
1101                                   const int32_t max_dx,          const IMAGE *const pCurrent = &current->image;
1102                                   const int32_t min_dy,          const IMAGE *const pRef = &reference->image;
                                  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);  
1103    
1104          return iMinSAD;          uint32_t mb_width = pParam->mb_width;
1105            uint32_t mb_height = pParam->mb_height;
1106            const uint32_t iEdgedWidth = pParam->edged_width;
1107            const uint32_t MotionFlags = MakeGoodMotionFlags(current->motion_flags, current->vop_flags, current->vol_flags);
1108    
1109            uint32_t x, y;
1110            uint32_t iIntra = 0;
1111            int32_t quant = current->quant, sad00;
1112            int skip_thresh = INITIAL_SKIP_THRESH * \
1113                    (current->vop_flags & XVID_VOP_REDUCED ? 4:1) * \
1114                    (current->vop_flags & XVID_VOP_MODEDECISION_BITS ? 2:1);
1115    
1116            /* some pre-initialized thingies for SearchP */
1117            int32_t temp[8];
1118            VECTOR currentMV[5];
1119            VECTOR currentQMV[5];
1120            int32_t iMinSAD[5];
1121            DECLARE_ALIGNED_MATRIX(dct_space, 3, 64, int16_t, CACHE_LINE);
1122            SearchData Data;
1123            memset(&Data, 0, sizeof(SearchData));
1124            Data.iEdgedWidth = iEdgedWidth;
1125            Data.currentMV = currentMV;
1126            Data.currentQMV = currentQMV;
1127            Data.iMinSAD = iMinSAD;
1128            Data.temp = temp;
1129            Data.iFcode = current->fcode;
1130            Data.rounding = pParam->m_rounding_type;
1131            Data.qpel = (current->vol_flags & XVID_VOL_QUARTERPEL ? 1:0);
1132            Data.chroma = MotionFlags & XVID_ME_CHROMA16;
1133            Data.rrv = (current->vop_flags & XVID_VOP_REDUCED) ? 1:0;
1134            Data.dctSpace = dct_space;
1135            Data.quant_type = !(pParam->vol_flags & XVID_VOL_MPEGQUANT);
1136    
1137            if ((current->vop_flags & XVID_VOP_REDUCED)) {
1138                    mb_width = (pParam->width + 31) / 32;
1139                    mb_height = (pParam->height + 31) / 32;
1140                    Data.qpel = 0;
1141            }
1142    
1143            Data.RefQ = pRefV->u; /* a good place, also used in MC (for similar purpose) */
1144            if (sadInit) (*sadInit) ();
1145    
1146            for (y = 0; y < mb_height; y++) {
1147                    for (x = 0; x < mb_width; x++)  {
1148                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1149    
1150                            if (!Data.rrv) pMB->sad16 =
1151                                    sad16v(pCurrent->y + (x + y * iEdgedWidth) * 16,
1152                                                            pRef->y + (x + y * iEdgedWidth) * 16,
1153                                                            pParam->edged_width, pMB->sad8 );
1154    
1155                            else pMB->sad16 =
1156                                    sad32v_c(pCurrent->y + (x + y * iEdgedWidth) * 32,
1157                                                            pRef->y + (x + y * iEdgedWidth) * 32,
1158                                                            pParam->edged_width, pMB->sad8 );
1159    
1160                            if (Data.chroma) {
1161                                    Data.temp[7] = sad8(pCurrent->u + x*8 + y*(iEdgedWidth/2)*8,
1162                                                                            pRef->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2)
1163                                                                    + sad8(pCurrent->v + (x + y*(iEdgedWidth/2))*8,
1164                                                                            pRef->v + (x + y*(iEdgedWidth/2))*8, iEdgedWidth/2);
1165                                    pMB->sad16 += Data.temp[7];
1166                            }
1167    
1168                            sad00 = pMB->sad16;
1169    
1170                            if (pMB->dquant != 0) {
1171                                    quant += DQtab[pMB->dquant];
1172                                    if (quant > 31) quant = 31;
1173                                    else if (quant < 1) quant = 1;
1174                            }
1175                            pMB->quant = quant;
1176    
1177                            /* initial skip decision */
1178                            /* no early skip for GMC (global vector = skip vector is unknown!)  */
1179                            if (!(current->vol_flags & XVID_VOL_GMC))       { /* no fast SKIP for S(GMC)-VOPs */
1180                                    if (pMB->dquant == 0 && sad00 < pMB->quant * skip_thresh)
1181                                            if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, iEdgedWidth/2, pMB->quant, Data.rrv)) {
1182                                                    SkipMacroblockP(pMB, sad00);
1183                                                    continue;
1184                                            }
1185  }  }
1186    
1187                            SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1188                                            y, MotionFlags, current->vop_flags, current->vol_flags,
1189                                            &Data, pParam, pMBs, reference->mbs, pMB);
1190    
1191                            ModeDecision(&Data, pMB, pMBs, x, y, pParam,
1192                                                     MotionFlags, current->vop_flags, current->vol_flags,
1193                                                     pCurrent, pRef);
1194    
1195  int32_t                          if (pMB->mode == MODE_INTRA)
1196  Halfpel16_Refine(const uint8_t * const pRef,                                  if (++iIntra > iLimit) return 1;
1197                                   const uint8_t * const pRefH,                  }
1198                                   const uint8_t * const pRefV,          }
1199                                   const uint8_t * const pRefHV,  
1200                                   const uint8_t * const cur,  //      if (current->vol_flags & XVID_VOL_GMC ) /* GMC only for S(GMC)-VOPs */
1201                                   const int x,  //      {
1202                                   const int y,  //              current->warp = GlobalMotionEst( pMBs, pParam, current, reference, pRefH, pRefV, pRefHV);
1203                                   VECTOR * const currMV,  //      }
1204                                   int32_t iMinSAD,          return 0;
1205                                   const VECTOR * const pmv,  }
                                  const int32_t min_dx,  
                                  const int32_t max_dx,  
                                  const int32_t min_dy,  
                                  const int32_t max_dy,  
                                  const int32_t iFcode,  
                                  const int32_t iQuant,  
                                  const int32_t iEdgedWidth)  
 {  
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
   
         int32_t iSAD;  
         VECTOR backupMV = *currMV;  
   
         CHECK_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);  
         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);  
1206    
1207          return iMinSAD;  
1208    static __inline int
1209    make_mask(const VECTOR * const pmv, const int i)
1210    {
1211            int mask = 255, j;
1212            for (j = 0; j < i; j++) {
1213                    if (MVequal(pmv[i], pmv[j])) return 0; /* same vector has been checked already */
1214                    if (pmv[i].x == pmv[j].x) {
1215                            if (pmv[i].y == pmv[j].y + iDiamondSize) mask &= ~4;
1216                            else if (pmv[i].y == pmv[j].y - iDiamondSize) mask &= ~8;
1217                    } else
1218                            if (pmv[i].y == pmv[j].y) {
1219                                    if (pmv[i].x == pmv[j].x + iDiamondSize) mask &= ~1;
1220                                    else if (pmv[i].x == pmv[j].x - iDiamondSize) mask &= ~2;
1221  }  }
1222            }
1223            return mask;
1224    }
1225    
1226    static __inline void
1227    PreparePredictionsP(VECTOR * const pmv, int x, int y, int iWcount,
1228                            int iHcount, const MACROBLOCK * const prevMB, int rrv)
1229    {
1230            /* this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself */
1231            if (rrv) { iWcount /= 2; iHcount /= 2; }
1232    
1233  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)          if ( (y != 0) && (x < (iWcount-1)) ) {          /* [5] top-right neighbour */
1234                    pmv[5].x = EVEN(pmv[3].x);
1235                    pmv[5].y = EVEN(pmv[3].y);
1236            } else pmv[5].x = pmv[5].y = 0;
1237    
1238            if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }/* pmv[3] is left neighbour */
1239            else pmv[3].x = pmv[3].y = 0;
1240    
1241  int32_t          if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }/* [4] top neighbour */
1242  PMVfastSearch16(const uint8_t * const pRef,          else pmv[4].x = pmv[4].y = 0;
1243    
1244            /* [1] median prediction */
1245            pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
1246    
1247            pmv[0].x = pmv[0].y = 0; /* [0] is zero; not used in the loop (checked before) but needed here for make_mask */
1248    
1249            pmv[2].x = EVEN(prevMB->mvs[0].x); /* [2] is last frame */
1250            pmv[2].y = EVEN(prevMB->mvs[0].y);
1251    
1252            if ((x < iWcount-1) && (y < iHcount-1)) {
1253                    pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); /* [6] right-down neighbour in last frame */
1254                    pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
1255            } else pmv[6].x = pmv[6].y = 0;
1256    
1257            if (rrv) {
1258                    int i;
1259                    for (i = 0; i < 7; i++) {
1260                            pmv[i].x = RRV_MV_SCALEUP(pmv[i].x);
1261                            pmv[i].y = RRV_MV_SCALEUP(pmv[i].y);
1262                    }
1263            }
1264    }
1265    
1266    static void
1267    SearchP(const IMAGE * const pRef,
1268                                  const uint8_t * const pRefH,                                  const uint8_t * const pRefH,
1269                                  const uint8_t * const pRefV,                                  const uint8_t * const pRefV,
1270                                  const uint8_t * const pRefHV,                                  const uint8_t * const pRefHV,
# Line 1227  Line 1272 
1272                                  const int x,                                  const int x,
1273                                  const int y,                                  const int y,
1274                                  const uint32_t MotionFlags,                                  const uint32_t MotionFlags,
1275                                  const uint32_t iQuant,                  const uint32_t VopFlags,
1276                                  const uint32_t iFcode,                  const uint32_t VolFlags,
1277                    SearchData * const Data,
1278                                  const MBParam * const pParam,                                  const MBParam * const pParam,
1279                                  const MACROBLOCK * const pMBs,                                  const MACROBLOCK * const pMBs,
1280                                  const MACROBLOCK * const prevMBs,                                  const MACROBLOCK * const prevMBs,
1281                                  VECTOR * const currMV,                  MACROBLOCK * const pMB)
                                 VECTOR * const currPMV)  
1282  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
1283    
1284          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          int i, iDirection = 255, mask, threshA;
1285            VECTOR pmv[7];
1286            int inter4v = (VopFlags & XVID_VOP_INTER4V) && (pMB->dquant == 0);
1287    
1288            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1289                                                    pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
1290    
1291            get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);
1292    
1293            Data->temp[5] = Data->temp[6] = 0; /* chroma-sad cache */
1294            i = Data->rrv ? 2 : 1;
1295            Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16*i;
1296            Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1297            Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1298    
1299            Data->RefP[0] = pRef->y + (x + Data->iEdgedWidth*y) * 16*i;
1300            Data->RefP[2] = pRefH + (x + Data->iEdgedWidth*y) * 16*i;
1301            Data->RefP[1] = pRefV + (x + Data->iEdgedWidth*y) * 16*i;
1302            Data->RefP[3] = pRefHV + (x + Data->iEdgedWidth*y) * 16*i;
1303            Data->RefP[4] = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1304            Data->RefP[5] = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1305    
1306            Data->lambda16 = lambda_vec16[pMB->quant];
1307            Data->lambda8 = lambda_vec8[pMB->quant];
1308            Data->qpel_precision = 0;
1309    
1310            memset(Data->currentMV, 0, 5*sizeof(VECTOR));
1311    
1312            if (Data->qpel) Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1313            else Data->predMV = pmv[0];
1314    
1315            i = d_mv_bits(0, 0, Data->predMV, Data->iFcode, 0, 0);
1316            Data->iMinSAD[0] = pMB->sad16 + ((Data->lambda16 * i * pMB->sad16)>>10);
1317            Data->iMinSAD[1] = pMB->sad8[0] + ((Data->lambda8 * i * (pMB->sad8[0]+NEIGH_8X8_BIAS)) >> 10);
1318            Data->iMinSAD[2] = pMB->sad8[1];
1319            Data->iMinSAD[3] = pMB->sad8[2];
1320            Data->iMinSAD[4] = pMB->sad8[3];
1321    
1322            if ((!(VopFlags & XVID_VOP_MODEDECISION_BITS)) && (x | y)) {
1323                    threshA = Data->temp[0]; /* that's where we keep this SAD atm */
1324                    if (threshA < 512) threshA = 512;
1325                    else if (threshA > 1024) threshA = 1024;
1326            } else
1327                    threshA = 512;
1328    
1329          int32_t iDiamondSize;          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
1330                                            prevMBs + x + y * pParam->mb_width, Data->rrv);
1331    
1332          int32_t min_dx;          if (!Data->rrv) {
1333          int32_t max_dx;                  if (inter4v | Data->chroma) CheckCandidate = CheckCandidate16;
1334          int32_t min_dy;                          else CheckCandidate = CheckCandidate16no4v; /* for extra speed */
1335          int32_t max_dy;          } else CheckCandidate = CheckCandidate32;
1336    
1337    /* main loop. checking all predictions (but first, which is 0,0 and has been checked in MotionEstimation())*/
1338    
1339            for (i = 1; i < 7; i++) {
1340                    if (!(mask = make_mask(pmv, i)) ) continue;
1341                    CheckCandidate(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1342                    if (Data->iMinSAD[0] <= threshA) break;
1343            }
1344    
1345            if ((Data->iMinSAD[0] <= threshA) ||
1346                            (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
1347                            (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16)))
1348                    inter4v = 0;
1349            else {
1350    
1351          int32_t iFound;                  MainSearchFunc * MainSearchPtr;
1352                    if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1353                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1354                            else MainSearchPtr = DiamondSearch;
1355    
1356          VECTOR newMV;                  MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
         VECTOR backupMV;                        /* just for PMVFAST */  
1357    
1358          VECTOR pmv[4];  /* extended search, diamond starting in 0,0 and in prediction.
1359          int32_t psad[4];          note that this search is/might be done in halfpel positions,
1360            which makes it more different than the diamond above */
1361    
1362          MainSearch16FuncPtr MainSearchPtr;                  if (MotionFlags & XVID_ME_EXTSEARCH16) {
1363                            int32_t bSAD;
1364                            VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
1365                            if (Data->rrv) {
1366                                    startMV.x = RRV_MV_SCALEUP(startMV.x);
1367                                    startMV.y = RRV_MV_SCALEUP(startMV.y);
1368                            }
1369                            if (!(MVequal(startMV, backupMV))) {
1370                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1371    
1372  //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1373          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1374                                    if (bSAD < Data->iMinSAD[0]) {
1375                                            Data->currentMV[0] = backupMV;
1376                                            Data->iMinSAD[0] = bSAD; }
1377                            }
1378    
1379          static int32_t threshA, threshB;                          backupMV = Data->currentMV[0];
1380          int32_t bPredEq;                          startMV.x = startMV.y = 1;
1381          int32_t iMinSAD, iSAD;                          if (!(MVequal(startMV, backupMV))) {
1382                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1383    
1384  /* Get maximum range */                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1385          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1386                            iFcode);                                  if (bSAD < Data->iMinSAD[0]) {
1387                                            Data->currentMV[0] = backupMV;
1388                                            Data->iMinSAD[0] = bSAD; }
1389                            }
1390                    }
1391            }
1392    
1393  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          if (MotionFlags & XVID_ME_HALFPELREFINE16)
1394                            SubpelRefine(Data);
1395    
1396          if (!(MotionFlags & PMV_HALFPEL16)) {          for(i = 0; i < 5; i++) {
1397                  min_dx = EVEN(min_dx);                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; /* initialize qpel vectors */
1398                  max_dx = EVEN(max_dx);                  Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
1399          }          }
1400    
1401          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */          if (Data->qpel) {
1402          bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1403                                    pParam->width, pParam->height, Data->iFcode, 1, 0);
1404                    Data->qpel_precision = 1;
1405                    if (MotionFlags & XVID_ME_QUARTERPELREFINE16)
1406                            SubpelRefine(Data);
1407            }
1408    
1409          if ((x == 0) && (y == 0)) {          if (Data->iMinSAD[0] < (int32_t)pMB->quant * 30)
1410                  threshA = 512;                  inter4v = 0;
1411                  threshB = 1024;  
1412            if (inter4v) {
1413                    SearchData Data8;
1414                    memcpy(&Data8, Data, sizeof(SearchData)); /* quick copy of common data */
1415    
1416                    Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
1417                    Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
1418                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
1419                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
1420    
1421                    if ((Data->chroma) && (!(VopFlags & XVID_VOP_MODEDECISION_BITS))) {
1422                            /* chroma is only used for comparsion to INTER. if the comparsion will be done in BITS domain, it will not be used */
1423                            int sumx = 0, sumy = 0;
1424    
1425                            if (Data->qpel)
1426                                    for (i = 1; i < 5; i++) {
1427                                            sumx += Data->currentQMV[i].x/2;
1428                                            sumy += Data->currentQMV[i].y/2;
1429                                    }
1430                            else
1431                                    for (i = 1; i < 5; i++) {
1432                                            sumx += Data->currentMV[i].x;
1433                                            sumy += Data->currentMV[i].y;
1434                                    }
1435    
1436                            Data->iMinSAD[1] += ChromaSAD(  (sumx >> 3) + roundtab_76[sumx & 0xf],
1437                                                                                            (sumy >> 3) + roundtab_76[sumy & 0xf], Data);
1438                    }
1439            } else Data->iMinSAD[1] = 4096*256;
1440    }
1441    
1442    static void
1443    Search8(const SearchData * const OldData,
1444                    const int x, const int y,
1445                    const uint32_t MotionFlags,
1446                    const MBParam * const pParam,
1447                    MACROBLOCK * const pMB,
1448                    const MACROBLOCK * const pMBs,
1449                    const int block,
1450                    SearchData * const Data)
1451    {
1452            int i = 0;
1453            Data->iMinSAD = OldData->iMinSAD + 1 + block;
1454            Data->currentMV = OldData->currentMV + 1 + block;
1455            Data->currentQMV = OldData->currentQMV + 1 + block;
1456    
1457            if(Data->qpel) {
1458                    Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1459                    if (block != 0) i = d_mv_bits(  Data->currentQMV->x, Data->currentQMV->y,
1460                                                                                    Data->predMV, Data->iFcode, 0, 0);
1461          } else {          } else {
1462                  threshA = psad[0];                  Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1463                  threshB = threshA + 256;                  if (block != 0) i = d_mv_bits(  Data->currentMV->x, Data->currentMV->y,
1464                  if (threshA < 512)                                                                                  Data->predMV, Data->iFcode, 0, Data->rrv);
                         threshA = 512;  
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
1465          }          }
1466    
1467          iFound = 0;          *(Data->iMinSAD) += (Data->lambda8 * i * (*Data->iMinSAD + NEIGH_8X8_BIAS))>>10;
1468    
1469  /* Step 4: Calculate SAD around the Median prediction.          if (MotionFlags & (XVID_ME_EXTSEARCH8|XVID_ME_HALFPELREFINE8|XVID_ME_QUARTERPELREFINE8)) {
1470     MinSAD=SAD  
1471     If Motion Vector equal to Previous frame motion vector                  if (Data->rrv) i = 16; else i = 8;
1472     and MinSAD<PrevFrmSAD goto Step 10.  
1473     If SAD<=256 goto Step 10.                  Data->RefP[0] = OldData->RefP[0] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1474  */                  Data->RefP[1] = OldData->RefP[1] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1475                    Data->RefP[2] = OldData->RefP[2] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1476                    Data->RefP[3] = OldData->RefP[3] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1477    
1478                    Data->Cur = OldData->Cur + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1479                    Data->qpel_precision = 0;
1480    
1481                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1482                                            pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
1483    
1484          *currMV = pmv[0];                       /* current best := prediction */                  if (!Data->rrv) CheckCandidate = CheckCandidate8;
1485          if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */                  else CheckCandidate = CheckCandidate16no4v;
1486                  currMV->x = EVEN(currMV->x);  
1487                  currMV->y = EVEN(currMV->y);                  if (MotionFlags & XVID_ME_EXTSEARCH8 && (!(MotionFlags & XVID_ME_EXTSEARCH_BITS))) {
1488                            int32_t temp_sad = *(Data->iMinSAD); /* store current MinSAD */
1489    
1490                            MainSearchFunc *MainSearchPtr;
1491                            if (MotionFlags & XVID_ME_USESQUARES8) MainSearchPtr = SquareSearch;
1492                                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1493                                            else MainSearchPtr = DiamondSearch;
1494    
1495                            MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, 255);
1496    
1497                            if(*(Data->iMinSAD) < temp_sad) {
1498                                            Data->currentQMV->x = 2 * Data->currentMV->x; /* update our qpel vector */
1499                                            Data->currentQMV->y = 2 * Data->currentMV->y;
1500          }          }
1501                    }
1502    
1503                    if (MotionFlags & XVID_ME_HALFPELREFINE8) {
1504                            int32_t temp_sad = *(Data->iMinSAD); /* store current MinSAD */
1505    
1506          if (currMV->x > max_dx) {                          SubpelRefine(Data); /* perform halfpel refine of current best vector */
1507                  currMV->x = max_dx;  
1508                            if(*(Data->iMinSAD) < temp_sad) { /* we have found a better match */
1509                                    Data->currentQMV->x = 2 * Data->currentMV->x; /* update our qpel vector */
1510                                    Data->currentQMV->y = 2 * Data->currentMV->y;
1511          }          }
         if (currMV->x < min_dx) {  
                 currMV->x = min_dx;  
1512          }          }
1513          if (currMV->y > max_dy) {  
1514                  currMV->y = max_dy;                  if (Data->qpel && MotionFlags & XVID_ME_QUARTERPELREFINE8) {
1515                                    Data->qpel_precision = 1;
1516                                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1517                                            pParam->width, pParam->height, Data->iFcode, 1, 0);
1518                                    SubpelRefine(Data);
1519          }          }
         if (currMV->y < min_dy) {  
                 currMV->y = min_dy;  
1520          }          }
1521    
1522          iMinSAD =          if (Data->rrv) {
1523                  sad16(cur,                          Data->currentMV->x = RRV_MV_SCALEDOWN(Data->currentMV->x);
1524                            get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,                          Data->currentMV->y = RRV_MV_SCALEDOWN(Data->currentMV->y);
1525                                                   iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);          }
1526          iMinSAD +=  
1527                  calc_delta_16(currMV->x - pmv[0].x, currMV->y - pmv[0].y,          if(Data->qpel) {
1528                                            (uint8_t) iFcode, iQuant);                  pMB->pmvs[block].x = Data->currentQMV->x - Data->predMV.x;
1529                    pMB->pmvs[block].y = Data->currentQMV->y - Data->predMV.y;
1530                    pMB->qmvs[block] = *Data->currentQMV;
1531            } else {
1532                    pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1533                    pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
1534            }
1535    
1536          if ((iMinSAD < 256) ||          pMB->mvs[block] = *Data->currentMV;
1537                  ((MVequal(*currMV, prevMB->mvs[0])) &&          pMB->sad8[block] = 4 * *Data->iMinSAD;
1538                   ((uint32_t) iMinSAD < prevMB->sad16))) {  }
1539                  if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
1540    /* motion estimation for B-frames */
1541    
1542    static __inline VECTOR
1543    ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1544                  {                  {
1545                          if (!MVzero(*currMV)) {  /* the stupidiest function ever */
1546                                  iMinSAD += MV16_00_BIAS;          return (mode == MODE_FORWARD ? pMB->mvs[0] : pMB->b_mvs[0]);
                                 CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures  
                                 iMinSAD -= MV16_00_BIAS;  
1547                          }                          }
1548    
1549    static void __inline
1550    PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
1551                                                            const uint32_t iWcount,
1552                                                            const MACROBLOCK * const pMB,
1553                                                            const uint32_t mode_curr)
1554    {
1555    
1556            /* [0] is prediction */
1557            pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
1558    
1559            pmv[1].x = pmv[1].y = 0; /* [1] is zero */
1560    
1561            pmv[2] = ChoosePred(pMB, mode_curr);
1562            pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
1563    
1564            if ((y != 0)&&(x != (int)(iWcount+1))) {                        /* [3] top-right neighbour */
1565                    pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
1566                    pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
1567            } else pmv[3].x = pmv[3].y = 0;
1568    
1569            if (y != 0) {
1570                    pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
1571                    pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
1572            } else pmv[4].x = pmv[4].y = 0;
1573    
1574            if (x != 0) {
1575                    pmv[5] = ChoosePred(pMB-1, mode_curr);
1576                    pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1577            } else pmv[5].x = pmv[5].y = 0;
1578    
1579            if (x != 0 && y != 0) {
1580                    pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
1581                    pmv[6].x = EVEN(pmv[6].x); pmv[6].y = EVEN(pmv[6].y);
1582            } else pmv[6].x = pmv[6].y = 0;
1583                  }                  }
1584    
1585                  if (MotionFlags & PMV_QUICKSTOP16)  
1586                          goto PMVfast16_Terminate_without_Refine;  /* search backward or forward */
1587                  if (MotionFlags & PMV_EARLYSTOP16)  static void
1588                          goto PMVfast16_Terminate_with_Refine;  SearchBF(       const IMAGE * const pRef,
1589                            const uint8_t * const pRefH,
1590                            const uint8_t * const pRefV,
1591                            const uint8_t * const pRefHV,
1592                            const IMAGE * const pCur,
1593                            const int x, const int y,
1594                            const uint32_t MotionFlags,
1595                            const uint32_t iFcode,
1596                            const MBParam * const pParam,
1597                            MACROBLOCK * const pMB,
1598                            const VECTOR * const predMV,
1599                            int32_t * const best_sad,
1600                            const int32_t mode_current,
1601                            SearchData * const Data)
1602    {
1603    
1604            int i, iDirection = 255, mask;
1605            VECTOR pmv[7];
1606            MainSearchFunc *MainSearchPtr;
1607            *Data->iMinSAD = MV_MAX_ERROR;
1608            Data->iFcode = iFcode;
1609            Data->qpel_precision = 0;
1610            Data->temp[5] = Data->temp[6] = Data->temp[7] = 256*4096; /* reset chroma-sad cache */
1611    
1612            Data->RefP[0] = pRef->y + (x + Data->iEdgedWidth*y) * 16;
1613            Data->RefP[2] = pRefH + (x + Data->iEdgedWidth*y) * 16;
1614            Data->RefP[1] = pRefV + (x + Data->iEdgedWidth*y) * 16;
1615            Data->RefP[3] = pRefHV + (x + Data->iEdgedWidth*y) * 16;
1616            Data->RefP[4] = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8;
1617            Data->RefP[5] = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8;
1618    
1619            Data->predMV = *predMV;
1620    
1621            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1622                                    pParam->width, pParam->height, iFcode - Data->qpel, 0, 0);
1623    
1624            pmv[0] = Data->predMV;
1625            if (Data->qpel) { pmv[0].x /= 2; pmv[0].y /= 2; }
1626    
1627            PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);
1628    
1629            Data->currentMV->x = Data->currentMV->y = 0;
1630            CheckCandidate = CheckCandidate16no4v;
1631    
1632            /* main loop. checking all predictions */
1633            for (i = 0; i < 7; i++) {
1634                    if (!(mask = make_mask(pmv, i)) ) continue;
1635                    CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1636          }          }
1637    
1638            if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1639            else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1640                    else MainSearchPtr = DiamondSearch;
1641    
1642  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
    vector of the median.  
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
1643    
1644          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[0])))          SubpelRefine(Data);
                 iFound = 2;  
1645    
1646  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          if (Data->qpel && *Data->iMinSAD < *best_sad + 300) {
1647     Otherwise select large Diamond Search.                  Data->currentQMV->x = 2*Data->currentMV->x;
1648  */                  Data->currentQMV->y = 2*Data->currentMV->y;
1649                    Data->qpel_precision = 1;
1650                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1651                                            pParam->width, pParam->height, iFcode, 1, 0);
1652                    SubpelRefine(Data);
1653            }
1654    
1655            /* three bits are needed to code backward mode. four for forward */
1656    
1657          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))          if (mode_current == MODE_FORWARD) *Data->iMinSAD += 4 * Data->lambda16;
1658                  iDiamondSize = 1;               // halfpel!          else *Data->iMinSAD += 3 * Data->lambda16;
1659    
1660            if (*Data->iMinSAD < *best_sad) {
1661                    *best_sad = *Data->iMinSAD;
1662                    pMB->mode = mode_current;
1663                    if (Data->qpel) {
1664                            pMB->pmvs[0].x = Data->currentQMV->x - predMV->x;
1665                            pMB->pmvs[0].y = Data->currentQMV->y - predMV->y;
1666                            if (mode_current == MODE_FORWARD)
1667                                    pMB->qmvs[0] = *Data->currentQMV;
1668          else          else
1669                  iDiamondSize = 2;               // halfpel!                                  pMB->b_qmvs[0] = *Data->currentQMV;
1670                    } else {
1671                            pMB->pmvs[0].x = Data->currentMV->x - predMV->x;
1672                            pMB->pmvs[0].y = Data->currentMV->y - predMV->y;
1673                    }
1674                    if (mode_current == MODE_FORWARD) pMB->mvs[0] = *Data->currentMV;
1675                    else pMB->b_mvs[0] = *Data->currentMV;
1676            }
1677    
1678            if (mode_current == MODE_FORWARD) *(Data->currentMV+2) = *Data->currentMV;
1679            else *(Data->currentMV+1) = *Data->currentMV; /* we store currmv for interpolate search */
1680    }
1681    
1682    static void
1683    SkipDecisionB(const IMAGE * const pCur,
1684                                    const IMAGE * const f_Ref,
1685                                    const IMAGE * const b_Ref,
1686                                    MACROBLOCK * const pMB,
1687                                    const uint32_t x, const uint32_t y,
1688                                    const SearchData * const Data)
1689    {
1690            int dx = 0, dy = 0, b_dx = 0, b_dy = 0;
1691            int32_t sum;
1692            const int div = 1 + Data->qpel;
1693            int k;
1694            const uint32_t stride = Data->iEdgedWidth/2;
1695            /* this is not full chroma compensation, only it's fullpel approximation. should work though */
1696    
1697            for (k = 0; k < 4; k++) {
1698                    dy += Data->directmvF[k].y / div;
1699                    dx += Data->directmvF[k].x / div;
1700                    b_dy += Data->directmvB[k].y / div;
1701                    b_dx += Data->directmvB[k].x / div;
1702            }
1703    
1704            dy = (dy >> 3) + roundtab_76[dy & 0xf];
1705            dx = (dx >> 3) + roundtab_76[dx & 0xf];
1706            b_dy = (b_dy >> 3) + roundtab_76[b_dy & 0xf];
1707            b_dx = (b_dx >> 3) + roundtab_76[b_dx & 0xf];
1708    
1709            sum = sad8bi(pCur->u + 8 * x + 8 * y * stride,
1710                                            f_Ref->u + (y*8 + dy/2) * stride + x*8 + dx/2,
1711                                            b_Ref->u + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1712                                            stride);
1713    
1714            if (sum >= 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) return; /* no skip */
1715    
1716            sum += sad8bi(pCur->v + 8*x + 8 * y * stride,
1717                                            f_Ref->v + (y*8 + dy/2) * stride + x*8 + dx/2,
1718                                            b_Ref->v + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1719                                            stride);
1720    
1721            if (sum < 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) {
1722                    pMB->mode = MODE_DIRECT_NONE_MV; /* skipped */
1723                    for (k = 0; k < 4; k++) {
1724                            pMB->qmvs[k] = pMB->mvs[k];
1725                            pMB->b_qmvs[k] = pMB->b_mvs[k];
1726                    }
1727            }
1728    }
1729    
1730          if (!(MotionFlags & PMV_HALFPELDIAMOND16))  static __inline uint32_t
1731                  iDiamondSize *= 2;  SearchDirect(const IMAGE * const f_Ref,
1732                                    const uint8_t * const f_RefH,
1733                                    const uint8_t * const f_RefV,
1734                                    const uint8_t * const f_RefHV,
1735                                    const IMAGE * const b_Ref,
1736                                    const uint8_t * const b_RefH,
1737                                    const uint8_t * const b_RefV,
1738                                    const uint8_t * const b_RefHV,
1739                                    const IMAGE * const pCur,
1740                                    const int x, const int y,
1741                                    const uint32_t MotionFlags,
1742                                    const int32_t TRB, const int32_t TRD,
1743                                    const MBParam * const pParam,
1744                                    MACROBLOCK * const pMB,
1745                                    const MACROBLOCK * const b_mb,
1746                                    int32_t * const best_sad,
1747                                    SearchData * const Data)
1748    
1749    {
1750            int32_t skip_sad;
1751            int k = (x + Data->iEdgedWidth*y) * 16;
1752            MainSearchFunc *MainSearchPtr;
1753    
1754            *Data->iMinSAD = 256*4096;
1755            Data->RefP[0] = f_Ref->y + k;
1756            Data->RefP[2] = f_RefH + k;
1757            Data->RefP[1] = f_RefV + k;
1758            Data->RefP[3] = f_RefHV + k;
1759            Data->b_RefP[0] = b_Ref->y + k;
1760            Data->b_RefP[2] = b_RefH + k;
1761            Data->b_RefP[1] = b_RefV + k;
1762            Data->b_RefP[3] = b_RefHV + k;
1763            Data->RefP[4] = f_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1764            Data->RefP[5] = f_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1765            Data->b_RefP[4] = b_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1766            Data->b_RefP[5] = b_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1767    
1768            k = Data->qpel ? 4 : 2;
1769            Data->max_dx = k * (pParam->width - x * 16);
1770            Data->max_dy = k * (pParam->height - y * 16);
1771            Data->min_dx = -k * (16 + x * 16);
1772            Data->min_dy = -k * (16 + y * 16);
1773    
1774            Data->referencemv = Data->qpel ? b_mb->qmvs : b_mb->mvs;
1775            Data->qpel_precision = 0;
1776    
1777            for (k = 0; k < 4; k++) {
1778                    pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);
1779                    pMB->b_mvs[k].x = Data->directmvB[k].x = ((TRB - TRD) * Data->referencemv[k].x) / TRD;
1780                    pMB->mvs[k].y = Data->directmvF[k].y = ((TRB * Data->referencemv[k].y) / TRD);
1781                    pMB->b_mvs[k].y = Data->directmvB[k].y = ((TRB - TRD) * Data->referencemv[k].y) / TRD;
1782    
1783                    if ( (pMB->b_mvs[k].x > Data->max_dx) | (pMB->b_mvs[k].x < Data->min_dx)
1784                            | (pMB->b_mvs[k].y > Data->max_dy) | (pMB->b_mvs[k].y < Data->min_dy) ) {
1785    
1786                            *best_sad = 256*4096; /* in that case, we won't use direct mode */
1787                            pMB->mode = MODE_DIRECT; /* just to make sure it doesn't say "MODE_DIRECT_NONE_MV" */
1788                            pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;
1789                            return 256*4096;
1790                    }
1791                    if (b_mb->mode != MODE_INTER4V) {
1792                            pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mvs[0];
1793                            pMB->b_mvs[1] = pMB->b_mvs[2] = pMB->b_mvs[3] = pMB->b_mvs[0];
1794                            Data->directmvF[1] = Data->directmvF[2] = Data->directmvF[3] = Data->directmvF[0];
1795                            Data->directmvB[1] = Data->directmvB[2] = Data->directmvB[3] = Data->directmvB[0];
1796                            break;
1797                    }
1798            }
1799    
1800            CheckCandidate = b_mb->mode == MODE_INTER4V ? CheckCandidateDirect : CheckCandidateDirectno4v;
1801    
1802            CheckCandidate(0, 0, 255, &k, Data);
1803    
1804            /* initial (fast) skip decision */
1805            if (*Data->iMinSAD < pMB->quant * INITIAL_SKIP_THRESH * (Data->chroma?3:2)) {
1806                    /* possible skip */
1807                    if (Data->chroma) {
1808                            pMB->mode = MODE_DIRECT_NONE_MV;
1809                            return *Data->iMinSAD; /* skip. */
1810                    } else {
1811                            SkipDecisionB(pCur, f_Ref, b_Ref, pMB, x, y, Data);
1812                            if (pMB->mode == MODE_DIRECT_NONE_MV) return *Data->iMinSAD; /* skip. */
1813                    }
1814            }
1815    
1816            *Data->iMinSAD += Data->lambda16;
1817            skip_sad = *Data->iMinSAD;
1818    
1819  /*  /*
1820     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.           * DIRECT MODE DELTA VECTOR SEARCH.
1821     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.  
1822  */  */
1823    
1824  // (0,0) is always possible          if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1825                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1826                            else MainSearchPtr = DiamondSearch;
1827    
1828            MainSearchPtr(0, 0, Data, 255);
1829    
1830          if (!MVzero(pmv[0]))          SubpelRefine(Data);
                 CHECK_MV16_ZERO;  
1831    
1832  // previous frame MV is always possible          *best_sad = *Data->iMinSAD;
1833    
1834          if (!MVzero(prevMB->mvs[0]))          if (Data->qpel || b_mb->mode == MODE_INTER4V) pMB->mode = MODE_DIRECT;
1835                  if (!MVequal(prevMB->mvs[0], pmv[0]))          else pMB->mode = MODE_DIRECT_NO4V; /* for faster compensation */
                         CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);  
1836    
1837  // left neighbour, if allowed          pMB->pmvs[3] = *Data->currentMV;
1838    
1839            for (k = 0; k < 4; k++) {
1840                    pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
1841                    pMB->b_mvs[k].x = (     (Data->currentMV->x == 0)
1842                                                            ? Data->directmvB[k].x
1843                                                            :pMB->mvs[k].x - Data->referencemv[k].x);
1844                    pMB->mvs[k].y = (Data->directmvF[k].y + Data->currentMV->y);
1845                    pMB->b_mvs[k].y = ((Data->currentMV->y == 0)
1846                                                            ? Data->directmvB[k].y
1847                                                            : pMB->mvs[k].y - Data->referencemv[k].y);
1848                    if (Data->qpel) {
1849                            pMB->qmvs[k].x = pMB->mvs[k].x; pMB->mvs[k].x /= 2;
1850                            pMB->b_qmvs[k].x = pMB->b_mvs[k].x; pMB->b_mvs[k].x /= 2;
1851                            pMB->qmvs[k].y = pMB->mvs[k].y; pMB->mvs[k].y /= 2;
1852                            pMB->b_qmvs[k].y = pMB->b_mvs[k].y; pMB->b_mvs[k].y /= 2;
1853                    }
1854    
1855          if (!MVzero(pmv[1]))                  if (b_mb->mode != MODE_INTER4V) {
1856                  if (!MVequal(pmv[1], prevMB->mvs[0]))                          pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1857                          if (!MVequal(pmv[1], pmv[0])) {                          pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1858                                  if (!(MotionFlags & PMV_HALFPEL16)) {                          pMB->qmvs[3] = pMB->qmvs[2] = pMB->qmvs[1] = pMB->qmvs[0];
1859                                          pmv[1].x = EVEN(pmv[1].x);                          pMB->b_qmvs[3] = pMB->b_qmvs[2] = pMB->b_qmvs[1] = pMB->b_qmvs[0];
1860                                          pmv[1].y = EVEN(pmv[1].y);                          break;
1861                    }
1862                                  }                                  }
1863            return skip_sad;
1864    }
1865    
1866    static void
1867    SearchInterpolate(const IMAGE * const f_Ref,
1868                                    const uint8_t * const f_RefH,
1869                                    const uint8_t * const f_RefV,
1870                                    const uint8_t * const f_RefHV,
1871                                    const IMAGE * const b_Ref,
1872                                    const uint8_t * const b_RefH,
1873                                    const uint8_t * const b_RefV,
1874                                    const uint8_t * const b_RefHV,
1875                                    const IMAGE * const pCur,
1876                                    const int x, const int y,
1877                                    const uint32_t fcode,
1878                                    const uint32_t bcode,
1879                                    const uint32_t MotionFlags,
1880                                    const MBParam * const pParam,
1881                                    const VECTOR * const f_predMV,
1882                                    const VECTOR * const b_predMV,
1883                                    MACROBLOCK * const pMB,
1884                                    int32_t * const best_sad,
1885                                    SearchData * const fData)
1886    
1887    {
1888    
1889            int iDirection, i, j;
1890            SearchData bData;
1891    
1892            fData->qpel_precision = 0;
1893            memcpy(&bData, fData, sizeof(SearchData)); /* quick copy of common data */
1894            *fData->iMinSAD = 4096*256;
1895            bData.currentMV++; bData.currentQMV++;
1896            fData->iFcode = bData.bFcode = fcode; fData->bFcode = bData.iFcode = bcode;
1897    
1898            i = (x + y * fData->iEdgedWidth) * 16;
1899    
1900            bData.b_RefP[0] = fData->RefP[0] = f_Ref->y + i;
1901            bData.b_RefP[2] = fData->RefP[2] = f_RefH + i;
1902            bData.b_RefP[1] = fData->RefP[1] = f_RefV + i;
1903            bData.b_RefP[3] = fData->RefP[3] = f_RefHV + i;
1904            bData.RefP[0] = fData->b_RefP[0] = b_Ref->y + i;
1905            bData.RefP[2] = fData->b_RefP[2] = b_RefH + i;
1906            bData.RefP[1] = fData->b_RefP[1] = b_RefV + i;
1907            bData.RefP[3] = fData->b_RefP[3] = b_RefHV + i;
1908            bData.b_RefP[4] = fData->RefP[4] = f_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
1909            bData.b_RefP[5] = fData->RefP[5] = f_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
1910            bData.RefP[4] = fData->b_RefP[4] = b_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
1911            bData.RefP[5] = fData->b_RefP[5] = b_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
1912    
1913            bData.bpredMV = fData->predMV = *f_predMV;
1914            fData->bpredMV = bData.predMV = *b_predMV;
1915            fData->currentMV[0] = fData->currentMV[2];
1916    
1917            get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode - fData->qpel, 0, 0);
1918            get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode - fData->qpel, 0, 0);
1919    
1920            if (fData->currentMV[0].x > fData->max_dx) fData->currentMV[0].x = fData->max_dx;
1921            if (fData->currentMV[0].x < fData->min_dx) fData->currentMV[0].x = fData->min_dx;
1922            if (fData->currentMV[0].y > fData->max_dy) fData->currentMV[0].y = fData->max_dy;
1923            if (fData->currentMV[0].y < fData->min_dy) fData->currentMV[0].y = fData->min_dy;
1924    
1925            if (fData->currentMV[1].x > bData.max_dx) fData->currentMV[1].x = bData.max_dx;
1926            if (fData->currentMV[1].x < bData.min_dx) fData->currentMV[1].x = bData.min_dx;
1927            if (fData->currentMV[1].y > bData.max_dy) fData->currentMV[1].y = bData.max_dy;
1928            if (fData->currentMV[1].y < bData.min_dy) fData->currentMV[1].y = bData.min_dy;
1929    
1930            CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, 255, &iDirection, fData);
1931    
1932                                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);          /* diamond */
1933            do {
1934                    iDirection = 255;
1935                    /* forward MV moves */
1936                    i = fData->currentMV[0].x; j = fData->currentMV[0].y;
1937    
1938                    CheckCandidateInt(i + 1, j, 0, &iDirection, fData);
1939                    CheckCandidateInt(i, j + 1, 0, &iDirection, fData);
1940                    CheckCandidateInt(i - 1, j, 0, &iDirection, fData);
1941                    CheckCandidateInt(i, j - 1, 0, &iDirection, fData);
1942    
1943                    /* backward MV moves */
1944                    i = fData->currentMV[1].x; j = fData->currentMV[1].y;
1945                    fData->currentMV[2] = fData->currentMV[0];
1946                    CheckCandidateInt(i + 1, j, 0, &iDirection, &bData);
1947                    CheckCandidateInt(i, j + 1, 0, &iDirection, &bData);
1948                    CheckCandidateInt(i - 1, j, 0, &iDirection, &bData);
1949                    CheckCandidateInt(i, j - 1, 0, &iDirection, &bData);
1950    
1951            } while (!(iDirection));
1952    
1953            /* qpel refinement */
1954            if (fData->qpel) {
1955                    if (*fData->iMinSAD > *best_sad + 500) return;
1956                    CheckCandidate = CheckCandidateInt;
1957                    fData->qpel_precision = bData.qpel_precision = 1;
1958                    get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode, 1, 0);
1959                    get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode, 1, 0);
1960                    fData->currentQMV[2].x = fData->currentQMV[0].x = 2 * fData->currentMV[0].x;
1961                    fData->currentQMV[2].y = fData->currentQMV[0].y = 2 * fData->currentMV[0].y;
1962                    fData->currentQMV[1].x = 2 * fData->currentMV[1].x;
1963                    fData->currentQMV[1].y = 2 * fData->currentMV[1].y;
1964                    SubpelRefine(fData);
1965                    if (*fData->iMinSAD > *best_sad + 300) return;
1966                    fData->currentQMV[2] = fData->currentQMV[0];
1967                    SubpelRefine(&bData);
1968            }
1969    
1970            *fData->iMinSAD += (2+3) * fData->lambda16; /* two bits are needed to code interpolate mode. */
1971    
1972            if (*fData->iMinSAD < *best_sad) {
1973                    *best_sad = *fData->iMinSAD;
1974                    pMB->mvs[0] = fData->currentMV[0];
1975                    pMB->b_mvs[0] = fData->currentMV[1];
1976                    pMB->mode = MODE_INTERPOLATE;
1977                    if (fData->qpel) {
1978                            pMB->qmvs[0] = fData->currentQMV[0];
1979                            pMB->b_qmvs[0] = fData->currentQMV[1];
1980                            pMB->pmvs[1].x = pMB->qmvs[0].x - f_predMV->x;
1981                            pMB->pmvs[1].y = pMB->qmvs[0].y - f_predMV->y;
1982                            pMB->pmvs[0].x = pMB->b_qmvs[0].x - b_predMV->x;
1983                            pMB->pmvs[0].y = pMB->b_qmvs[0].y - b_predMV->y;
1984                    } else {
1985                            pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;
1986                            pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;
1987                            pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;
1988                            pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;
1989                    }
1990            }
1991                          }                          }
1992  // top neighbour, if allowed  
1993          if (!MVzero(pmv[2]))  void
1994                  if (!MVequal(pmv[2], prevMB->mvs[0]))  MotionEstimationBVOP(MBParam * const pParam,
1995                          if (!MVequal(pmv[2], pmv[0]))                                           FRAMEINFO * const frame,
1996                                  if (!MVequal(pmv[2], pmv[1])) {                                           const int32_t time_bp,
1997                                          if (!(MotionFlags & PMV_HALFPEL16)) {                                           const int32_t time_pp,
1998                                                  pmv[2].x = EVEN(pmv[2].x);                                           /* forward (past) reference */
1999                                                  pmv[2].y = EVEN(pmv[2].y);                                           const MACROBLOCK * const f_mbs,
2000                                             const IMAGE * const f_ref,
2001                                             const IMAGE * const f_refH,
2002                                             const IMAGE * const f_refV,
2003                                             const IMAGE * const f_refHV,
2004                                             /* backward (future) reference */
2005                                             const FRAMEINFO * const b_reference,
2006                                             const IMAGE * const b_ref,
2007                                             const IMAGE * const b_refH,
2008                                             const IMAGE * const b_refV,
2009                                             const IMAGE * const b_refHV)
2010    {
2011            uint32_t i, j;
2012            int32_t best_sad;
2013            uint32_t skip_sad;
2014            int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;
2015            const MACROBLOCK * const b_mbs = b_reference->mbs;
2016    
2017            VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
2018    
2019            const int32_t TRB = time_pp - time_bp;
2020            const int32_t TRD = time_pp;
2021    
2022            /* some pre-inintialized data for the rest of the search */
2023    
2024            SearchData Data;
2025            int32_t iMinSAD;
2026            VECTOR currentMV[3];
2027            VECTOR currentQMV[3];
2028            int32_t temp[8];
2029            memset(&Data, 0, sizeof(SearchData));
2030            Data.iEdgedWidth = pParam->edged_width;
2031            Data.currentMV = currentMV; Data.currentQMV = currentQMV;
2032            Data.iMinSAD = &iMinSAD;
2033            Data.lambda16 = lambda_vec16[frame->quant];
2034            Data.qpel = pParam->vol_flags & XVID_VOL_QUARTERPEL;
2035            Data.rounding = 0;
2036            Data.chroma = frame->motion_flags & XVID_ME_CHROMA8;
2037            Data.temp = temp;
2038    
2039            Data.RefQ = f_refV->u; /* a good place, also used in MC (for similar purpose) */
2040    
2041            /* note: i==horizontal, j==vertical */
2042            for (j = 0; j < pParam->mb_height; j++) {
2043    
2044                    f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
2045    
2046                    for (i = 0; i < pParam->mb_width; i++) {
2047                            MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
2048                            const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
2049    
2050    /* special case, if collocated block is SKIPed in P-VOP: encoding is forward (0,0), cpb=0 without further ado */
2051                            if (b_reference->coding_type != S_VOP)
2052                                    if (b_mb->mode == MODE_NOT_CODED) {
2053                                            pMB->mode = MODE_NOT_CODED;
2054                                            continue;
2055                                          }                                          }
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
2056    
2057  // top right neighbour, if allowed                          Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
2058                                          if (!MVzero(pmv[3]))                          Data.CurU = frame->image.u + (j * Data.iEdgedWidth/2 + i) * 8;
2059                                                  if (!MVequal(pmv[3], prevMB->mvs[0]))                          Data.CurV = frame->image.v + (j * Data.iEdgedWidth/2 + i) * 8;
2060                                                          if (!MVequal(pmv[3], pmv[0]))                          pMB->quant = frame->quant;
2061                                                                  if (!MVequal(pmv[3], pmv[1]))  
2062                                                                          if (!MVequal(pmv[3], pmv[2])) {  /* direct search comes first, because it (1) checks for SKIP-mode
2063                                                                                  if (!(MotionFlags & PMV_HALFPEL16)) {          and (2) sets very good predictions for forward and backward search */
2064                                                                                          pmv[3].x = EVEN(pmv[3].x);                          skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2065                                                                                          pmv[3].y = EVEN(pmv[3].y);                                                                          b_ref, b_refH->y, b_refV->y, b_refHV->y,
2066                                                                            &frame->image,
2067                                                                            i, j,
2068                                                                            frame->motion_flags,
2069                                                                            TRB, TRD,
2070                                                                            pParam,
2071                                                                            pMB, b_mb,
2072                                                                            &best_sad,
2073                                                                            &Data);
2074    
2075                            if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
2076    
2077                            /* forward search */
2078                            SearchBF(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2079                                                    &frame->image, i, j,
2080                                                    frame->motion_flags,
2081                                                    frame->fcode, pParam,
2082                                                    pMB, &f_predMV, &best_sad,
2083                                                    MODE_FORWARD, &Data);
2084    
2085                            /* backward search */
2086                            SearchBF(b_ref, b_refH->y, b_refV->y, b_refHV->y,
2087                                                    &frame->image, i, j,
2088                                                    frame->motion_flags,
2089                                                    frame->bcode, pParam,
2090                                                    pMB, &b_predMV, &best_sad,
2091                                                    MODE_BACKWARD, &Data);
2092    
2093                            /* interpolate search comes last, because it uses data from forward and backward as prediction */
2094                            SearchInterpolate(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2095                                                    b_ref, b_refH->y, b_refV->y, b_refHV->y,
2096                                                    &frame->image,
2097                                                    i, j,
2098                                                    frame->fcode, frame->bcode,
2099                                                    frame->motion_flags,
2100                                                    pParam,
2101                                                    &f_predMV, &b_predMV,
2102                                                    pMB, &best_sad,
2103                                                    &Data);
2104    
2105                            /* final skip decision */
2106                            if ( (skip_sad < frame->quant * MAX_SAD00_FOR_SKIP * 2)
2107                                            && ((100*best_sad)/(skip_sad+1) > FINAL_SKIP_THRESH) )
2108                                    SkipDecisionB(&frame->image, f_ref, b_ref, pMB, i, j, &Data);
2109    
2110                            switch (pMB->mode) {
2111                                    case MODE_FORWARD:
2112                                            f_count++;
2113                                            f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2114                                            break;
2115                                    case MODE_BACKWARD:
2116                                            b_count++;
2117                                            b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2118                                            break;
2119                                    case MODE_INTERPOLATE:
2120                                            i_count++;
2121                                            f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2122                                            b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2123                                            break;
2124                                    case MODE_DIRECT:
2125                                    case MODE_DIRECT_NO4V:
2126                                            d_count++;
2127                                    default:
2128                                            break;
2129                            }
2130                                                                                  }                                                                                  }
                                                                                 CHECK_MV16_CANDIDATE(pmv[3].x,  
                                                                                                                          pmv[3].y);  
2131                                                                          }                                                                          }
2132                                  }                                  }
2133    
2134          if ((MVzero(*currMV)) &&  static __inline void
2135                  (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  MEanalyzeMB (   const uint8_t * const pRef,
2136                  iMinSAD -= MV16_00_BIAS;                                  const uint8_t * const pCur,
2137                                    const int x,
2138                                    const int y,
2139                                    const MBParam * const pParam,
2140                                    MACROBLOCK * const pMBs,
2141                                    SearchData * const Data)
2142    {
2143    
2144  /* Step 6: If MinSAD <= thresa goto Step 10.          int i, mask;
2145     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.          int quarterpel = (pParam->vol_flags & XVID_VOL_QUARTERPEL)? 1: 0;
2146  */          VECTOR pmv[3];
2147            MACROBLOCK * const pMB = &pMBs[x + y * pParam->mb_width];
2148    
2149          if ((iMinSAD <= threshA) ||          for (i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;
                 (MVequal(*currMV, prevMB->mvs[0]) &&  
                  ((uint32_t) iMinSAD < prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
         }  
2150    
2151            /* median is only used as prediction. it doesn't have to be real */
2152            if (x == 1 && y == 1) Data->predMV.x = Data->predMV.y = 0;
2153            else
2154                    if (x == 1) /* left macroblock does not have any vector now */
2155                            Data->predMV = (pMB - pParam->mb_width)->mvs[0]; /* top instead of median */
2156                    else if (y == 1) /* top macroblock doesn't have it's vector */
2157                            Data->predMV = (pMB - 1)->mvs[0]; /* left instead of median */
2158                            else Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); /* else median */
2159    
2160  /************ (Diamond Search)  **************/          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2161  /*          pParam->width, pParam->height, Data->iFcode - quarterpel, 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.  
 */  
2162    
2163          if (MotionFlags & PMV_USESQUARES16)          Data->Cur = pCur + (x + y * pParam->edged_width) * 16;
2164                  MainSearchPtr = Square16_MainSearch;          Data->RefP[0] = pRef + (x + y * pParam->edged_width) * 16;
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
2165    
2166          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          pmv[1].x = EVEN(pMB->mvs[0].x);
2167            pmv[1].y = EVEN(pMB->mvs[0].y);
2168            pmv[2].x = EVEN(Data->predMV.x);
2169            pmv[2].y = EVEN(Data->predMV.y);
2170            pmv[0].x = pmv[0].y = 0;
2171    
2172  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          CheckCandidate32I(0, 0, 255, &i, Data);
         iSAD =  
                 (*MainSearchPtr) (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);  
2173    
2174          if (iSAD < iMinSAD) {          if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP) {
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
2175    
2176          if (MotionFlags & PMV_EXTSEARCH16) {                  if (!(mask = make_mask(pmv, 1)))
2177  /* extended: search (up to) two more times: orignal prediction and (0,0) */                          CheckCandidate32I(pmv[1].x, pmv[1].y, mask, &i, Data);
2178                    if (!(mask = make_mask(pmv, 2)))
2179                            CheckCandidate32I(pmv[2].x, pmv[2].y, mask, &i, Data);
2180    
2181                  if (!(MVequal(pmv[0], backupMV))) {                  if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP) /* diamond only if needed */
2182                          iSAD =                          DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, i);
2183                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,          }
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, pmv,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
2184    
2185                          if (iSAD < iMinSAD) {          for (i = 0; i < 4; i++) {
2186                                  *currMV = newMV;                  MACROBLOCK * MB = &pMBs[x + (i&1) + (y+(i>>1)) * pParam->mb_width];
2187                                  iMinSAD = iSAD;                  MB->mvs[0] = MB->mvs[1] = MB->mvs[2] = MB->mvs[3] = Data->currentMV[i];
2188                    MB->mode = MODE_INTER;
2189                    MB->sad16 = Data->iMinSAD[i+1];
2190                          }                          }
2191                  }                  }
2192    
2193                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {  #define INTRA_THRESH    2200
2194                          iSAD =  #define INTER_THRESH    50
2195                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  #define INTRA_THRESH2   95
                                                                   iMinSAD, &newMV, pmv, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
2196    
2197                          if (iSAD < iMinSAD) {  int
2198                                  *currMV = newMV;  MEanalysis(     const IMAGE * const pRef,
2199                                  iMinSAD = iSAD;                          const FRAMEINFO * const Current,
2200                          }                          const MBParam * const pParam,
2201                  }                          const int maxIntra, //maximum number if non-I frames
2202                            const int intraCount, //number of non-I frames after last I frame; 0 if we force P/B frame
2203                            const int bCount,  // number of B frames in a row
2204                            const int b_thresh)
2205    {
2206            uint32_t x, y, intra = 0;
2207            int sSAD = 0;
2208            MACROBLOCK * const pMBs = Current->mbs;
2209            const IMAGE * const pCurrent = &Current->image;
2210            int IntraThresh = INTRA_THRESH, InterThresh = INTER_THRESH + b_thresh;
2211            int blocks = 0;
2212            int complexity = 0;
2213    
2214            int32_t iMinSAD[5], temp[5];
2215            VECTOR currentMV[5];
2216            SearchData Data;
2217            Data.iEdgedWidth = pParam->edged_width;
2218            Data.currentMV = currentMV;
2219            Data.iMinSAD = iMinSAD;
2220            Data.iFcode = Current->fcode;
2221            Data.temp = temp;
2222            CheckCandidate = CheckCandidate32I;
2223    
2224    
2225            if (intraCount != 0) {
2226                    if (intraCount < 10) // we're right after an I frame
2227                            IntraThresh += 15* (intraCount - 10) * (intraCount - 10);
2228                    else
2229                            if ( 5*(maxIntra - intraCount) < maxIntra) // we're close to maximum. 2 sec when max is 10 sec
2230                                    IntraThresh -= (IntraThresh * (maxIntra - 8*(maxIntra - intraCount)))/maxIntra;
2231          }          }
2232    
2233  /*          InterThresh -= 12 * bCount;
2234     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.          if (InterThresh < 15 + b_thresh) InterThresh = 15 + b_thresh;
 */  
2235    
2236    PMVfast16_Terminate_with_Refine:          if (sadInit) (*sadInit) ();
         if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step  
                 iMinSAD =  
                         Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                          iMinSAD, pmv, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
2237    
2238    PMVfast16_Terminate_without_Refine:          for (y = 1; y < pParam->mb_height-1; y += 2) {
2239          currPMV->x = currMV->x - pmv[0].x;                  for (x = 1; x < pParam->mb_width-1; x += 2) {
2240          currPMV->y = currMV->y - pmv[0].y;                          int i;
2241          return iMinSAD;                          blocks += 10;
 }  
2242    
2243                            if (bCount == 0) pMBs[x + y * pParam->mb_width].mvs[0] = zeroMV;
2244                            else { //extrapolation of the vector found for last frame
2245                                    pMBs[x + y * pParam->mb_width].mvs[0].x =
2246                                            (pMBs[x + y * pParam->mb_width].mvs[0].x * (bCount+1) ) / bCount;
2247                                    pMBs[x + y * pParam->mb_width].mvs[0].y =
2248                                            (pMBs[x + y * pParam->mb_width].mvs[0].y * (bCount+1) ) / bCount;
2249                            }
2250    
2251                            MEanalyzeMB(pRef->y, pCurrent->y, x, y, pParam, pMBs, &Data);
2252    
2253                            for (i = 0; i < 4; i++) {
2254                                    int dev;
2255                                    MACROBLOCK *pMB = &pMBs[x+(i&1) + (y+(i>>1)) * pParam->mb_width];
2256                                    dev = dev16(pCurrent->y + (x + (i&1) + (y + (i>>1)) * pParam->edged_width) * 16,
2257                                                                    pParam->edged_width);
2258    
2259                                    complexity += dev;
2260                                    if (dev + IntraThresh < pMB->sad16) {
2261                                            pMB->mode = MODE_INTRA;
2262                                            if (++intra > ((pParam->mb_height-2)*(pParam->mb_width-2))/2) return I_VOP;
2263                                    }
2264    
2265                                    if (pMB->mvs[0].x == 0 && pMB->mvs[0].y == 0)
2266                                            if (dev > 500 && pMB->sad16 < 1000)
2267                                                    sSAD += 1000;
2268    
2269  int32_t                                  sSAD += pMB->sad16;
 Diamond8_MainSearch(const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x,  
                                         const int y,  
                                         int32_t startx,  
                                         int32_t starty,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                         const VECTOR * const pmv,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = startx;  
         backupMV.y = starty;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         CHECK_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);  
         } else {  
                 currMV->x = startx;  
                 currMV->y = starty;  
2270          }          }
         return iMinSAD;  
2271  }  }
2272            }
2273            complexity >>= 7;
2274    
2275  int32_t          sSAD /= complexity + 4*blocks;
 Halfpel8_Refine(const uint8_t * const pRef,  
                                 const uint8_t * const pRefH,  
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const uint8_t * const cur,  
                                 const int x,  
                                 const int y,  
                                 VECTOR * const currMV,  
                                 int32_t iMinSAD,  
                                 const VECTOR * const pmv,  
                                 const int32_t min_dx,  
                                 const int32_t max_dx,  
                                 const int32_t min_dy,  
                                 const int32_t max_dy,  
                                 const int32_t iFcode,  
                                 const int32_t iQuant,  
                                 const int32_t iEdgedWidth)  
 {  
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
   
         int32_t iSAD;  
         VECTOR backupMV = *currMV;  
   
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y + 1);  
         CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y + 1);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y + 1);  
2276    
2277          return iMinSAD;          if (intraCount > 12 && sSAD > INTRA_THRESH2 ) return I_VOP;
2278            if (sSAD > InterThresh ) return P_VOP;
2279            emms();
2280            return B_VOP;
2281  }  }
2282    
2283    
2284  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)  /* functions which perform BITS-based search/bitcount */
2285    
2286  int32_t  static int
2287  PMVfastSearch8(const uint8_t * const pRef,  CountMBBitsInter(SearchData * const Data,
2288                             const uint8_t * const pRefH,                                  const MACROBLOCK * const pMBs, const int x, const int y,
                            const uint8_t * const pRefV,  
                            const uint8_t * const pRefHV,  
                            const IMAGE * const pCur,  
                            const int x,  
                            const int y,  
                            const int start_x,  
                            const int start_y,  
                            const uint32_t MotionFlags,  
                            const uint32_t iQuant,  
                            const uint32_t iFcode,  
2289                             const MBParam * const pParam,                             const MBParam * const pParam,
2290                             const MACROBLOCK * const pMBs,                                  const uint32_t MotionFlags)
                            const MACROBLOCK * const prevMBs,  
                            VECTOR * const currMV,  
                            VECTOR * const currPMV)  
2291  {  {
2292          const uint32_t iWcount = pParam->mb_width;          int i, iDirection;
2293          const int32_t iWidth = pParam->width;          int32_t bsad[5];
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
   
         const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;  
   
         int32_t iDiamondSize;  
2294    
2295          int32_t min_dx;          CheckCandidate = CheckCandidateBits16;
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
2296    
2297          VECTOR pmv[4];          if (Data->qpel) {
2298          int32_t psad[4];                  for(i = 0; i < 5; i++) {
2299          VECTOR newMV;                          Data->currentMV[i].x = Data->currentQMV[i].x/2;
2300          VECTOR backupMV;                          Data->currentMV[i].y = Data->currentQMV[i].y/2;
2301          VECTOR startMV;                  }
2302                    Data->qpel_precision = 1;
2303                    CheckCandidateBits16(Data->currentQMV[0].x, Data->currentQMV[0].y, 255, &iDirection, Data);
2304    
2305  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;                  if (MotionFlags & (XVID_ME_HALFPELREFINE16_BITS | XVID_ME_EXTSEARCH_BITS)) { /* we have to prepare for halfpixel-precision search */
2306          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;                          for(i = 0; i < 5; i++) bsad[i] = Data->iMinSAD[i];
2307                            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2308                                                    pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
2309                            Data->qpel_precision = 0;
2310                            if (Data->currentQMV->x & 1 || Data->currentQMV->y & 1)
2311                                    CheckCandidateBits16(Data->currentMV[0].x, Data->currentMV[0].y, 255, &iDirection, Data);
2312                    }