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

Legend:
Removed from v.181  
changed lines
  Added in v.1081

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