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

Legend:
Removed from v.184  
changed lines
  Added in v.1084

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