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

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

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