[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 1107, Sat Aug 2 15:08:48 2003 UTC
# Line 1  Line 1 
1  /**************************************************************************  /*****************************************************************************
2   *   *
3   *  Modifications:   *  XVID MPEG-4 VIDEO CODEC
4     *  - Motion Estimation related code  -
5   *   *
6   *      01.05.2002      updated MotionEstimationBVOP   *  Copyright(C) 2002 Christoph Lampert <gruel@web.de>
7   *      25.04.2002 partial prevMB conversion   *               2002 Michael Militzer <michael@xvid.org>
8   *  22.04.2002 remove some compile warning by chenm001 <chenm001@163.com>   *               2002-2003 Radoslaw Czyz <xvid@syskin.cjb.net>
  *  14.04.2002 added MotionEstimationBVOP()  
  *  02.04.2002 add EPZS(^2) as ME algorithm, use PMV_USESQUARES to choose between  
  *             EPZS and EPZS^2  
  *  08.02.2002 split up PMVfast into three routines: PMVFast, PMVFast_MainLoop  
  *             PMVFast_Refine to support multiple searches with different start points  
  *  07.01.2002 uv-block-based interpolation  
  *  06.01.2002 INTER/INTRA-decision is now done before any SEARCH8 (speedup)  
  *             changed INTER_BIAS to 150 (as suggested by suxen_drol)  
  *             removed halfpel refinement step in PMVfastSearch8 + quality=5  
  *             added new quality mode = 6 which performs halfpel refinement  
  *             filesize difference between quality 5 and 6 is smaller than 1%  
  *             (Isibaar)  
  *  31.12.2001 PMVfastSearch16 and PMVfastSearch8 (gruel)  
  *  30.12.2001 get_range/MotionSearchX simplified; blue/green bug fix  
  *  22.12.2001 commented best_point==99 check  
  *  19.12.2001 modified get_range (purple bug fix)  
  *  15.12.2001 moved pmv displacement from mbprediction  
  *  02.12.2001 motion estimation/compensation split (Isibaar)  
  *  16.11.2001 rewrote/tweaked search algorithms; pross@cs.rmit.edu.au  
  *  10.11.2001 support for sad16/sad8 functions  
  *  28.08.2001 reactivated MODE_INTER4V for EXT_MODE  
  *  24.08.2001 removed MODE_INTER4V_Q, disabled MODE_INTER4V for EXT_MODE  
  *  22.08.2001 added MODE_INTER4V_Q  
  *  20.08.2001 added pragma to get rid of internal compiler error with VC6  
  *             idea by Cyril. Thanks.  
9   *   *
10   *  Michael Militzer <isibaar@videocoding.de>   *  This program is free software ; you can redistribute it and/or modify
11     *  it under the terms of the GNU General Public License as published by
12     *  the Free Software Foundation ; either version 2 of the License, or
13     *  (at your option) any later version.
14   *   *
15   **************************************************************************/   *  This program is distributed in the hope that it will be useful,
16     *  but WITHOUT ANY WARRANTY ; without even the implied warranty of
17     *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18     *  GNU General Public License for more details.
19     *
20     *  You should have received a copy of the GNU General Public License
21     *  along with this program ; if not, write to the Free Software
22     *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
23     *
24     * $Id: motion_est.c,v 1.58.2.24 2003-08-02 15:08:39 edgomez Exp $
25     *
26     ****************************************************************************/
27    
28  #include <assert.h>  #include <assert.h>
29  #include <stdio.h>  #include <stdio.h>
30  #include <stdlib.h>  #include <stdlib.h>
31    #include <string.h>     /* memcpy */
32    #include <math.h>       /* lrint */
33    
34  #include "../encoder.h"  #include "../encoder.h"
35  #include "../utils/mbfunctions.h"  #include "../utils/mbfunctions.h"
36  #include "../prediction/mbprediction.h"  #include "../prediction/mbprediction.h"
37  #include "../global.h"  #include "../global.h"
38  #include "../utils/timer.h"  #include "../utils/timer.h"
39    #include "../image/interpolate8x8.h"
40    #include "motion_est.h"
41  #include "motion.h"  #include "motion.h"
42  #include "sad.h"  #include "sad.h"
43    #include "gmc.h"
44    #include "../utils/emms.h"
45    #include "../dct/fdct.h"
46    
47    /*****************************************************************************
48     * Modified rounding tables -- declared in motion.h
49     * Original tables see ISO spec tables 7-6 -> 7-9
50     ****************************************************************************/
51    
52    const uint32_t roundtab[16] =
53    {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2 };
54    
55    /* K = 4 */
56    const uint32_t roundtab_76[16] =
57    { 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1 };
58    
59    /* K = 2 */
60    const uint32_t roundtab_78[8] =
61    { 0, 0, 1, 1, 0, 0, 0, 1  };
62    
63    /* K = 1 */
64    const uint32_t roundtab_79[4] =
65    { 0, 1, 0, 0 };
66    
67    #define INITIAL_SKIP_THRESH     (10)
68    #define FINAL_SKIP_THRESH       (50)
69    #define MAX_SAD00_FOR_SKIP      (20)
70    #define MAX_CHROMA_SAD_FOR_SKIP (22)
71    
72    #define CHECK_CANDIDATE(X,Y,D) { \
73    CheckCandidate((X),(Y), (D), &iDirection, data ); }
74    
75    
76    /*****************************************************************************
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      if (component < 0)          int32_t sad; uint32_t t;
                 component = -component;  
319    
320      if (iFcode == 1)          if ( (x > data->max_dx) || (x < data->min_dx)
321      {                  || (y > data->max_dy) || (y < data->min_dy) ) return;
                 if (component > 32)  
                     component = 32;  
322    
323                  return mvtab[component] + 1;          if (!data->qpel_precision) {
324                    Reference = GetReference(x, y, data);
325                    current = data->currentMV;
326                    xc = x; yc = y;
327            } else { /* x and y are in 1/4 precision */
328                    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            sad += (data->lambda16 * t * sad)>>10;
337            data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;
338    
339      if (component > 32)          if (data->chroma && sad < data->iMinSAD[0])
340                  component = 32;                  sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
341                                                            (yc >> 1) + roundtab_79[yc & 0x3], data);
342    
343      return mvtab[component] + 1 + iFcode - 1;          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;
471    
472                                          if (sad8 < pMB->sad16)          Reference = GetReference(x, y, data);
473                                                  sad8 += pMB->sad8[1]    = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,  //      xc = x; yc = y;
                                                                                                                         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]);  
474    
475                                          /* decide: MODE_INTER or MODE_INTER4V          sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
476                                                  mpeg4:   if (sad8 < pMB->sad16 - nb/2+1) use_inter4v  //      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;
732          backupMV.x = startx;  
733          backupMV.y = starty;          /* chroma V */
734            ptr = interpolate8x8_switch2(data->RefQ, data->RefP[5], 0, 0, xc, yc, data->iEdgedWidth/2, data->rounding);
735          for (dx = min_dx; dx<=max_dx; dx+=iDiamondSize)          transfer_8to16subro(in, data->CurV, ptr, data->iEdgedWidth/2);
736                  for (dy = min_dy; dy<= max_dy; dy+=iDiamondSize)          bits += Block_CalcBits(coeff, in, data->dctSpace + 128, data->iQuant, data->quant_type, &cbp, 5);
737                          NOCHECK_MV16_CANDIDATE(dx,dy);  
738            bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTER & 7) | ((cbp & 3) << 3)].len;
739    
740          return iMinSAD;          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)
949                                          int32_t iMinSAD,  
950                                          VECTOR * const currMV,  {
951                                          const VECTOR * const pmv,          int offset = (x + y*stride)*8;
952                                          const int32_t min_dx, const int32_t max_dx,          if(!rrv) {
953                                          const int32_t min_dy, const int32_t max_dy,                  uint32_t sadC = sad8(current->u + offset,
954                                          const int32_t iEdgedWidth,                                                  reference->u + offset, stride);
955                                          const int32_t iDiamondSize,                  if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
956                                          const int32_t iFcode,                  sadC += sad8(current->v + offset,
957                                          const int32_t iQuant,                                                  reference->v + offset, stride);
958                                          int iFound)                  if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
959  {                  return 1;
         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);  
960    
961          return iMinSAD;          } 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    static __inline void
982    ZeroMacroblockP(MACROBLOCK *pMB, const int32_t sad)
983    {
984            pMB->mode = MODE_INTER;
985            pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = zeroMV;
986            pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] = pMB->qmvs[3] = zeroMV;
987            pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
988    }
989    
990  int32_t Halfpel16_Refine(  static __inline void
991          const uint8_t * const pRef,  ModeDecision(SearchData * const Data,
992          const uint8_t * const pRefH,                          MACROBLOCK * const pMB,
993          const uint8_t * const pRefV,                          const MACROBLOCK * const pMBs,
         const uint8_t * const pRefHV,  
         const uint8_t * const cur,  
994          const int x, const int y,          const int x, const int y,
995          VECTOR * const currMV,                          const MBParam * const pParam,
996          int32_t iMinSAD,                          const uint32_t MotionFlags,
997          const VECTOR * const pmv,                          const uint32_t VopFlags,
998          const int32_t min_dx, const int32_t max_dx,                          const uint32_t VolFlags,
999          const int32_t min_dy, const int32_t max_dy,                          const IMAGE * const pCurrent,
1000          const int32_t iFcode,                          const IMAGE * const pRef,
1001          const int32_t iQuant,                          const IMAGE * const vGMC,
1002          const int32_t iEdgedWidth)                          const int coding_type)
1003  {  {
1004  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */          int mode = MODE_INTER;
1005            int mcsel = 0;
1006            int inter4v = (VopFlags & XVID_VOP_INTER4V) && (pMB->dquant == 0);
1007            const uint32_t iQuant = pMB->quant;
1008    
1009          int32_t iSAD;          const int skip_possible = (coding_type == P_VOP) && (pMB->dquant == 0);
         VECTOR backupMV = *currMV;  
1010    
1011          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);  
1012    
1013          return iMinSAD;          if (!(VopFlags & XVID_VOP_MODEDECISION_RD)) { /* normal, fast, SAD-based mode decision */
1014                    int sad;
1015                    int InterBias = MV16_INTER_BIAS;
1016                    if (inter4v == 0 || Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
1017                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant) {
1018                            mode = MODE_INTER;
1019                            sad = Data->iMinSAD[0];
1020                    } else {
1021                            mode = MODE_INTER4V;
1022                            sad = Data->iMinSAD[1] + Data->iMinSAD[2] +
1023                                                    Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant;
1024                            Data->iMinSAD[0] = sad;
1025  }  }
1026    
1027  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)                  /* final skip decision, a.k.a. "the vector you found, really that good?" */
1028                    if (skip_possible && (pMB->sad16 < (int)iQuant * MAX_SAD00_FOR_SKIP))
1029                            if ( (100*sad)/(pMB->sad16+1) > FINAL_SKIP_THRESH)
1030                                    if (Data->chroma || SkipDecisionP(pCurrent, pRef, x, y, Data->iEdgedWidth/2, iQuant, Data->rrv)) {
1031                                            mode = MODE_NOT_CODED;
1032                                            sad = 0;
1033                                    }
1034    
1035                    /* mcsel */
1036                    if (coding_type == S_VOP) {
1037    
1038  int32_t PMVfastSearch16(                          int32_t iSAD = sad16(Data->Cur,
1039                                          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;  
1040    
1041          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;                          if (Data->chroma) {
1042                                    iSAD += sad8(Data->CurU, vGMC->u + 8*y*(Data->iEdgedWidth/2) + 8*x, Data->iEdgedWidth/2);
1043                                    iSAD += sad8(Data->CurV, vGMC->v + 8*y*(Data->iEdgedWidth/2) + 8*x, Data->iEdgedWidth/2);
1044                            }
1045    
1046          int32_t iDiamondSize;                          if (iSAD <= sad) {              /* mode decision GMC */
1047                                    mode = MODE_INTER;
1048                                    mcsel = 1;
1049                                    sad = iSAD;
1050                            }
1051    
1052          int32_t min_dx;                  }
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
1053    
1054          int32_t iFound;                  /* intra decision */
1055    
1056          VECTOR newMV;                  if (iQuant > 8) InterBias += 100 * (iQuant - 8); /* to make high quants work */
1057          VECTOR backupMV;        /* just for PMVFAST */                  if (y != 0)
1058                            if ((pMB - pParam->mb_width)->mode == MODE_INTRA ) InterBias -= 80;
1059                    if (x != 0)
1060                            if ((pMB - 1)->mode == MODE_INTRA ) InterBias -= 80;
1061    
1062          VECTOR pmv[4];                  if (Data->chroma) InterBias += 50; /* dev8(chroma) ??? <-- yes, we need dev8 (no big difference though) */
1063          int32_t psad[4];                  if (Data->rrv) InterBias *= 4;
1064    
1065          MainSearch16FuncPtr MainSearchPtr;                  if (InterBias < sad) {
1066                            int32_t deviation;
1067                            if (!Data->rrv)
1068                                    deviation = dev16(Data->Cur, Data->iEdgedWidth);
1069                            else
1070                                    deviation = dev16(Data->Cur, Data->iEdgedWidth) + /* dev32() */
1071                                                            dev16(Data->Cur+16, Data->iEdgedWidth) +
1072                                                            dev16(Data->Cur + 16*Data->iEdgedWidth, Data->iEdgedWidth) +
1073                                                            dev16(Data->Cur+16+16*Data->iEdgedWidth, Data->iEdgedWidth);
1074    
1075  //      const MACROBLOCK * const pMB = pMBs + x + y * iWcount;                          if (deviation < (sad - InterBias)) mode = MODE_INTRA;
1076          const MACROBLOCK * const prevMB = prevMBs + x + y * iWcount;                  }
1077    
1078          static int32_t threshA,threshB;                  pMB->cbp = 63;
1079          int32_t bPredEq;                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
         int32_t iMinSAD,iSAD;  
1080    
1081  /* Get maximum range */          } else { /* BITS */
         get_range(&min_dx, &max_dx, &min_dy, &max_dy,  
                   x, y, 16, iWidth, iHeight, iFcode);  
1082    
1083  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */                  int bits, intra, i, cbp, c[2] = {0, 0};
1084                    VECTOR backup[5], *v;
1085                    Data->iQuant = iQuant;
1086                    Data->cbp = c;
1087    
1088          if (!(MotionFlags & PMV_HALFPEL16 ))                  v = Data->qpel ? Data->currentQMV : Data->currentMV;
1089          { min_dx = EVEN(min_dx);                  for (i = 0; i < 5; i++) {
1090          max_dx = EVEN(max_dx);                          Data->iMinSAD[i] = 256*4096;
1091          min_dy = EVEN(min_dy);                          backup[i] = v[i];
1092          max_dy = EVEN(max_dy);                  }
         }               /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
1093    
1094                    bits = CountMBBitsInter(Data, pMBs, x, y, pParam, MotionFlags);
1095                    cbp = *Data->cbp;
1096    
1097          bPredEq  = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);                  if (coding_type == S_VOP) {
1098                            int bits_gmc;
1099                            *Data->iMinSAD = bits += BITS_MULT*1; /* mcsel */
1100                            bits_gmc = CountMBBitsGMC(Data, vGMC, x, y);
1101                            if (bits_gmc < bits) {
1102                                    mcsel = 1;
1103                                    *Data->iMinSAD = bits = bits_gmc;
1104                                    mode = MODE_INTER;
1105                                    cbp = *Data->cbp;
1106                            }
1107                    }
1108    
1109          if ((x==0) && (y==0) )                  if (inter4v) {
1110          {                          int bits_4v;
1111                  threshA =  512;                          bits_4v = CountMBBitsInter4v(Data, pMB, pMBs, x, y, pParam, MotionFlags, backup);
1112                  threshB = 1024;                          if (bits_4v < bits) {
1113                                    Data->iMinSAD[0] = bits = bits_4v;
1114                                    mode = MODE_INTER4V;
1115                                    cbp = *Data->cbp;
1116                            }
1117                    }
1118    
1119                    intra = CountMBBitsIntra(Data);
1120                    if (intra < bits) {
1121                            *Data->iMinSAD = bits = intra;
1122                            mode = MODE_INTRA;
1123          }          }
1124          else  
1125          {                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = 0;
1126                  threshA = psad[0];                  pMB->cbp = cbp;
                 threshB = threshA+256;  
                 if (threshA< 512) threshA =  512;  
                 if (threshA>1024) threshA = 1024;  
                 if (threshB>1792) threshB = 1792;  
1127          }          }
1128    
1129          iFound=0;          if (Data->rrv) {
1130                            Data->currentMV[0].x = RRV_MV_SCALEDOWN(Data->currentMV[0].x);
1131                            Data->currentMV[0].y = RRV_MV_SCALEDOWN(Data->currentMV[0].y);
1132            }
1133    
1134  /* Step 4: Calculate SAD around the Median prediction.          if (mode == MODE_INTER && mcsel == 0) {
1135     MinSAD=SAD                  pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
1136    
1137          *currMV=pmv[0];         /* current best := prediction */                  if(Data->qpel) {
1138          if (!(MotionFlags & PMV_HALFPEL16 ))                          pMB->qmvs[0] = pMB->qmvs[1]
1139          {       /* This should NOT be necessary! */                                  = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1140                  currMV->x = EVEN(currMV->x);                          pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1141                  currMV->y = EVEN(currMV->y);                          pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;
1142                    } else {
1143                            pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1144                            pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
1145          }          }
1146    
1147          if (currMV->x > max_dx)          } else if (mode == MODE_INTER ) { // but mcsel == 1
1148          {  
1149                  currMV->x=max_dx;                  pMB->mcsel = 1;
1150                    if (Data->qpel) {
1151                            pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] = pMB->qmvs[3] = pMB->amv;
1152                            pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = pMB->amv.x/2;
1153                            pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = pMB->amv.y/2;
1154                    } else
1155                            pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->amv;
1156    
1157            } else
1158                    if (mode == MODE_INTER4V) ; /* anything here? */
1159            else    /* INTRA, NOT_CODED */
1160                    SkipMacroblockP(pMB, 0);
1161    
1162            pMB->mode = mode;
1163          }          }
1164          if (currMV->x < min_dx)  
1165    bool
1166    MotionEstimation(MBParam * const pParam,
1167                                     FRAMEINFO * const current,
1168                                     FRAMEINFO * const reference,
1169                                     const IMAGE * const pRefH,
1170                                     const IMAGE * const pRefV,
1171                                     const IMAGE * const pRefHV,
1172                                    const IMAGE * const pGMC,
1173                                     const uint32_t iLimit)
1174          {          {
1175                  currMV->x=min_dx;          MACROBLOCK *const pMBs = current->mbs;
1176            const IMAGE *const pCurrent = &current->image;
1177            const IMAGE *const pRef = &reference->image;
1178    
1179            uint32_t mb_width = pParam->mb_width;
1180            uint32_t mb_height = pParam->mb_height;
1181            const uint32_t iEdgedWidth = pParam->edged_width;
1182            const uint32_t MotionFlags = MakeGoodMotionFlags(current->motion_flags, current->vop_flags, current->vol_flags);
1183    
1184            uint32_t x, y;
1185            uint32_t iIntra = 0;
1186            int32_t quant = current->quant, sad00;
1187            int skip_thresh = INITIAL_SKIP_THRESH * \
1188                    (current->vop_flags & XVID_VOP_REDUCED ? 4:1) * \
1189                    (current->vop_flags & XVID_VOP_MODEDECISION_RD ? 2:1);
1190    
1191            /* some pre-initialized thingies for SearchP */
1192            int32_t temp[8];
1193            VECTOR currentMV[5];
1194            VECTOR currentQMV[5];
1195            int32_t iMinSAD[5];
1196            DECLARE_ALIGNED_MATRIX(dct_space, 3, 64, int16_t, CACHE_LINE);
1197            SearchData Data;
1198            memset(&Data, 0, sizeof(SearchData));
1199            Data.iEdgedWidth = iEdgedWidth;
1200            Data.currentMV = currentMV;
1201            Data.currentQMV = currentQMV;
1202            Data.iMinSAD = iMinSAD;
1203            Data.temp = temp;
1204            Data.iFcode = current->fcode;
1205            Data.rounding = pParam->m_rounding_type;
1206            Data.qpel = (current->vol_flags & XVID_VOL_QUARTERPEL ? 1:0);
1207            Data.chroma = MotionFlags & XVID_ME_CHROMA_PVOP;
1208            Data.rrv = (current->vop_flags & XVID_VOP_REDUCED) ? 1:0;
1209            Data.dctSpace = dct_space;
1210            Data.quant_type = !(pParam->vol_flags & XVID_VOL_MPEGQUANT);
1211    
1212            if ((current->vop_flags & XVID_VOP_REDUCED)) {
1213                    mb_width = (pParam->width + 31) / 32;
1214                    mb_height = (pParam->height + 31) / 32;
1215                    Data.qpel = 0;
1216            }
1217    
1218            Data.RefQ = pRefV->u; /* a good place, also used in MC (for similar purpose) */
1219            if (sadInit) (*sadInit) ();
1220    
1221            for (y = 0; y < mb_height; y++) {
1222                    for (x = 0; x < mb_width; x++)  {
1223                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1224    
1225                            if (!Data.rrv) pMB->sad16 =
1226                                    sad16v(pCurrent->y + (x + y * iEdgedWidth) * 16,
1227                                                            pRef->y + (x + y * iEdgedWidth) * 16,
1228                                                            pParam->edged_width, pMB->sad8 );
1229    
1230                            else pMB->sad16 =
1231                                    sad32v_c(pCurrent->y + (x + y * iEdgedWidth) * 32,
1232                                                            pRef->y + (x + y * iEdgedWidth) * 32,
1233                                                            pParam->edged_width, pMB->sad8 );
1234    
1235                            if (Data.chroma) {
1236                                    Data.temp[7] = sad8(pCurrent->u + x*8 + y*(iEdgedWidth/2)*8,
1237                                                                            pRef->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2)
1238                                                                    + sad8(pCurrent->v + (x + y*(iEdgedWidth/2))*8,
1239                                                                            pRef->v + (x + y*(iEdgedWidth/2))*8, iEdgedWidth/2);
1240                                    pMB->sad16 += Data.temp[7];
1241                            }
1242    
1243                            sad00 = pMB->sad16;
1244    
1245                            if (pMB->dquant != 0) {
1246                                    quant += DQtab[pMB->dquant];
1247                                    if (quant > 31) quant = 31;
1248                                    else if (quant < 1) quant = 1;
1249                            }
1250                            pMB->quant = quant;
1251    
1252                            /* initial skip decision */
1253                            /* no early skip for GMC (global vector = skip vector is unknown!)  */
1254                            if (current->coding_type != S_VOP)      { /* no fast SKIP for S(GMC)-VOPs */
1255                                    if (pMB->dquant == 0 && sad00 < pMB->quant * skip_thresh)
1256                                            if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, iEdgedWidth/2, pMB->quant, Data.rrv)) {
1257                                                    SkipMacroblockP(pMB, sad00);
1258                                                    continue;
1259          }          }
         if (currMV->y > max_dy)  
         {  
                 currMV->y=max_dy;  
1260          }          }
1261          if (currMV->y < min_dy)  
1262          {                          if ((current->vop_flags & XVID_VOP_CARTOON) &&
1263                  currMV->y=min_dy;                                  (sad00 < pMB->quant * 4 * skip_thresh)) { /* favorize (0,0) vector for cartoons */
1264                                    ZeroMacroblockP(pMB, sad00);
1265                                    continue;
1266          }          }
1267    
1268          iMinSAD = sad16( cur,                          SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1269                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV, iEdgedWidth),                                          y, MotionFlags, current->vop_flags, current->vol_flags,
1270                           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);  
1271    
1272          if ( (iMinSAD < 256 ) || ( (MVequal(*currMV,prevMB->mvs[0])) && ((uint32_t)iMinSAD < prevMB->sad16) ) )                          ModeDecision(&Data, pMB, pMBs, x, y, pParam,
1273          {                                                   MotionFlags, current->vop_flags, current->vol_flags,
1274                  if (iMinSAD < 2*iQuant) // high chances for SKIP-mode                                                   pCurrent, pRef, pGMC, current->coding_type);
1275                  {  
1276                          if (!MVzero(*currMV))                          if (pMB->mode == MODE_INTRA)
1277                          {                                  if (++iIntra > iLimit) return 1;
                                 iMinSAD += MV16_00_BIAS;  
                                 CHECK_MV16_ZERO;                // (0,0) saves space for letterboxed pictures  
                                 iMinSAD -= MV16_00_BIAS;  
1278                          }                          }
1279                  }                  }
1280    
1281                  if (MotionFlags & PMV_QUICKSTOP16)  //      if (current->vol_flags & XVID_VOL_GMC ) /* GMC only for S(GMC)-VOPs */
1282                          goto PMVfast16_Terminate_without_Refine;  //      {
1283                  if (MotionFlags & PMV_EARLYSTOP16)  //              current->warp = GlobalMotionEst( pMBs, pParam, current, reference, pRefH, pRefV, pRefHV);
1284                          goto PMVfast16_Terminate_with_Refine;  //      }
1285            return 0;
1286          }          }
1287    
1288    
1289  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  static __inline int
1290     vector of the median.  make_mask(const VECTOR * const pmv, const int i)
1291     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  {
1292  */          int mask = 255, j;
1293            for (j = 0; j < i; j++) {
1294          if ((bPredEq) && (MVequal(pmv[0],prevMB->mvs[0]) ) )                  if (MVequal(pmv[i], pmv[j])) return 0; /* same vector has been checked already */
1295                  iFound=2;                  if (pmv[i].x == pmv[j].x) {
1296                            if (pmv[i].y == pmv[j].y + iDiamondSize) mask &= ~4;
1297  /* 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;
1298     Otherwise select large Diamond Search.                  } else
1299  */                          if (pmv[i].y == pmv[j].y) {
1300                                    if (pmv[i].x == pmv[j].x + iDiamondSize) mask &= ~1;
1301                                    else if (pmv[i].x == pmv[j].x - iDiamondSize) mask &= ~2;
1302                            }
1303            }
1304            return mask;
1305    }
1306    
1307          if ( (!MVzero(pmv[0])) || (threshB<1536) || (bPredEq) )  static __inline void
1308                  iDiamondSize=1; // halfpel!  PreparePredictionsP(VECTOR * const pmv, int x, int y, int iWcount,
1309          else                          int iHcount, const MACROBLOCK * const prevMB, int rrv)
1310                  iDiamondSize=2; // halfpel!  {
1311            /* this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself */
1312            if (rrv) { iWcount /= 2; iHcount /= 2; }
1313    
1314          if (!(MotionFlags & PMV_HALFPELDIAMOND16) )          if ( (y != 0) && (x < (iWcount-1)) ) {          /* [5] top-right neighbour */
1315                  iDiamondSize*=2;                  pmv[5].x = EVEN(pmv[3].x);
1316                    pmv[5].y = EVEN(pmv[3].y);
1317            } else pmv[5].x = pmv[5].y = 0;
1318    
1319  /*          if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }/* pmv[3] is left neighbour */
1320     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.  
 */  
1321    
1322  // (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 */
1323            else pmv[4].x = pmv[4].y = 0;
1324    
1325          if (!MVzero(pmv[0]))          /* [1] median prediction */
1326                  CHECK_MV16_ZERO;          pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
1327    
1328  // 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 */
1329    
1330          if (!MVzero(prevMB->mvs[0]))          pmv[2].x = EVEN(prevMB->mvs[0].x); /* [2] is last frame */
1331          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);  
1332    
1333  // left neighbour, if allowed          if ((x < iWcount-1) && (y < iHcount-1)) {
1334                    pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); /* [6] right-down neighbour in last frame */
1335                    pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
1336            } else pmv[6].x = pmv[6].y = 0;
1337    
1338          if (!MVzero(pmv[1]))          if (rrv) {
1339          if (!MVequal(pmv[1],prevMB->mvs[0]))                  int i;
1340          if (!MVequal(pmv[1],pmv[0]))                  for (i = 0; i < 7; i++) {
1341          {                          pmv[i].x = RRV_MV_SCALEUP(pmv[i].x);
1342                  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);  
1343                  }                  }
   
                 CHECK_MV16_CANDIDATE(pmv[1].x,pmv[1].y);  
1344          }          }
   
 // 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);  
1345                  }                  }
                 CHECK_MV16_CANDIDATE(pmv[2].x,pmv[2].y);  
1346    
1347  // top right neighbour, if allowed  static void
1348                  if (!MVzero(pmv[3]))  SearchP(const IMAGE * const pRef,
1349                  if (!MVequal(pmv[3],prevMB->mvs[0]))                  const uint8_t * const pRefH,
1350                  if (!MVequal(pmv[3],pmv[0]))                  const uint8_t * const pRefV,
1351                  if (!MVequal(pmv[3],pmv[1]))                  const uint8_t * const pRefHV,
1352                  if (!MVequal(pmv[3],pmv[2]))                  const IMAGE * const pCur,
1353                    const int x,
1354                    const int y,
1355                    const uint32_t MotionFlags,
1356                    const uint32_t VopFlags,
1357                    const uint32_t VolFlags,
1358                    SearchData * const Data,
1359                    const MBParam * const pParam,
1360                    const MACROBLOCK * const pMBs,
1361                    const MACROBLOCK * const prevMBs,
1362                    MACROBLOCK * const pMB)
1363                  {                  {
                         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);  
                 }  
         }  
1364    
1365          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96)*/ )          int i, iDirection = 255, mask, threshA;
1366                  iMinSAD -= MV16_00_BIAS;          VECTOR pmv[7];
1367            int inter4v = (VopFlags & XVID_VOP_INTER4V) && (pMB->dquant == 0);
1368    
1369            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1370                                                    pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
1371    
1372  /* 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.  
 */  
1373    
1374          if ( (iMinSAD <= threshA) || ( MVequal(*currMV,prevMB->mvs[0]) && ((uint32_t)iMinSAD < prevMB->sad16) ) )          Data->temp[5] = Data->temp[6] = 0; /* chroma-sad cache */
1375          {          i = Data->rrv ? 2 : 1;
1376                  if (MotionFlags & PMV_QUICKSTOP16)          Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16*i;
1377                          goto PMVfast16_Terminate_without_Refine;          Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1378                  if (MotionFlags & PMV_EARLYSTOP16)          Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
                         goto PMVfast16_Terminate_with_Refine;  
         }  
1379    
1380            Data->RefP[0] = pRef->y + (x + Data->iEdgedWidth*y) * 16*i;
1381            Data->RefP[2] = pRefH + (x + Data->iEdgedWidth*y) * 16*i;
1382            Data->RefP[1] = pRefV + (x + Data->iEdgedWidth*y) * 16*i;
1383            Data->RefP[3] = pRefHV + (x + Data->iEdgedWidth*y) * 16*i;
1384            Data->RefP[4] = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1385            Data->RefP[5] = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1386    
1387  /************ (Diamond Search)  **************/          Data->lambda16 = lambda_vec16[pMB->quant];
1388  /*          Data->lambda8 = lambda_vec8[pMB->quant];
1389     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.  
 */  
1390    
1391          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;  
1392    
1393          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */          if (Data->qpel) Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1394            else Data->predMV = pmv[0];
1395    
1396  /* 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);
1397          iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,          Data->iMinSAD[0] = pMB->sad16 + ((Data->lambda16 * i * pMB->sad16)>>10);
1398                                            x, y,          Data->iMinSAD[1] = pMB->sad8[0] + ((Data->lambda8 * i * (pMB->sad8[0]+NEIGH_8X8_BIAS)) >> 10);
1399                                            currMV->x, currMV->y, iMinSAD, &newMV,          Data->iMinSAD[2] = pMB->sad8[1];
1400                                            pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);          Data->iMinSAD[3] = pMB->sad8[2];
1401            Data->iMinSAD[4] = pMB->sad8[3];
1402    
1403          if (iSAD < iMinSAD)          if ((!(VopFlags & XVID_VOP_MODEDECISION_RD)) && (x | y)) {
1404          {                  threshA = Data->temp[0]; /* that's where we keep this SAD atm */
1405                  *currMV = newMV;                  if (threshA < 512) threshA = 512;
1406                  iMinSAD = iSAD;                  else if (threshA > 1024) threshA = 1024;
1407            } else
1408                    threshA = 512;
1409    
1410            PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
1411                                            prevMBs + x + y * pParam->mb_width, Data->rrv);
1412    
1413            if (!Data->rrv) {
1414                    if (inter4v | Data->chroma) CheckCandidate = CheckCandidate16;
1415                            else CheckCandidate = CheckCandidate16no4v; /* for extra speed */
1416            } else CheckCandidate = CheckCandidate32;
1417    
1418    /* main loop. checking all predictions (but first, which is 0,0 and has been checked in MotionEstimation())*/
1419    
1420            for (i = 1; i < 7; i++) {
1421                    if (!(mask = make_mask(pmv, i)) ) continue;
1422                    CheckCandidate(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1423                    if (Data->iMinSAD[0] <= threshA) break;
1424          }          }
1425    
1426          if (MotionFlags & PMV_EXTSEARCH16)          if ((Data->iMinSAD[0] <= threshA) ||
1427          {                          (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
1428  /* extended: search (up to) two more times: orignal prediction and (0,0) */                          (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16)))
1429                    inter4v = 0;
1430            else {
1431    
1432                  if (!(MVequal(pmv[0],backupMV)) )                  MainSearchFunc * MainSearchPtr;
1433                  {       iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,                  if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1434                                                            x, y,                  else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1435                                                            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);  
1436    
1437                  if (iSAD < iMinSAD)                  MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
1438                  {  
1439                          *currMV = newMV;  /* extended search, diamond starting in 0,0 and in prediction.
1440                          iMinSAD = iSAD;          note that this search is/might be done in halfpel positions,
1441            which makes it more different than the diamond above */
1442    
1443                    if (MotionFlags & XVID_ME_EXTSEARCH16) {
1444                            int32_t bSAD;
1445                            VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
1446                            if (Data->rrv) {
1447                                    startMV.x = RRV_MV_SCALEUP(startMV.x);
1448                                    startMV.y = RRV_MV_SCALEUP(startMV.y);
1449                  }                  }
1450                            if (!(MVequal(startMV, backupMV))) {
1451                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1452    
1453                                    CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1454                                    MainSearchPtr(startMV.x, startMV.y, Data, 255);
1455                                    if (bSAD < Data->iMinSAD[0]) {
1456                                            Data->currentMV[0] = backupMV;
1457                                            Data->iMinSAD[0] = bSAD; }
1458                  }                  }
1459    
1460                  if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )                          backupMV = Data->currentMV[0];
1461                  {       iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,                          startMV.x = startMV.y = 1;
1462                                                            x, y,                          if (!(MVequal(startMV, backupMV))) {
1463                                                            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);  
1464    
1465                  if (iSAD < iMinSAD)                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1466                  {                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1467                          *currMV = newMV;                                  if (bSAD < Data->iMinSAD[0]) {
1468                          iMinSAD = iSAD;                                          Data->currentMV[0] = backupMV;
1469                                            Data->iMinSAD[0] = bSAD; }
1470                  }                  }
1471                  }                  }
1472          }          }
1473    
1474  /*          if (MotionFlags & XVID_ME_HALFPELREFINE16)
1475     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);  
1476    
1477  PMVfast16_Terminate_without_Refine:          for(i = 0; i < 5; i++) {
1478          currPMV->x = currMV->x - pmv[0].x;                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; /* initialize qpel vectors */
1479          currPMV->y = currMV->y - pmv[0].y;                  Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
         return iMinSAD;  
1480  }  }
1481    
1482            if (Data->qpel) {
1483                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1484                                    pParam->width, pParam->height, Data->iFcode, 1, 0);
1485                    Data->qpel_precision = 1;
1486                    if (MotionFlags & XVID_ME_QUARTERPELREFINE16)
1487                            SubpelRefine(Data);
1488            }
1489    
1490            if (Data->iMinSAD[0] < (int32_t)pMB->quant * 30)
1491                    inter4v = 0;
1492    
1493            if (inter4v) {
1494                    SearchData Data8;
1495                    memcpy(&Data8, Data, sizeof(SearchData)); /* quick copy of common data */
1496    
1497                    Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
1498                    Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
1499                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
1500                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
1501    
1502                    if ((Data->chroma) && (!(VopFlags & XVID_VOP_MODEDECISION_RD))) {
1503                            /* chroma is only used for comparsion to INTER. if the comparsion will be done in BITS domain, it will not be used */
1504                            int sumx = 0, sumy = 0;
1505    
1506  int32_t Diamond8_MainSearch(                          if (Data->qpel)
1507          const uint8_t * const pRef,                                  for (i = 1; i < 5; i++) {
1508          const uint8_t * const pRefH,                                          sumx += Data->currentQMV[i].x/2;
1509          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);  
1510                  }                  }
1511          else          else
1512          {                                  for (i = 1; i < 5; i++) {
1513                  currMV->x = startx;                                          sumx += Data->currentMV[i].x;
1514                  currMV->y = starty;                                          sumy += Data->currentMV[i].y;
1515          }          }
1516          return iMinSAD;  
1517                            Data->iMinSAD[1] += ChromaSAD(  (sumx >> 3) + roundtab_76[sumx & 0xf],
1518                                                                                            (sumy >> 3) + roundtab_76[sumy & 0xf], Data);
1519                    }
1520            } else Data->iMinSAD[1] = 4096*256;
1521  }  }
1522    
1523  int32_t Halfpel8_Refine(  static void
1524          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,  
1525          const int x, const int y,          const int x, const int y,
1526          VECTOR * const currMV,                  const uint32_t MotionFlags,
1527          int32_t iMinSAD,                  const MBParam * const pParam,
1528          const VECTOR * const pmv,                  MACROBLOCK * const pMB,
1529          const int32_t min_dx, const int32_t max_dx,                  const MACROBLOCK * const pMBs,
1530          const int32_t min_dy, const int32_t max_dy,                  const int block,
1531          const int32_t iFcode,                  SearchData * const Data)
         const int32_t iQuant,  
         const int32_t iEdgedWidth)  
1532  {  {
1533  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */          int i = 0;
1534            Data->iMinSAD = OldData->iMinSAD + 1 + block;
1535          int32_t iSAD;          Data->currentMV = OldData->currentMV + 1 + block;
1536          VECTOR backupMV = *currMV;          Data->currentQMV = OldData->currentQMV + 1 + block;
1537    
1538          CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y-1);          if(Data->qpel) {
1539          CHECK_MV8_CANDIDATE(backupMV.x  ,backupMV.y-1);                  Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1540          CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y-1);                  if (block != 0) i = d_mv_bits(  Data->currentQMV->x, Data->currentQMV->y,
1541          CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y);                                                                                  Data->predMV, Data->iFcode, 0, 0);
1542          CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y);          } else {
1543          CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y+1);                  Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1544          CHECK_MV8_CANDIDATE(backupMV.x  ,backupMV.y+1);                  if (block != 0) i = d_mv_bits(  Data->currentMV->x, Data->currentMV->y,
1545          CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y+1);                                                                                  Data->predMV, Data->iFcode, 0, Data->rrv);
   
         return iMinSAD;  
1546  }  }
1547    
1548            *(Data->iMinSAD) += (Data->lambda8 * i * (*Data->iMinSAD + NEIGH_8X8_BIAS))>>10;
1549    
1550  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)          if (MotionFlags & (XVID_ME_EXTSEARCH8|XVID_ME_HALFPELREFINE8|XVID_ME_QUARTERPELREFINE8)) {
1551    
1552  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;  
1553    
1554          const uint8_t * cur = pCur->y + x*8 + y*8*iEdgedWidth;                  Data->RefP[0] = OldData->RefP[0] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1555                    Data->RefP[1] = OldData->RefP[1] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1556                    Data->RefP[2] = OldData->RefP[2] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1557                    Data->RefP[3] = OldData->RefP[3] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1558    
1559          int32_t iDiamondSize;                  Data->Cur = OldData->Cur + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1560                    Data->qpel_precision = 0;
1561    
1562          int32_t min_dx;                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1563          int32_t max_dx;                                          pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
         int32_t min_dy;  
         int32_t max_dy;  
1564    
1565          VECTOR pmv[4];                  if (!Data->rrv) CheckCandidate = CheckCandidate8;
1566          int32_t psad[4];                  else CheckCandidate = CheckCandidate16no4v;
         VECTOR newMV;  
         VECTOR backupMV;  
         VECTOR startMV;  
1567    
1568  //      const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;                  if (MotionFlags & XVID_ME_EXTSEARCH8 && (!(MotionFlags & XVID_ME_EXTSEARCH_RD))) {
1569          const MACROBLOCK * const prevMB = prevMBs + (x>>1) + (y>>1) * iWcount;                          int32_t temp_sad = *(Data->iMinSAD); /* store current MinSAD */
1570    
1571          static int32_t threshA,threshB;                          MainSearchFunc *MainSearchPtr;
1572          int32_t iFound,bPredEq;                          if (MotionFlags & XVID_ME_USESQUARES8) MainSearchPtr = SquareSearch;
1573          int32_t iMinSAD,iSAD;                                  else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1574                                            else MainSearchPtr = DiamondSearch;
1575    
1576          int32_t iSubBlock = (y&1)+(y&1) + (x&1);                          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, 255);
1577    
1578          MainSearch8FuncPtr MainSearchPtr;                          if(*(Data->iMinSAD) < temp_sad) {
1579                                            Data->currentQMV->x = 2 * Data->currentMV->x; /* update our qpel vector */
1580                                            Data->currentQMV->y = 2 * Data->currentMV->y;
1581                            }
1582                    }
1583    
1584          /* Init variables */                  if (MotionFlags & XVID_ME_HALFPELREFINE8) {
1585          startMV.x = start_x;                          int32_t temp_sad = *(Data->iMinSAD); /* store current MinSAD */
         startMV.y = start_y;  
1586    
1587          /* 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);  
1588    
1589          if (!(MotionFlags & PMV_HALFPELDIAMOND8 ))                          if(*(Data->iMinSAD) < temp_sad) { /* we have found a better match */
1590          { min_dx = EVEN(min_dx);                                  Data->currentQMV->x = 2 * Data->currentMV->x; /* update our qpel vector */
1591            max_dx = EVEN(max_dx);                                  Data->currentQMV->y = 2 * Data->currentMV->y;
1592            min_dy = EVEN(min_dy);                          }
1593            max_dy = EVEN(max_dy);                  }
         }               /* because we might use IF (dx>max_dx) THEN dx=max_dx; */  
1594    
1595                    if (Data->qpel && MotionFlags & XVID_ME_QUARTERPELREFINE8) {
1596                                    Data->qpel_precision = 1;
1597                                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1598                                            pParam->width, pParam->height, Data->iFcode, 1, 0);
1599                                    SubpelRefine(Data);
1600                    }
1601            }
1602    
1603          bPredEq  = get_pmvdata(pMBs, (x>>1), (y>>1), iWcount, iSubBlock, pmv, psad);          if (Data->rrv) {
1604                            Data->currentMV->x = RRV_MV_SCALEDOWN(Data->currentMV->x);
1605                            Data->currentMV->y = RRV_MV_SCALEDOWN(Data->currentMV->y);
1606            }
1607    
1608          if ((x==0) && (y==0) )          if(Data->qpel) {
1609          {                  pMB->pmvs[block].x = Data->currentQMV->x - Data->predMV.x;
1610                  threshA =  512/4;                  pMB->pmvs[block].y = Data->currentQMV->y - Data->predMV.y;
1611                  threshB = 1024/4;                  pMB->qmvs[block] = *Data->currentQMV;
1612            } else {
1613                    pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1614                    pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
1615            }
1616    
1617            pMB->mvs[block] = *Data->currentMV;
1618            pMB->sad8[block] = 4 * *Data->iMinSAD;
1619          }          }
1620          else  
1621    /* motion estimation for B-frames */
1622    
1623    static __inline VECTOR
1624    ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1625          {          {
1626                  threshA = psad[0]/4;                    /* good estimate */  /* the stupidiest function ever */
1627                  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;  
1628          }          }
1629    
1630          iFound=0;  static void __inline
1631    PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
1632  /* Step 4: Calculate SAD around the Median prediction.                                                          const uint32_t iWcount,
1633     MinSAD=SAD                                                          const MACROBLOCK * const pMB,
1634     If Motion Vector equal to Previous frame motion vector                                                          const uint32_t mode_curr)
1635     and MinSAD<PrevFrmSAD goto Step 10.  {
    If SAD<=256 goto Step 10.  
 */  
1636    
1637            /* [0] is prediction */
1638            pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
1639    
1640  // Prepare for main loop          pmv[1].x = pmv[1].y = 0; /* [1] is zero */
1641    
1642  //      if (MotionFlags & PMV_USESQUARES8)          pmv[2] = ChoosePred(pMB, mode_curr);
1643  //              MainSearchPtr = Square8_MainSearch;          pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
 //      else  
1644    
1645          if (MotionFlags & PMV_ADVANCEDDIAMOND8)          if ((y != 0)&&(x != (int)(iWcount+1))) {                        /* [3] top-right neighbour */
1646                  MainSearchPtr = AdvDiamond8_MainSearch;                  pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
1647          else                  pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
1648                  MainSearchPtr = Diamond8_MainSearch;          } else pmv[3].x = pmv[3].y = 0;
1649    
1650            if (y != 0) {
1651                    pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
1652                    pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
1653            } else pmv[4].x = pmv[4].y = 0;
1654    
1655            if (x != 0) {
1656                    pmv[5] = ChoosePred(pMB-1, mode_curr);
1657                    pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1658            } else pmv[5].x = pmv[5].y = 0;
1659    
1660          *currMV = startMV;          if (x != 0 && y != 0) {
1661                    pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
1662                    pmv[6].x = EVEN(pmv[6].x); pmv[6].y = EVEN(pmv[6].y);
1663            } else pmv[6].x = pmv[6].y = 0;
1664    }
1665    
         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);  
1666    
1667          if ( (iMinSAD < 256/4 ) || ( (MVequal(*currMV,prevMB->mvs[iSubBlock]))  /* search backward or forward */
1668                                  && ((uint32_t)iMinSAD < prevMB->sad8[iSubBlock]) ) )  static void
1669    SearchBF(       const IMAGE * const pRef,
1670                            const uint8_t * const pRefH,
1671                            const uint8_t * const pRefV,
1672                            const uint8_t * const pRefHV,
1673                            const IMAGE * const pCur,
1674                            const int x, const int y,
1675                            const uint32_t MotionFlags,
1676                            const uint32_t iFcode,
1677                            const MBParam * const pParam,
1678                            MACROBLOCK * const pMB,
1679                            const VECTOR * const predMV,
1680                            int32_t * const best_sad,
1681                            const int32_t mode_current,
1682                            SearchData * const Data)
1683          {          {
1684                  if (MotionFlags & PMV_QUICKSTOP16)  
1685                          goto PMVfast8_Terminate_without_Refine;          int i, iDirection = 255, mask;
1686                  if (MotionFlags & PMV_EARLYSTOP16)          VECTOR pmv[7];
1687                          goto PMVfast8_Terminate_with_Refine;          MainSearchFunc *MainSearchPtr;
1688            *Data->iMinSAD = MV_MAX_ERROR;
1689            Data->iFcode = iFcode;
1690            Data->qpel_precision = 0;
1691            Data->temp[5] = Data->temp[6] = Data->temp[7] = 256*4096; /* reset chroma-sad cache */
1692    
1693            Data->RefP[0] = pRef->y + (x + Data->iEdgedWidth*y) * 16;
1694            Data->RefP[2] = pRefH + (x + Data->iEdgedWidth*y) * 16;
1695            Data->RefP[1] = pRefV + (x + Data->iEdgedWidth*y) * 16;
1696            Data->RefP[3] = pRefHV + (x + Data->iEdgedWidth*y) * 16;
1697            Data->RefP[4] = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8;
1698            Data->RefP[5] = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8;
1699    
1700            Data->predMV = *predMV;
1701    
1702            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1703                                    pParam->width, pParam->height, iFcode - Data->qpel, 0, 0);
1704    
1705            pmv[0] = Data->predMV;
1706            if (Data->qpel) { pmv[0].x /= 2; pmv[0].y /= 2; }
1707    
1708            PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);
1709    
1710            Data->currentMV->x = Data->currentMV->y = 0;
1711            CheckCandidate = CheckCandidate16no4v;
1712    
1713            /* main loop. checking all predictions */
1714            for (i = 0; i < 7; i++) {
1715                    if (!(mask = make_mask(pmv, i)) ) continue;
1716                    CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1717          }          }
1718    
1719  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion          if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1720     vector of the median.          else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1721     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2                  else MainSearchPtr = DiamondSearch;
 */  
1722    
1723          if ((bPredEq) && (MVequal(pmv[0],prevMB->mvs[iSubBlock]) ) )          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
                 iFound=2;  
1724    
1725  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          SubpelRefine(Data);
    Otherwise select large Diamond Search.  
 */  
1726    
1727          if ( (!MVzero(pmv[0])) || (threshB<1536/4) || (bPredEq) )          if (Data->qpel && *Data->iMinSAD < *best_sad + 300) {
1728                  iDiamondSize=1; // 1 halfpel!                  Data->currentQMV->x = 2*Data->currentMV->x;
1729          else                  Data->currentQMV->y = 2*Data->currentMV->y;
1730                  iDiamondSize=2; // 2 halfpel = 1 full pixel!                  Data->qpel_precision = 1;
1731                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1732                                            pParam->width, pParam->height, iFcode, 1, 0);
1733                    SubpelRefine(Data);
1734            }
1735    
1736            /* three bits are needed to code backward mode. four for forward */
1737    
1738          if (!(MotionFlags & PMV_HALFPELDIAMOND8) )          if (mode_current == MODE_FORWARD) *Data->iMinSAD += 4 * Data->lambda16;
1739                  iDiamondSize*=2;          else *Data->iMinSAD += 3 * Data->lambda16;
1740    
1741            if (*Data->iMinSAD < *best_sad) {
1742                    *best_sad = *Data->iMinSAD;
1743                    pMB->mode = mode_current;
1744                    if (Data->qpel) {
1745                            pMB->pmvs[0].x = Data->currentQMV->x - predMV->x;
1746                            pMB->pmvs[0].y = Data->currentQMV->y - predMV->y;
1747                            if (mode_current == MODE_FORWARD)
1748                                    pMB->qmvs[0] = *Data->currentQMV;
1749                            else
1750                                    pMB->b_qmvs[0] = *Data->currentQMV;
1751                    } else {
1752                            pMB->pmvs[0].x = Data->currentMV->x - predMV->x;
1753                            pMB->pmvs[0].y = Data->currentMV->y - predMV->y;
1754                    }
1755                    if (mode_current == MODE_FORWARD) pMB->mvs[0] = *Data->currentMV;
1756                    else pMB->b_mvs[0] = *Data->currentMV;
1757            }
1758    
1759            if (mode_current == MODE_FORWARD) *(Data->currentMV+2) = *Data->currentMV;
1760            else *(Data->currentMV+1) = *Data->currentMV; /* we store currmv for interpolate search */
1761    }
1762    
1763    static void
1764    SkipDecisionB(const IMAGE * const pCur,
1765                                    const IMAGE * const f_Ref,
1766                                    const IMAGE * const b_Ref,
1767                                    MACROBLOCK * const pMB,
1768                                    const uint32_t x, const uint32_t y,
1769                                    const SearchData * const Data)
1770    {
1771            int dx = 0, dy = 0, b_dx = 0, b_dy = 0;
1772            int32_t sum;
1773            const int div = 1 + Data->qpel;
1774            int k;
1775            const uint32_t stride = Data->iEdgedWidth/2;
1776            /* this is not full chroma compensation, only it's fullpel approximation. should work though */
1777    
1778            for (k = 0; k < 4; k++) {
1779                    dy += Data->directmvF[k].y / div;
1780                    dx += Data->directmvF[k].x / div;
1781                    b_dy += Data->directmvB[k].y / div;
1782                    b_dx += Data->directmvB[k].x / div;
1783            }
1784    
1785            dy = (dy >> 3) + roundtab_76[dy & 0xf];
1786            dx = (dx >> 3) + roundtab_76[dx & 0xf];
1787            b_dy = (b_dy >> 3) + roundtab_76[b_dy & 0xf];
1788            b_dx = (b_dx >> 3) + roundtab_76[b_dx & 0xf];
1789    
1790            sum = sad8bi(pCur->u + 8 * x + 8 * y * stride,
1791                                            f_Ref->u + (y*8 + dy/2) * stride + x*8 + dx/2,
1792                                            b_Ref->u + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1793                                            stride);
1794    
1795            if (sum >= 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) return; /* no skip */
1796    
1797            sum += sad8bi(pCur->v + 8*x + 8 * y * stride,
1798                                            f_Ref->v + (y*8 + dy/2) * stride + x*8 + dx/2,
1799                                            b_Ref->v + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1800                                            stride);
1801    
1802            if (sum < 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) {
1803                    pMB->mode = MODE_DIRECT_NONE_MV; /* skipped */
1804                    for (k = 0; k < 4; k++) {
1805                            pMB->qmvs[k] = pMB->mvs[k];
1806                            pMB->b_qmvs[k] = pMB->b_mvs[k];
1807                    }
1808            }
1809    }
1810    
1811    static __inline uint32_t
1812    SearchDirect(const IMAGE * const f_Ref,
1813                                    const uint8_t * const f_RefH,
1814                                    const uint8_t * const f_RefV,
1815                                    const uint8_t * const f_RefHV,
1816                                    const IMAGE * const b_Ref,
1817                                    const uint8_t * const b_RefH,
1818                                    const uint8_t * const b_RefV,
1819                                    const uint8_t * const b_RefHV,
1820                                    const IMAGE * const pCur,
1821                                    const int x, const int y,
1822                                    const uint32_t MotionFlags,
1823                                    const int32_t TRB, const int32_t TRD,
1824                                    const MBParam * const pParam,
1825                                    MACROBLOCK * const pMB,
1826                                    const MACROBLOCK * const b_mb,
1827                                    int32_t * const best_sad,
1828                                    SearchData * const Data)
1829    
1830    {
1831            int32_t skip_sad;
1832            int k = (x + Data->iEdgedWidth*y) * 16;
1833            MainSearchFunc *MainSearchPtr;
1834    
1835            *Data->iMinSAD = 256*4096;
1836            Data->RefP[0] = f_Ref->y + k;
1837            Data->RefP[2] = f_RefH + k;
1838            Data->RefP[1] = f_RefV + k;
1839            Data->RefP[3] = f_RefHV + k;
1840            Data->b_RefP[0] = b_Ref->y + k;
1841            Data->b_RefP[2] = b_RefH + k;
1842            Data->b_RefP[1] = b_RefV + k;
1843            Data->b_RefP[3] = b_RefHV + k;
1844            Data->RefP[4] = f_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1845            Data->RefP[5] = f_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1846            Data->b_RefP[4] = b_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1847            Data->b_RefP[5] = b_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1848    
1849            k = Data->qpel ? 4 : 2;
1850            Data->max_dx = k * (pParam->width - x * 16);
1851            Data->max_dy = k * (pParam->height - y * 16);
1852            Data->min_dx = -k * (16 + x * 16);
1853            Data->min_dy = -k * (16 + y * 16);
1854    
1855            Data->referencemv = Data->qpel ? b_mb->qmvs : b_mb->mvs;
1856            Data->qpel_precision = 0;
1857    
1858            for (k = 0; k < 4; k++) {
1859                    pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);
1860                    pMB->b_mvs[k].x = Data->directmvB[k].x = ((TRB - TRD) * Data->referencemv[k].x) / TRD;
1861                    pMB->mvs[k].y = Data->directmvF[k].y = ((TRB * Data->referencemv[k].y) / TRD);
1862                    pMB->b_mvs[k].y = Data->directmvB[k].y = ((TRB - TRD) * Data->referencemv[k].y) / TRD;
1863    
1864                    if ( (pMB->b_mvs[k].x > Data->max_dx) | (pMB->b_mvs[k].x < Data->min_dx)
1865                            | (pMB->b_mvs[k].y > Data->max_dy) | (pMB->b_mvs[k].y < Data->min_dy) ) {
1866    
1867                            *best_sad = 256*4096; /* in that case, we won't use direct mode */
1868                            pMB->mode = MODE_DIRECT; /* just to make sure it doesn't say "MODE_DIRECT_NONE_MV" */
1869                            pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;
1870                            return 256*4096;
1871                    }
1872                    if (b_mb->mode != MODE_INTER4V) {
1873                            pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mvs[0];
1874                            pMB->b_mvs[1] = pMB->b_mvs[2] = pMB->b_mvs[3] = pMB->b_mvs[0];
1875                            Data->directmvF[1] = Data->directmvF[2] = Data->directmvF[3] = Data->directmvF[0];
1876                            Data->directmvB[1] = Data->directmvB[2] = Data->directmvB[3] = Data->directmvB[0];
1877                            break;
1878                    }
1879            }
1880    
1881            CheckCandidate = b_mb->mode == MODE_INTER4V ? CheckCandidateDirect : CheckCandidateDirectno4v;
1882    
1883            CheckCandidate(0, 0, 255, &k, Data);
1884    
1885            /* initial (fast) skip decision */
1886            if (*Data->iMinSAD < pMB->quant * INITIAL_SKIP_THRESH * (Data->chroma?3:2)) {
1887                    /* possible skip */
1888                    if (Data->chroma) {
1889                            pMB->mode = MODE_DIRECT_NONE_MV;
1890                            return *Data->iMinSAD; /* skip. */
1891                    } else {
1892                            SkipDecisionB(pCur, f_Ref, b_Ref, pMB, x, y, Data);
1893                            if (pMB->mode == MODE_DIRECT_NONE_MV) return *Data->iMinSAD; /* skip. */
1894                    }
1895            }
1896    
1897            *Data->iMinSAD += Data->lambda16;
1898            skip_sad = *Data->iMinSAD;
1899    
1900  /*  /*
1901     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.           * DIRECT MODE DELTA VECTOR SEARCH.
1902     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.  
1903  */  */
1904    
1905  // the median prediction might be even better than mv16          if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1906                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1907                            else MainSearchPtr = DiamondSearch;
1908    
1909          if (!MVequal(pmv[0],startMV))          MainSearchPtr(0, 0, Data, 255);
                 CHECK_MV8_CANDIDATE(pmv[0].x,pmv[0].y);  
1910    
1911  // (0,0) if needed          SubpelRefine(Data);
         if (!MVzero(pmv[0]))  
         if (!MVzero(startMV))  
         CHECK_MV8_ZERO;  
1912    
1913  // 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);  
1914    
1915          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;
1916          {          else pMB->mode = MODE_DIRECT_NO4V; /* for faster compensation */
1917                  if (MotionFlags & PMV_QUICKSTOP16)  
1918                          goto PMVfast8_Terminate_without_Refine;          pMB->pmvs[3] = *Data->currentMV;
1919                  if (MotionFlags & PMV_EARLYSTOP16)  
1920                          goto PMVfast8_Terminate_with_Refine;          for (k = 0; k < 4; k++) {
1921                    pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
1922                    pMB->b_mvs[k].x = (     (Data->currentMV->x == 0)
1923                                                            ? Data->directmvB[k].x
1924                                                            :pMB->mvs[k].x - Data->referencemv[k].x);
1925                    pMB->mvs[k].y = (Data->directmvF[k].y + Data->currentMV->y);
1926                    pMB->b_mvs[k].y = ((Data->currentMV->y == 0)
1927                                                            ? Data->directmvB[k].y
1928                                                            : pMB->mvs[k].y - Data->referencemv[k].y);
1929                    if (Data->qpel) {
1930                            pMB->qmvs[k].x = pMB->mvs[k].x; pMB->mvs[k].x /= 2;
1931                            pMB->b_qmvs[k].x = pMB->b_mvs[k].x; pMB->b_mvs[k].x /= 2;
1932                            pMB->qmvs[k].y = pMB->mvs[k].y; pMB->mvs[k].y /= 2;
1933                            pMB->b_qmvs[k].y = pMB->b_mvs[k].y; pMB->b_mvs[k].y /= 2;
1934          }          }
1935    
1936                    if (b_mb->mode != MODE_INTER4V) {
1937                            pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1938                            pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1939                            pMB->qmvs[3] = pMB->qmvs[2] = pMB->qmvs[1] = pMB->qmvs[0];
1940                            pMB->b_qmvs[3] = pMB->b_qmvs[2] = pMB->b_qmvs[1] = pMB->b_qmvs[0];
1941                            break;
1942                    }
1943            }
1944            return skip_sad;
1945    }
1946    
1947  // left neighbour, if allowed and needed  static void
1948          if (!MVzero(pmv[1]))  SearchInterpolate(const IMAGE * const f_Ref,
1949          if (!MVequal(pmv[1],startMV))                                  const uint8_t * const f_RefH,
1950          if (!MVequal(pmv[1],prevMB->mvs[iSubBlock]))                                  const uint8_t * const f_RefV,
1951          if (!MVequal(pmv[1],pmv[0]))                                  const uint8_t * const f_RefHV,
1952          {                                  const IMAGE * const b_Ref,
1953                  if (!(MotionFlags & PMV_HALFPEL8 ))                                  const uint8_t * const b_RefH,
1954                  {       pmv[1].x = EVEN(pmv[1].x);                                  const uint8_t * const b_RefV,
1955                          pmv[1].y = EVEN(pmv[1].y);                                  const uint8_t * const b_RefHV,
1956                                    const IMAGE * const pCur,
1957                                    const int x, const int y,
1958                                    const uint32_t fcode,
1959                                    const uint32_t bcode,
1960                                    const uint32_t MotionFlags,
1961                                    const MBParam * const pParam,
1962                                    const VECTOR * const f_predMV,
1963                                    const VECTOR * const b_predMV,
1964                                    MACROBLOCK * const pMB,
1965                                    int32_t * const best_sad,
1966                                    SearchData * const fData)
1967    
1968    {
1969    
1970            int iDirection, i, j;
1971            SearchData bData;
1972    
1973            fData->qpel_precision = 0;
1974            memcpy(&bData, fData, sizeof(SearchData)); /* quick copy of common data */
1975            *fData->iMinSAD = 4096*256;
1976            bData.currentMV++; bData.currentQMV++;
1977            fData->iFcode = bData.bFcode = fcode; fData->bFcode = bData.iFcode = bcode;
1978    
1979            i = (x + y * fData->iEdgedWidth) * 16;
1980    
1981            bData.b_RefP[0] = fData->RefP[0] = f_Ref->y + i;
1982            bData.b_RefP[2] = fData->RefP[2] = f_RefH + i;
1983            bData.b_RefP[1] = fData->RefP[1] = f_RefV + i;
1984            bData.b_RefP[3] = fData->RefP[3] = f_RefHV + i;
1985            bData.RefP[0] = fData->b_RefP[0] = b_Ref->y + i;
1986            bData.RefP[2] = fData->b_RefP[2] = b_RefH + i;
1987            bData.RefP[1] = fData->b_RefP[1] = b_RefV + i;
1988            bData.RefP[3] = fData->b_RefP[3] = b_RefHV + i;
1989            bData.b_RefP[4] = fData->RefP[4] = f_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
1990            bData.b_RefP[5] = fData->RefP[5] = f_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
1991            bData.RefP[4] = fData->b_RefP[4] = b_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
1992            bData.RefP[5] = fData->b_RefP[5] = b_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
1993    
1994            bData.bpredMV = fData->predMV = *f_predMV;
1995            fData->bpredMV = bData.predMV = *b_predMV;
1996            fData->currentMV[0] = fData->currentMV[2];
1997    
1998            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);
1999            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);
2000    
2001            if (fData->currentMV[0].x > fData->max_dx) fData->currentMV[0].x = fData->max_dx;
2002            if (fData->currentMV[0].x < fData->min_dx) fData->currentMV[0].x = fData->min_dx;
2003            if (fData->currentMV[0].y > fData->max_dy) fData->currentMV[0].y = fData->max_dy;
2004            if (fData->currentMV[0].y < fData->min_dy) fData->currentMV[0].y = fData->min_dy;
2005    
2006            if (fData->currentMV[1].x > bData.max_dx) fData->currentMV[1].x = bData.max_dx;
2007            if (fData->currentMV[1].x < bData.min_dx) fData->currentMV[1].x = bData.min_dx;
2008            if (fData->currentMV[1].y > bData.max_dy) fData->currentMV[1].y = bData.max_dy;
2009            if (fData->currentMV[1].y < bData.min_dy) fData->currentMV[1].y = bData.min_dy;
2010    
2011            CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, 255, &iDirection, fData);
2012    
2013            /* diamond */
2014            do {
2015                    iDirection = 255;
2016                    /* forward MV moves */
2017                    i = fData->currentMV[0].x; j = fData->currentMV[0].y;
2018    
2019                    CheckCandidateInt(i + 1, j, 0, &iDirection, fData);
2020                    CheckCandidateInt(i, j + 1, 0, &iDirection, fData);
2021                    CheckCandidateInt(i - 1, j, 0, &iDirection, fData);
2022                    CheckCandidateInt(i, j - 1, 0, &iDirection, fData);
2023    
2024                    /* backward MV moves */
2025                    i = fData->currentMV[1].x; j = fData->currentMV[1].y;
2026                    fData->currentMV[2] = fData->currentMV[0];
2027                    CheckCandidateInt(i + 1, j, 0, &iDirection, &bData);
2028                    CheckCandidateInt(i, j + 1, 0, &iDirection, &bData);
2029                    CheckCandidateInt(i - 1, j, 0, &iDirection, &bData);
2030                    CheckCandidateInt(i, j - 1, 0, &iDirection, &bData);
2031    
2032            } while (!(iDirection));
2033    
2034            /* qpel refinement */
2035            if (fData->qpel) {
2036                    if (*fData->iMinSAD > *best_sad + 500) return;
2037                    CheckCandidate = CheckCandidateInt;
2038                    fData->qpel_precision = bData.qpel_precision = 1;
2039                    get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode, 1, 0);
2040                    get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode, 1, 0);
2041                    fData->currentQMV[2].x = fData->currentQMV[0].x = 2 * fData->currentMV[0].x;
2042                    fData->currentQMV[2].y = fData->currentQMV[0].y = 2 * fData->currentMV[0].y;
2043                    fData->currentQMV[1].x = 2 * fData->currentMV[1].x;
2044                    fData->currentQMV[1].y = 2 * fData->currentMV[1].y;
2045                    SubpelRefine(fData);
2046                    if (*fData->iMinSAD > *best_sad + 300) return;
2047                    fData->currentQMV[2] = fData->currentQMV[0];
2048                    SubpelRefine(&bData);
2049            }
2050    
2051            *fData->iMinSAD += (2+3) * fData->lambda16; /* two bits are needed to code interpolate mode. */
2052    
2053            if (*fData->iMinSAD < *best_sad) {
2054                    *best_sad = *fData->iMinSAD;
2055                    pMB->mvs[0] = fData->currentMV[0];
2056                    pMB->b_mvs[0] = fData->currentMV[1];
2057                    pMB->mode = MODE_INTERPOLATE;
2058                    if (fData->qpel) {
2059                            pMB->qmvs[0] = fData->currentQMV[0];
2060                            pMB->b_qmvs[0] = fData->currentQMV[1];
2061                            pMB->pmvs[1].x = pMB->qmvs[0].x - f_predMV->x;
2062                            pMB->pmvs[1].y = pMB->qmvs[0].y - f_predMV->y;
2063                            pMB->pmvs[0].x = pMB->b_qmvs[0].x - b_predMV->x;
2064                            pMB->pmvs[0].y = pMB->b_qmvs[0].y - b_predMV->y;
2065                    } else {
2066                            pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;
2067                            pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;
2068                            pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;
2069                            pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;
2070                    }
2071                  }                  }
                 CHECK_MV8_CANDIDATE(pmv[1].x,pmv[1].y);  
2072          }          }
2073    
2074  // top neighbour, if allowed and needed  void
2075          if (!MVzero(pmv[2]))  MotionEstimationBVOP(MBParam * const pParam,
2076          if (!MVequal(pmv[2],startMV))                                           FRAMEINFO * const frame,
2077          if (!MVequal(pmv[2],prevMB->mvs[iSubBlock]))                                           const int32_t time_bp,
2078          if (!MVequal(pmv[2],pmv[0]))                                           const int32_t time_pp,
2079          if (!MVequal(pmv[2],pmv[1]))                                           /* forward (past) reference */
2080                                             const MACROBLOCK * const f_mbs,
2081                                             const IMAGE * const f_ref,
2082                                             const IMAGE * const f_refH,
2083                                             const IMAGE * const f_refV,
2084                                             const IMAGE * const f_refHV,
2085                                             /* backward (future) reference */
2086                                             const FRAMEINFO * const b_reference,
2087                                             const IMAGE * const b_ref,
2088                                             const IMAGE * const b_refH,
2089                                             const IMAGE * const b_refV,
2090                                             const IMAGE * const b_refHV)
2091          {          {
2092                  if (!(MotionFlags & PMV_HALFPEL8 ))          uint32_t i, j;
2093                  {       pmv[2].x = EVEN(pmv[2].x);          int32_t best_sad;
2094                          pmv[2].y = EVEN(pmv[2].y);          uint32_t skip_sad;
2095            int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;
2096            const MACROBLOCK * const b_mbs = b_reference->mbs;
2097    
2098            VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
2099    
2100            const int32_t TRB = time_pp - time_bp;
2101            const int32_t TRD = time_pp;
2102    
2103            /* some pre-inintialized data for the rest of the search */
2104    
2105            SearchData Data;
2106            int32_t iMinSAD;
2107            VECTOR currentMV[3];
2108            VECTOR currentQMV[3];
2109            int32_t temp[8];
2110            memset(&Data, 0, sizeof(SearchData));
2111            Data.iEdgedWidth = pParam->edged_width;
2112            Data.currentMV = currentMV; Data.currentQMV = currentQMV;
2113            Data.iMinSAD = &iMinSAD;
2114            Data.lambda16 = lambda_vec16[frame->quant];
2115            Data.qpel = pParam->vol_flags & XVID_VOL_QUARTERPEL;
2116            Data.rounding = 0;
2117            Data.chroma = frame->motion_flags & XVID_ME_CHROMA_BVOP;
2118            Data.temp = temp;
2119    
2120            Data.RefQ = f_refV->u; /* a good place, also used in MC (for similar purpose) */
2121    
2122            /* note: i==horizontal, j==vertical */
2123            for (j = 0; j < pParam->mb_height; j++) {
2124    
2125                    f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
2126    
2127                    for (i = 0; i < pParam->mb_width; i++) {
2128                            MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
2129                            const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
2130    
2131    /* special case, if collocated block is SKIPed in P-VOP: encoding is forward (0,0), cpb=0 without further ado */
2132                            if (b_reference->coding_type != S_VOP)
2133                                    if (b_mb->mode == MODE_NOT_CODED) {
2134                                            pMB->mode = MODE_NOT_CODED;
2135                                            continue;
2136                  }                  }
                 CHECK_MV8_CANDIDATE(pmv[2].x,pmv[2].y);  
2137    
2138  // top right neighbour, if allowed and needed                          Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
2139          if (!MVzero(pmv[3]))                          Data.CurU = frame->image.u + (j * Data.iEdgedWidth/2 + i) * 8;
2140          if (!MVequal(pmv[3],startMV))                          Data.CurV = frame->image.v + (j * Data.iEdgedWidth/2 + i) * 8;
2141          if (!MVequal(pmv[3],prevMB->mvs[iSubBlock]))                          pMB->quant = frame->quant;
2142          if (!MVequal(pmv[3],pmv[0]))  
2143          if (!MVequal(pmv[3],pmv[1]))  /* direct search comes first, because it (1) checks for SKIP-mode
2144          if (!MVequal(pmv[3],pmv[2]))          and (2) sets very good predictions for forward and backward search */
2145                  {                          skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2146                          if (!(MotionFlags & PMV_HALFPEL8 ))                                                                          b_ref, b_refH->y, b_refV->y, b_refHV->y,
2147                          {       pmv[3].x = EVEN(pmv[3].x);                                                                          &frame->image,
2148                                  pmv[3].y = EVEN(pmv[3].y);                                                                          i, j,
2149                                                                            frame->motion_flags,
2150                                                                            TRB, TRD,
2151                                                                            pParam,
2152                                                                            pMB, b_mb,
2153                                                                            &best_sad,
2154                                                                            &Data);
2155    
2156                            if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
2157    
2158                            /* forward search */
2159                            SearchBF(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2160                                                    &frame->image, i, j,
2161                                                    frame->motion_flags,
2162                                                    frame->fcode, pParam,
2163                                                    pMB, &f_predMV, &best_sad,
2164                                                    MODE_FORWARD, &Data);
2165    
2166                            /* backward search */
2167                            SearchBF(b_ref, b_refH->y, b_refV->y, b_refHV->y,
2168                                                    &frame->image, i, j,
2169                                                    frame->motion_flags,
2170                                                    frame->bcode, pParam,
2171                                                    pMB, &b_predMV, &best_sad,
2172                                                    MODE_BACKWARD, &Data);
2173    
2174                            /* interpolate search comes last, because it uses data from forward and backward as prediction */
2175                            SearchInterpolate(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2176                                                    b_ref, b_refH->y, b_refV->y, b_refHV->y,
2177                                                    &frame->image,
2178                                                    i, j,
2179                                                    frame->fcode, frame->bcode,
2180                                                    frame->motion_flags,
2181                                                    pParam,
2182                                                    &f_predMV, &b_predMV,
2183                                                    pMB, &best_sad,
2184                                                    &Data);
2185    
2186                            /* final skip decision */
2187                            if ( (skip_sad < frame->quant * MAX_SAD00_FOR_SKIP * 2)
2188                                            && ((100*best_sad)/(skip_sad+1) > FINAL_SKIP_THRESH) )
2189                                    SkipDecisionB(&frame->image, f_ref, b_ref, pMB, i, j, &Data);
2190    
2191                            switch (pMB->mode) {
2192                                    case MODE_FORWARD:
2193                                            f_count++;
2194                                            f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2195                                            break;
2196                                    case MODE_BACKWARD:
2197                                            b_count++;
2198                                            b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2199                                            break;
2200                                    case MODE_INTERPOLATE:
2201                                            i_count++;
2202                                            f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2203                                            b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2204                                            break;
2205                                    case MODE_DIRECT:
2206                                    case MODE_DIRECT_NO4V:
2207                                            d_count++;
2208                                    default:
2209                                            break;
2210                            }
2211                          }                          }
                         CHECK_MV8_CANDIDATE(pmv[3].x,pmv[3].y);  
2212                  }                  }
2213          }          }
2214    
2215          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  static __inline void
2216                  iMinSAD -= MV8_00_BIAS;  MEanalyzeMB (   const uint8_t * const pRef,
2217                                    const uint8_t * const pCur,
2218                                    const int x,
2219                                    const int y,
2220                                    const MBParam * const pParam,
2221                                    MACROBLOCK * const pMBs,
2222                                    SearchData * const Data)
2223    {
2224    
2225            int i, mask;
2226            int quarterpel = (pParam->vol_flags & XVID_VOL_QUARTERPEL)? 1: 0;
2227            VECTOR pmv[3];
2228            MACROBLOCK * const pMB = &pMBs[x + y * pParam->mb_width];
2229    
2230  /* 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.  
 */  
2231    
2232          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 */
2233          {          if (x == 1 && y == 1) Data->predMV.x = Data->predMV.y = 0;
2234                  if (MotionFlags & PMV_QUICKSTOP16)          else
2235                          goto PMVfast8_Terminate_without_Refine;                  if (x == 1) /* left macroblock does not have any vector now */
2236                  if (MotionFlags & PMV_EARLYSTOP16)                          Data->predMV = (pMB - pParam->mb_width)->mvs[0]; /* top instead of median */
2237                          goto PMVfast8_Terminate_with_Refine;                  else if (y == 1) /* top macroblock doesn't have it's vector */
2238          }                          Data->predMV = (pMB - 1)->mvs[0]; /* left instead of median */
2239                            else Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); /* else median */
2240    
2241  /************ (Diamond Search)  **************/          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2242  /*                          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.  
 */  
2243    
2244          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */          Data->Cur = pCur + (x + y * pParam->edged_width) * 16;
2245            Data->RefP[0] = pRef + (x + y * pParam->edged_width) * 16;
2246    
2247  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          pmv[1].x = EVEN(pMB->mvs[0].x);
2248          iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,          pmv[1].y = EVEN(pMB->mvs[0].y);
2249                                           x, y,          pmv[2].x = EVEN(Data->predMV.x);
2250                                           currMV->x, currMV->y, iMinSAD, &newMV,          pmv[2].y = EVEN(Data->predMV.y);
2251                                           pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);          pmv[0].x = pmv[0].y = 0;
2252    
2253          if (iSAD < iMinSAD)          CheckCandidate32I(0, 0, 255, &i, Data);
         {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
2254    
2255          if (MotionFlags & PMV_EXTSEARCH8)          if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP) {
         {  
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
2256    
2257                  if (!(MVequal(pmv[0],backupMV)) )                  if (!(mask = make_mask(pmv, 1)))
2258                  {       iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,                          CheckCandidate32I(pmv[1].x, pmv[1].y, mask, &i, Data);
2259                                                            x, y,                  if (!(mask = make_mask(pmv, 2)))
2260                                                            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);  
2261    
2262                  if (iSAD < iMinSAD)                  if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP) /* diamond only if needed */
2263                  {                          DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, i);
2264                          *currMV = newMV;          }
2265                          iMinSAD = iSAD;  
2266            for (i = 0; i < 4; i++) {
2267                    MACROBLOCK * MB = &pMBs[x + (i&1) + (y+(i>>1)) * pParam->mb_width];
2268                    MB->mvs[0] = MB->mvs[1] = MB->mvs[2] = MB->mvs[3] = Data->currentMV[i];
2269                    MB->mode = MODE_INTER;
2270                    MB->sad16 = Data->iMinSAD[i+1];
2271                  }                  }
2272                  }                  }
2273    
2274                  if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )  #define INTRA_THRESH    2200
2275                  {       iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,  #define INTER_THRESH    50
2276                                                            x, y,  #define INTRA_THRESH2   95
                                                           0, 0, iMinSAD, &newMV,  
                                                           pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);  
2277    
2278                  if (iSAD < iMinSAD)  int
2279                  {  MEanalysis(     const IMAGE * const pRef,
2280                          *currMV = newMV;                          const FRAMEINFO * const Current,
2281                          iMinSAD = iSAD;                          const MBParam * const pParam,
2282                  }                          const int maxIntra, //maximum number if non-I frames
2283                            const int intraCount, //number of non-I frames after last I frame; 0 if we force P/B frame
2284                            const int bCount, // number of B frames in a row
2285                            const int b_thresh)
2286    {
2287            uint32_t x, y, intra = 0;
2288            int sSAD = 0;
2289            MACROBLOCK * const pMBs = Current->mbs;
2290            const IMAGE * const pCurrent = &Current->image;
2291            int IntraThresh = INTRA_THRESH, InterThresh = INTER_THRESH + b_thresh;
2292            int blocks = 0;
2293            int complexity = 0;
2294    
2295            int32_t iMinSAD[5], temp[5];
2296            VECTOR currentMV[5];
2297            SearchData Data;
2298            Data.iEdgedWidth = pParam->edged_width;
2299            Data.currentMV = currentMV;
2300            Data.iMinSAD = iMinSAD;
2301            Data.iFcode = Current->fcode;
2302            Data.temp = temp;
2303            CheckCandidate = CheckCandidate32I;
2304    
2305            if (intraCount != 0) {
2306                    if (intraCount < 10) // we're right after an I frame
2307                            IntraThresh += 15* (intraCount - 10) * (intraCount - 10);
2308                    else
2309                            if ( 5*(maxIntra - intraCount) < maxIntra) // we're close to maximum. 2 sec when max is 10 sec
2310                                    IntraThresh -= (IntraThresh * (maxIntra - 8*(maxIntra - intraCount)))/maxIntra;
2311                  }                  }
2312    
2313            InterThresh -= 12 * bCount;
2314            if (InterThresh < 15 + b_thresh) InterThresh = 15 + b_thresh;
2315    
2316            if (sadInit) (*sadInit) ();
2317    
2318            for (y = 1; y < pParam->mb_height-1; y += 2) {
2319                    for (x = 1; x < pParam->mb_width-1; x += 2) {
2320                            int i;
2321                            blocks += 10;
2322    
2323                            if (bCount == 0) pMBs[x + y * pParam->mb_width].mvs[0] = zeroMV;
2324                            else { //extrapolation of the vector found for last frame
2325                                    pMBs[x + y * pParam->mb_width].mvs[0].x =
2326                                            (pMBs[x + y * pParam->mb_width].mvs[0].x * (bCount+1) ) / bCount;
2327                                    pMBs[x + y * pParam->mb_width].mvs[0].y =
2328                                            (pMBs[x + y * pParam->mb_width].mvs[0].y * (bCount+1) ) / bCount;
2329          }          }
2330    
2331  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.                          MEanalyzeMB(pRef->y, pCurrent->y, x, y, pParam, pMBs, &Data);
2332     By performing an optional local half-pixel search, we can refine this result even further.  
2333  */                          for (i = 0; i < 4; i++) {
2334                                    int dev;
2335                                    MACROBLOCK *pMB = &pMBs[x+(i&1) + (y+(i>>1)) * pParam->mb_width];
2336                                    dev = dev16(pCurrent->y + (x + (i&1) + (y + (i>>1)) * pParam->edged_width) * 16,
2337                                                                    pParam->edged_width);
2338    
2339                                    complexity += dev;
2340                                    if (dev + IntraThresh < pMB->sad16) {
2341                                            pMB->mode = MODE_INTRA;
2342                                            if (++intra > ((pParam->mb_height-2)*(pParam->mb_width-2))/2) return I_VOP;
2343                                    }
2344    
2345  PMVfast8_Terminate_with_Refine:                                  if (pMB->mvs[0].x == 0 && pMB->mvs[0].y == 0)
2346          if (MotionFlags & PMV_HALFPELREFINE8)           // perform final half-pel step                                          if (dev > 500 && pMB->sad16 < 1000)
2347                  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);  
2348    
2349                                    sSAD += pMB->sad16;
2350                            }
2351                    }
2352            }
2353            complexity >>= 7;
2354    
2355  PMVfast8_Terminate_without_Refine:          sSAD /= complexity + 4*blocks;
         currPMV->x = currMV->x - pmv[0].x;  
         currPMV->y = currMV->y - pmv[0].y;  
2356    
2357          return iMinSAD;          if (intraCount > 12 && sSAD > INTRA_THRESH2 ) return I_VOP;
2358            if (sSAD > InterThresh ) return P_VOP;
2359            emms();
2360            return B_VOP;
2361  }  }
2362    
2363  int32_t EPZSSearch16(  
2364                                          const uint8_t * const pRef,  /* functions which perform BITS-based search/bitcount */
2365                                          const uint8_t * const pRefH,  
2366                                          const uint8_t * const pRefV,  static int
2367                                          const uint8_t * const pRefHV,  CountMBBitsInter(SearchData * const Data,
2368                                          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,  
2369                                          const MBParam * const pParam,                                          const MBParam * const pParam,
2370                                          const MACROBLOCK * const pMBs,                                  const uint32_t MotionFlags)
                                         const MACROBLOCK * const prevMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
2371  {  {
2372      const uint32_t iWcount = pParam->mb_width;          int i, iDirection;
2373      const uint32_t iHcount = pParam->mb_height;          int32_t bsad[5];
2374    
2375            CheckCandidate = CheckCandidateBits16;
2376    
2377          const int32_t iWidth = pParam->width;          if (Data->qpel) {
2378          const int32_t iHeight = pParam->height;                  for(i = 0; i < 5; i++) {
2379          const int32_t iEdgedWidth = pParam->edged_width;                          Data->currentMV[i].x = Data->currentQMV[i].x/2;
2380                            Data->currentMV[i].y = Data->currentQMV[i].y/2;
2381                    }
2382                    Data->qpel_precision = 1;
2383                    CheckCandidateBits16(Data->currentQMV[0].x, Data->currentQMV[0].y, 255, &iDirection, Data);
2384    
2385          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;                  if (MotionFlags & (XVID_ME_HALFPELREFINE16_RD | XVID_ME_EXTSEARCH_RD)) { /* we have to prepare for halfpixel-precision search */
2386                            for(i = 0; i < 5; i++) bsad[i] = Data->iMinSAD[i];
2387                            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2388                                                    pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
2389                            Data->qpel_precision = 0;
2390                            if (Data->currentQMV->x & 1 || Data->currentQMV->y & 1)
2391                                    CheckCandidateBits16(Data->currentMV[0].x, Data->currentMV[0].y, 255, &iDirection, Data);
2392                    }
2393    
2394          int32_t min_dx;          } else { /* not qpel */
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
2395    
2396          VECTOR newMV;                  CheckCandidateBits16(Data->currentMV[0].x, Data->currentMV[0].y, 255, &iDirection, Data);
2397          VECTOR backupMV;          }
2398    
2399          VECTOR pmv[4];          if (MotionFlags&XVID_ME_EXTSEARCH_RD) SquareSearch(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
         int32_t psad[8];  
2400    
2401          static MACROBLOCK * oldMBs = NULL;          if (MotionFlags&XVID_ME_HALFPELREFINE16_RD) SubpelRefine(Data);
 //      const MACROBLOCK * const pMB = pMBs + x + y * iWcount;  
         const MACROBLOCK * const prevMB = prevMBs + x + y * iWcount;  
         MACROBLOCK * oldMB = NULL;  
2402    
2403          static int32_t thresh2;          if (Data->qpel) {
2404          int32_t bPredEq;                  if (MotionFlags&(XVID_ME_EXTSEARCH_RD | XVID_ME_HALFPELREFINE16_RD)) { /* there was halfpel-precision search */
2405          int32_t iMinSAD,iSAD=9999;                          for(i = 0; i < 5; i++) if (bsad[i] > Data->iMinSAD[i]) {
2406                                    Data->currentQMV[i].x = 2 * Data->currentMV[i].x; /* we have found a better match */
2407                                    Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
2408                            }
2409    
2410          MainSearch16FuncPtr MainSearchPtr;                          /* preparing for qpel-precision search */
2411                            Data->qpel_precision = 1;
2412                            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2413                                            pParam->width, pParam->height, Data->iFcode, 1, 0);
2414                    }
2415                    if (MotionFlags&XVID_ME_QUARTERPELREFINE16_RD) SubpelRefine(Data);
2416            }
2417    
2418          if (oldMBs == NULL)          if (MotionFlags&XVID_ME_CHECKPREDICTION_RD) { /* let's check vector equal to prediction */
2419          {       oldMBs = (MACROBLOCK*) calloc(iWcount*iHcount,sizeof(MACROBLOCK));                  VECTOR * v = Data->qpel ? Data->currentQMV : Data->currentMV;
2420  //              fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));                  if (!(Data->predMV.x == v->x && Data->predMV.y == v->y))
2421                            CheckCandidateBits16(Data->predMV.x, Data->predMV.y, 255, &iDirection, Data);
2422            }
2423            return Data->iMinSAD[0];
2424          }          }
         oldMB = oldMBs + x + y * iWcount;  
2425    
2426  /* Get maximum range */  static int
2427          get_range(&min_dx, &max_dx, &min_dy, &max_dy,  CountMBBitsInter4v(const SearchData * const Data,
2428                          x, y, 16, iWidth, iHeight, iFcode);                                          MACROBLOCK * const pMB, const MACROBLOCK * const pMBs,
2429                                            const int x, const int y,
2430                                            const MBParam * const pParam, const uint32_t MotionFlags,
2431                                            const VECTOR * const backup)
2432    {
2433    
2434          if (!(MotionFlags & PMV_HALFPEL16 ))          int cbp = 0, bits = 0, t = 0, i, iDirection;
2435          { min_dx = EVEN(min_dx);          SearchData Data2, *Data8 = &Data2;
2436            max_dx = EVEN(max_dx);          int sumx = 0, sumy = 0;
2437            min_dy = EVEN(min_dy);          int16_t *in = Data->dctSpace, *coeff = Data->dctSpace + 64;
2438            max_dy = EVEN(max_dy);          uint8_t * ptr;
         }               /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
2439    
2440          bPredEq  = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);          memcpy(Data8, Data, sizeof(SearchData));
2441            CheckCandidate = CheckCandidateBits8;
2442    
2443  /* 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.  
 */  
2444    
2445  // Prepare for main loop                  Data8->iMinSAD = Data->iMinSAD + i + 1;
2446                    Data8->currentMV = Data->currentMV + i + 1;
2447                    Data8->currentQMV = Data->currentQMV + i + 1;
2448                    Data8->Cur = Data->Cur + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2449                    Data8->RefP[0] = Data->RefP[0] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2450                    Data8->RefP[2] = Data->RefP[2] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2451                    Data8->RefP[1] = Data->RefP[1] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2452                    Data8->RefP[3] = Data->RefP[3] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2453                    *Data8->cbp = (Data->cbp[1] & (1<<(5-i))) ? 1:0; // copy corresponding cbp bit
2454    //              *Data8->cbp = 1;
2455    
2456          *currMV=pmv[0];         /* current best := median prediction */                  if(Data->qpel) {
2457          if (!(MotionFlags & PMV_HALFPEL16))                          Data8->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, i);
2458          {                          if (i != 0)     t = d_mv_bits(  Data8->currentQMV->x, Data8->currentQMV->y,
2459                  currMV->x = EVEN(currMV->x);                                                                                  Data8->predMV, Data8->iFcode, 0, 0);
2460                  currMV->y = EVEN(currMV->y);                  } else {
2461                            Data8->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, i);
2462                            if (i != 0)     t = d_mv_bits(  Data8->currentMV->x, Data8->currentMV->y,
2463                                                                                    Data8->predMV, Data8->iFcode, 0, 0);
2464          }          }
2465    
2466          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,
2467                  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 ******************/  
2468    
2469          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);  
2470    
2471  // thresh1 is fixed to 256                  Data8->qpel_precision = Data8->qpel;
2472          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) */
2473                  {                  {
2474                          if (MotionFlags & PMV_QUICKSTOP16)                          VECTOR *v = Data8->qpel ? Data8->currentQMV : Data8->currentMV;
2475                                  goto EPZS16_Terminate_without_Refine;                          if (!MVequal (*v, backup[i+1]) )
2476                          if (MotionFlags & PMV_EARLYSTOP16)                                  CheckCandidateBits8(backup[i+1].x, backup[i+1].y, 255, &iDirection, Data8);
                                 goto EPZS16_Terminate_with_Refine;  
2477                  }                  }
2478    
2479  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/                  if (Data8->qpel) {
2480                            if (MotionFlags&XVID_ME_HALFPELREFINE8_RD || (MotionFlags&XVID_ME_EXTSEARCH8 && MotionFlags&XVID_ME_EXTSEARCH_RD)) { /* halfpixel motion search follows */
2481                                    int32_t s = *Data8->iMinSAD;
2482                                    Data8->currentMV->x = Data8->currentQMV->x/2;
2483                                    Data8->currentMV->y = Data8->currentQMV->y/2;
2484                                    Data8->qpel_precision = 0;
2485                                    get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 8,
2486                                                            pParam->width, pParam->height, Data8->iFcode - 1, 0, 0);
2487    
2488  // previous frame MV                                  if (Data8->currentQMV->x & 1 || Data8->currentQMV->y & 1)
2489          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x,prevMB->mvs[0].y);                                          CheckCandidateBits8(Data8->currentMV->x, Data8->currentMV->y, 255, &iDirection, Data8);
2490    
2491  // set threshhold based on Min of Prediction and SAD of collocated block                                  if (MotionFlags & XVID_ME_EXTSEARCH8 && MotionFlags & XVID_ME_EXTSEARCH_RD)
2492  // 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);
2493    
2494          if ((x==0) && (y==0) )                                  if (MotionFlags & XVID_ME_HALFPELREFINE8_RD)
2495          {                                          SubpelRefine(Data8);
                 thresh2 =  512;  
         }  
         else  
         {  
 /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */  
2496    
2497                  thresh2 = MIN(psad[0],iSAD)*6/5 + 128;                                  if(s > *Data8->iMinSAD) { /* we have found a better match */
2498                                            Data8->currentQMV->x = 2*Data8->currentMV->x;
2499                                            Data8->currentQMV->y = 2*Data8->currentMV->y;
2500          }          }
2501    
2502  // MV=(0,0) is often a good choice                                  Data8->qpel_precision = 1;
2503                                    get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 8,
2504                                                            pParam->width, pParam->height, Data8->iFcode, 1, 0);
2505    
2506          CHECK_MV16_ZERO;                          }
2507                            if (MotionFlags & XVID_ME_QUARTERPELREFINE8_RD) SubpelRefine(Data8);
2508    
2509                    } else { /* not qpel */
2510    
2511  // left neighbour, if allowed                          if (MotionFlags & XVID_ME_EXTSEARCH8 && MotionFlags & XVID_ME_EXTSEARCH_RD) /* extsearch */
2512          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);  
         }  
2513    
2514  // top neighbour, if allowed                          if (MotionFlags & XVID_ME_HALFPELREFINE8_RD)
2515          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);  
2516                  }                  }
                 CHECK_MV16_CANDIDATE(pmv[2].x,pmv[2].y);  
2517    
2518  // top right neighbour, if allowed                  /* checking vector equal to predicion */
2519                  if ((uint32_t)x != (iWcount-1))                  if (i != 0 && MotionFlags & XVID_ME_CHECKPREDICTION_RD) {
2520                  {                          const VECTOR * v = Data->qpel ? Data8->currentQMV : Data8->currentMV;
2521                          if (!(MotionFlags & PMV_HALFPEL16 ))                          if (!MVequal(*v, Data8->predMV))
2522                          {       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);  
                 }  
2523          }          }
2524    
2525  /* Terminate if MinSAD <= T_2                  bits += *Data8->iMinSAD;
2526     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]                  if (bits >= Data->iMinSAD[0]) return bits; /* no chances for INTER4V */
 */  
2527    
2528          if ( (iMinSAD <= thresh2)                  /* MB structures for INTER4V mode; we have to set them here, we don't have predictor anywhere else */
2529                  || ( MVequal(*currMV,prevMB->mvs[0]) && ((uint32_t)iMinSAD <= prevMB->sad16) ) )                  if(Data->qpel) {
2530                  {                          pMB->pmvs[i].x = Data8->currentQMV->x - Data8->predMV.x;
2531                          if (MotionFlags & PMV_QUICKSTOP16)                          pMB->pmvs[i].y = Data8->currentQMV->y - Data8->predMV.y;
2532                                  goto EPZS16_Terminate_without_Refine;                          pMB->qmvs[i] = *Data8->currentQMV;
2533                          if (MotionFlags & PMV_EARLYSTOP16)                          sumx += Data8->currentQMV->x/2;
2534                                  goto EPZS16_Terminate_with_Refine;                          sumy += Data8->currentQMV->y/2;
2535                    } else {
2536                            pMB->pmvs[i].x = Data8->currentMV->x - Data8->predMV.x;
2537                            pMB->pmvs[i].y = Data8->currentMV->y - Data8->predMV.y;
2538                            sumx += Data8->currentMV->x;
2539                            sumy += Data8->currentMV->y;
2540                  }                  }
2541                    pMB->mvs[i] = *Data8->currentMV;
2542                    pMB->sad8[i] = 4 * *Data8->iMinSAD;
2543                    if (Data8->cbp[0]) cbp |= 1 << (5 - i);
2544    
2545  /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/          } /* end - for all luma blocks */
2546    
2547          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  
2548    
2549          CHECK_MV16_CANDIDATE(backupMV.x,backupMV.y);          /* let's check chroma */
2550            sumx = (sumx >> 3) + roundtab_76[sumx & 0xf];
2551  // 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);  
2552    
2553  // top neighbour          /* chroma U */
2554          if (y != 0)          ptr = interpolate8x8_switch2(Data->RefQ + 64, Data->RefP[4], 0, 0, sumx, sumy, Data->iEdgedWidth/2, Data->rounding);
2555                  CHECK_MV16_CANDIDATE((prevMB-iWcount)->mvs[0].x,(prevMB-iWcount)->mvs[0].y);          transfer_8to16subro(in, Data->CurU, ptr, Data->iEdgedWidth/2);
2556            bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 4);
2557    
2558  // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs          if (bits >= *Data->iMinSAD) return bits;
2559    
2560          if ((uint32_t)x != iWcount-1)          /* chroma V */
2561                  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);
2562            transfer_8to16subro(in, Data->CurV, ptr, Data->iEdgedWidth/2);
2563            bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 5);
2564    
2565  // 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);  
2566    
2567  /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */          *Data->cbp = cbp;
2568          if (iMinSAD <= thresh2)          return bits;
                 {  
                         if (MotionFlags & PMV_QUICKSTOP16)  
                                 goto EPZS16_Terminate_without_Refine;  
                         if (MotionFlags & PMV_EARLYSTOP16)  
                                 goto EPZS16_Terminate_with_Refine;  
2569                  }                  }
2570    
2571  /************ (if Diamond Search)  **************/  static int
2572    CountMBBitsIntra(const SearchData * const Data)
2573          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */  {
2574            int bits = BITS_MULT*1; /* this one is ac/dc prediction flag bit */
2575            int cbp = 0, i, dc = 0;
2576            int16_t *in = Data->dctSpace, * coeff = Data->dctSpace + 64;
2577    
2578          if (MotionFlags & PMV_USESQUARES8)          for(i = 0; i < 4; i++) {
2579                  MainSearchPtr = Square16_MainSearch;                  int s = 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2580          else                  transfer_8to16copy(in, Data->Cur + s, Data->iEdgedWidth);
2581                    bits += Block_CalcBitsIntra(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, i, &dc);
2582    
2583          if (MotionFlags & PMV_ADVANCEDDIAMOND8)                  if (bits >= Data->iMinSAD[0]) return bits;
2584                  MainSearchPtr = AdvDiamond16_MainSearch;          }
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
2585    
2586  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          bits += BITS_MULT*xvid_cbpy_tab[cbp>>2].len;
2587    
2588          iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,          /*chroma U */
2589                          x, y,          transfer_8to16copy(in, Data->CurU, Data->iEdgedWidth/2);
2590                          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);  
2591    
2592          if (iSAD < iMinSAD)          if (bits >= Data->iMinSAD[0]) return bits;
         {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
2593    
2594            /* chroma V */
2595            transfer_8to16copy(in, Data->CurV, Data->iEdgedWidth/2);
2596            bits += Block_CalcBitsIntra(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 5, &dc);
2597    
2598          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) */  
2599    
2600                  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);  
2601                  }                  }
2602    
2603                  if (iSAD < iMinSAD)  static int
2604    CountMBBitsGMC(const SearchData * const Data, const IMAGE * const vGMC, const int x, const int y)
2605                  {                  {
2606                          *currMV = newMV;          int bits = BITS_MULT*1; /* this one is mcsel */
2607                          iMinSAD = iSAD;          int cbp = 0, i;
2608            int16_t *in = Data->dctSpace, * coeff = Data->dctSpace + 64;
2609    
2610            for(i = 0; i < 4; i++) {
2611                    int s = 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2612                    transfer_8to16subro(in, Data->Cur + s, vGMC->y + s + 16*(x+y*Data->iEdgedWidth), Data->iEdgedWidth);
2613                    bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, i);
2614                    if (bits >= Data->iMinSAD[0]) return bits;
2615                  }                  }
2616    
2617                  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);  
2618    
2619                          if (iSAD < iMinSAD)          /*chroma U */
2620                          {          transfer_8to16subro(in, Data->CurU, vGMC->u + 8*(x+y*(Data->iEdgedWidth/2)), Data->iEdgedWidth/2);
2621                                  *currMV = newMV;          bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 4);
                                 iMinSAD = iSAD;  
                         }  
                 }  
         }  
2622    
2623  /***************        Choose best MV found     **************/          if (bits >= Data->iMinSAD[0]) return bits;
2624    
2625  EPZS16_Terminate_with_Refine:          /* chroma V */
2626          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);
2627                  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);  
2628    
2629  EPZS16_Terminate_without_Refine:          bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTER & 7) | ((cbp & 3) << 3)].len;
2630    
2631          *oldMB = *prevMB;          *Data->cbp = cbp;
2632    
2633          currPMV->x = currMV->x - pmv[0].x;          return bits;
         currPMV->y = currMV->y - pmv[0].y;  
         return iMinSAD;  
2634  }  }
2635    
2636    
2637  int32_t EPZSSearch8(  
2638    
2639    static __inline void
2640    GMEanalyzeMB (  const uint8_t * const pCur,
2641                                          const uint8_t * const pRef,                                          const uint8_t * const pRef,
2642                                          const uint8_t * const pRefH,                                          const uint8_t * const pRefH,
2643                                          const uint8_t * const pRefV,                                          const uint8_t * const pRefV,
2644                                          const uint8_t * const pRefHV,                                          const uint8_t * const pRefHV,
2645                                          const IMAGE * const pCur,                                  const int x,
2646                                          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,  
2647                                          const MBParam * const pParam,                                          const MBParam * const pParam,
2648                                          const MACROBLOCK * const pMBs,                                  MACROBLOCK * const pMBs,
2649                                          const MACROBLOCK * const prevMBs,                                  SearchData * const Data)
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
2650  {  {
 /* Please not that EPZS might not be a good choice for 8x8-block motion search ! */  
2651    
2652          const uint32_t iWcount = pParam->mb_width;          int i=0;
2653          const int32_t iWidth = pParam->width;          MACROBLOCK * const pMB = &pMBs[x + y * pParam->mb_width];
2654          const int32_t iHeight = pParam->height;  
2655          const int32_t iEdgedWidth = pParam->edged_width;          Data->iMinSAD[0] = MV_MAX_ERROR;
2656    
2657          const uint8_t * cur = pCur->y + x*8 + y*8*iEdgedWidth;          Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
2658    
2659          int32_t iDiamondSize=1;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2660                                    pParam->width, pParam->height, 16, 0, 0);
2661    
2662          int32_t min_dx;          Data->Cur = pCur + 16*(x + y * pParam->edged_width);
2663          int32_t max_dx;          Data->RefP[0] = pRef + 16*(x + y * pParam->edged_width);
2664          int32_t min_dy;          Data->RefP[1] = pRefV + 16*(x + y * pParam->edged_width);
2665          int32_t max_dy;          Data->RefP[2] = pRefH + 16*(x + y * pParam->edged_width);
2666            Data->RefP[3] = pRefHV + 16*(x + y * pParam->edged_width);
2667    
2668          VECTOR newMV;          Data->currentMV[0].x = Data->currentMV[0].y = 0;
2669          VECTOR backupMV;          CheckCandidate16I(0, 0, 255, &i, Data);
2670    
2671          VECTOR pmv[4];          if ( (Data->predMV.x !=0) || (Data->predMV.y != 0) )
2672          int32_t psad[8];                  CheckCandidate16I(Data->predMV.x, Data->predMV.y, 255, &i, Data);
2673    
2674          const   int32_t iSubBlock = ((y&1)<<1) + (x&1);          AdvDiamondSearch(Data->currentMV[0].x, Data->currentMV[0].y, Data, 255);
2675    
2676  //      const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          SubpelRefine(Data);
         const MACROBLOCK * const prevMB = prevMBs + (x>>1) + (y>>1) * iWcount;  
2677    
         int32_t bPredEq;  
         int32_t iMinSAD,iSAD=9999;  
2678    
2679          MainSearch8FuncPtr MainSearchPtr;          /* for QPel halfpel positions are worse than in halfpel mode :( */
2680    /*      if (Data->qpel) {
2681                    Data->currentQMV->x = 2*Data->currentMV->x;
2682                    Data->currentQMV->y = 2*Data->currentMV->y;
2683                    Data->qpel_precision = 1;
2684                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2685                                            pParam->width, pParam->height, iFcode, 1, 0);
2686                    SubpelRefine(Data);
2687            }
2688    */
2689    
2690  /* Get maximum range */          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
2691          get_range(&min_dx, &max_dx, &min_dy, &max_dy,          pMB->sad16 = Data->iMinSAD[0];
2692                          x, y, 8, iWidth, iHeight, iFcode);          pMB->mode = MODE_INTER;
2693            pMB->sad16 += 10*d_mv_bits(pMB->mvs[0].x, pMB->mvs[0].y, Data->predMV, Data->iFcode, 0, 0);
2694            return;
2695    }
2696    
2697  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  void
2698    GMEanalysis(const MBParam * const pParam,
2699                            const FRAMEINFO * const current,
2700                            const FRAMEINFO * const reference,
2701                            const IMAGE * const pRefH,
2702                            const IMAGE * const pRefV,
2703                            const IMAGE * const pRefHV)
2704    {
2705            uint32_t x, y;
2706            MACROBLOCK * const pMBs = current->mbs;
2707            const IMAGE * const pCurrent = &current->image;
2708            const IMAGE * const pReference = &reference->image;
2709    
2710          if (!(MotionFlags & PMV_HALFPEL8 ))          int32_t iMinSAD[5], temp[5];
2711          { min_dx = EVEN(min_dx);          VECTOR currentMV[5];
2712            max_dx = EVEN(max_dx);          SearchData Data;
2713            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; */  
2714    
2715          bPredEq  = get_pmvdata(pMBs, x>>1, y>>1, iWcount, iSubBlock, pmv, psad);          Data.iEdgedWidth = pParam->edged_width;
2716            Data.rounding = pParam->m_rounding_type;
2717    
2718            Data.currentMV = &currentMV[0];
2719            Data.iMinSAD = &iMinSAD[0];
2720            Data.iFcode = current->fcode;
2721            Data.temp = temp;
2722    
2723  /* 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.  
 */  
2724    
2725  // Prepare for main loop          if (sadInit) (*sadInit) ();
2726    
2727            for (y = 0; y < pParam->mb_height; y ++) {
2728                    for (x = 0; x < pParam->mb_width; x ++) {
2729    
2730          if (!(MotionFlags & PMV_HALFPEL8))                          GMEanalyzeMB(pCurrent->y, pReference->y, pRefH->y, pRefV->y, pRefHV->y, x, y, pParam, pMBs, &Data);
2731          {                  }
2732                  currMV->x = EVEN(currMV->x);          }
2733                  currMV->y = EVEN(currMV->y);          return;
2734          }          }
2735    
         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;  
2736    
2737  /***************** This is predictor SET A: only median prediction ******************/  WARPPOINTS
2738    GlobalMotionEst(MACROBLOCK * const pMBs,
2739                                    const MBParam * const pParam,
2740                                    const FRAMEINFO * const current,
2741                                    const FRAMEINFO * const reference,
2742                                    const IMAGE * const pRefH,
2743                                    const IMAGE * const pRefV,
2744                                    const IMAGE * const pRefHV)
2745    {
2746    
2747            const int deltax=8;             // upper bound for difference between a MV and it's neighbour MVs
2748            const int deltay=8;
2749            const unsigned int gradx=512;           // lower bound for gradient in MB (ignore "flat" blocks)
2750            const unsigned int grady=512;
2751    
2752          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);  
2753    
2754            WARPPOINTS gmc;
2755    
2756  // 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;  
                 }  
2757    
2758  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/          int MBh = pParam->mb_height;
2759            int MBw = pParam->mb_width;
2760            const int minblocks = 9; //MBh*MBw/32+3;                /* just some reasonable number 3% + 3 */
2761            const int maxblocks = MBh*MBw/4;                /* just some reasonable number 3% + 3 */
2762    
2763            int num=0;
2764            int oldnum;
2765    
2766  // 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;  
2767    
2768  // previous frame MV          GMEanalysis(pParam,current, reference, pRefH, pRefV, pRefHV);
         CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x,prevMB->mvs[iSubBlock].y);  
2769    
2770  // 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);  
         }  
2771    
2772  // top neighbour, if allowed  // filter mask of all blocks
2773          if (psad[2] != MV_MAX_ERROR)  
2774            for (my = 0; my < (uint32_t)MBh; my++)
2775            for (mx = 0; mx < (uint32_t)MBw; mx++)
2776          {          {
2777                  if (!(MotionFlags & PMV_HALFPEL8 ))                  const int mbnum = mx + my * MBw;
2778                  {       pmv[2].x = EVEN(pmv[2].x);                          pMBs[mbnum].mcsel = 0;
                         pmv[2].y = EVEN(pmv[2].y);  
2779                  }                  }
                 CHECK_MV8_CANDIDATE(pmv[2].x,pmv[2].y);  
2780    
2781  // top right neighbour, if allowed  
2782                  if (psad[3] != MV_MAX_ERROR)          for (my = 1; my < (uint32_t)MBh-1; my++) /* ignore boundary blocks */
2783            for (mx = 1; mx < (uint32_t)MBw-1; mx++) /* theirs MVs are often wrong */
2784                  {                  {
2785                          if (!(MotionFlags & PMV_HALFPEL8 ))                  const int mbnum = mx + my * MBw;
2786                          {       pmv[3].x = EVEN(pmv[3].x);                  MACROBLOCK *const pMB = &pMBs[mbnum];
2787                                  pmv[3].y = EVEN(pmv[3].y);                  const VECTOR mv = pMB->mvs[0];
2788    
2789                    /* don't use object boundaries */
2790                    if   ( (abs(mv.x -   (pMB-1)->mvs[0].x) < deltax)
2791                            && (abs(mv.y -   (pMB-1)->mvs[0].y) < deltay)
2792                            && (abs(mv.x -   (pMB+1)->mvs[0].x) < deltax)
2793                            && (abs(mv.y -   (pMB+1)->mvs[0].y) < deltay)
2794                            && (abs(mv.x - (pMB-MBw)->mvs[0].x) < deltax)
2795                            && (abs(mv.y - (pMB-MBw)->mvs[0].y) < deltay)
2796                            && (abs(mv.x - (pMB+MBw)->mvs[0].x) < deltax)
2797                            && (abs(mv.y - (pMB+MBw)->mvs[0].y) < deltay) )
2798                    {       const int iEdgedWidth = pParam->edged_width;
2799                            const uint8_t *const pCur = current->image.y + 16*(my*iEdgedWidth + mx);
2800                            if ( (sad16 ( pCur, pCur+1 , iEdgedWidth, 65536) >= gradx )
2801                             &&  (sad16 ( pCur, pCur+iEdgedWidth, iEdgedWidth, 65536) >= grady ) )
2802                             {      pMB->mcsel = 1;
2803                                    num++;
2804                          }                          }
2805                          CHECK_MV8_CANDIDATE(pmv[3].x,pmv[3].y);  
2806                    /* only use "structured" blocks */
2807                  }                  }
2808          }          }
2809            emms();
2810    
2811  /*  // this bias is zero anyway, at the moment!          /*      further filtering would be possible, but during iteration, remaining
2812                    outliers usually are removed, too */
2813    
2814          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)          if (num>= minblocks)
2815                  iMinSAD -= MV8_00_BIAS;          do {            /* until convergence */
2816                    double DtimesF[4];
2817                    double a,b,c,n,invdenom;
2818                    double meanx,meany;
2819    
2820  */                  a = b = c = n = 0;
2821                    DtimesF[0] = DtimesF[1] = DtimesF[2] = DtimesF[3] = 0.;
2822                    for (my = 1; my < (uint32_t)MBh-1; my++)
2823                    for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2824                    {
2825                            const int mbnum = mx + my * MBw;
2826                            const VECTOR mv = pMBs[mbnum].mvs[0];
2827    
2828  /* Terminate if MinSAD <= T_2                          if (!pMBs[mbnum].mcsel)
2829     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]                                  continue;
 */  
2830    
2831          if (iMinSAD < 512/4)    /* T_2 == 512/4 hardcoded */                          n++;
2832                  {                          a += 16*mx+8;
2833                          if (MotionFlags & PMV_QUICKSTOP8)                          b += 16*my+8;
2834                                  goto EPZS8_Terminate_without_Refine;                          c += (16*mx+8)*(16*mx+8)+(16*my+8)*(16*my+8);
2835                          if (MotionFlags & PMV_EARLYSTOP8)  
2836                                  goto EPZS8_Terminate_with_Refine;                          DtimesF[0] += (double)mv.x;
2837                            DtimesF[1] += (double)mv.x*(16*mx+8) + (double)mv.y*(16*my+8);
2838                            DtimesF[2] += (double)mv.x*(16*my+8) - (double)mv.y*(16*mx+8);
2839                            DtimesF[3] += (double)mv.y;
2840                  }                  }
2841    
2842  /************ (Diamond Search)  **************/          invdenom = a*a+b*b-c*n;
2843    
2844          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */  /* Solve the system:    sol = (D'*E*D)^{-1} D'*E*F   */
2845    /* D'*E*F has been calculated in the same loop as matrix */
2846    
2847          if (!(MotionFlags & PMV_HALFPELDIAMOND8))          sol[0] = -c*DtimesF[0] + a*DtimesF[1] + b*DtimesF[2];
2848                  iDiamondSize *= 2;          sol[1] =  a*DtimesF[0] - n*DtimesF[1]                           + b*DtimesF[3];
2849            sol[2] =  b*DtimesF[0]                          - n*DtimesF[2] - a*DtimesF[3];
2850            sol[3] =                                 b*DtimesF[1] - a*DtimesF[2] - c*DtimesF[3];
2851    
2852  /* default: use best prediction as starting point for one call of EPZS_MainSearch */          sol[0] /= invdenom;
2853            sol[1] /= invdenom;
2854            sol[2] /= invdenom;
2855            sol[3] /= invdenom;
2856    
2857            meanx = meany = 0.;
2858            oldnum = 0;
2859            for (my = 1; my < (uint32_t)MBh-1; my++)
2860                    for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2861                    {
2862                            const int mbnum = mx + my * MBw;
2863                            const VECTOR mv = pMBs[mbnum].mvs[0];
2864    
2865  // there is no EPZS^2 for inter4v at the moment                          if (!pMBs[mbnum].mcsel)
2866                                    continue;
2867    
2868  //      if (MotionFlags & PMV_USESQUARES8)                          oldnum++;
2869  //              MainSearchPtr = Square8_MainSearch;                          meanx += fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - (double)mv.x );
2870  //      else                          meany += fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - (double)mv.y );
2871                    }
2872    
2873          if (MotionFlags & PMV_ADVANCEDDIAMOND8)          if (4*meanx > oldnum)   /* better fit than 0.25 (=1/4pel) is useless */
2874                  MainSearchPtr = AdvDiamond8_MainSearch;                  meanx /= oldnum;
2875          else          else
2876                  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);  
2877    
2878            if (4*meany > oldnum)
2879                    meany /= oldnum;
2880            else
2881                    meany = 0.25;
2882    
2883          if (iSAD < iMinSAD)          num = 0;
2884            for (my = 0; my < (uint32_t)MBh; my++)
2885                    for (mx = 0; mx < (uint32_t)MBw; mx++)
2886          {          {
2887                  *currMV = newMV;                          const int mbnum = mx + my * MBw;
2888                  iMinSAD = iSAD;                          const VECTOR mv = pMBs[mbnum].mvs[0];
2889    
2890                            if (!pMBs[mbnum].mcsel)
2891                                    continue;
2892    
2893                            if  ( ( fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - (double)mv.x ) > meanx )
2894                                    || ( fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - (double)mv.y ) > meany ) )
2895                                    pMBs[mbnum].mcsel=0;
2896                            else
2897                                    num++;
2898          }          }
2899    
2900          if (MotionFlags & PMV_EXTSEARCH8)          } while ( (oldnum != num) && (num>= minblocks) );
         {  
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
2901    
2902                  if (!(MVequal(pmv[0],backupMV)) )          if (num < minblocks)
2903                  {                  {
2904                          iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,                  const int iEdgedWidth = pParam->edged_width;
2905                                  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);  
2906    
2907                          if (iSAD < iMinSAD)  /*              fprintf(stderr,"Warning! Unreliable GME (%d/%d blocks), falling back to translation.\n",num,MBh*MBw);
2908                          {  */
2909                                  *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;  
                         }  
                 }  
2910    
2911                  if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )                  if (!(current->motion_flags & XVID_ME_GME_REFINE))
2912                  {                          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);  
2913    
2914                          if (iSAD < iMinSAD)                  for (my = 1; my < (uint32_t)MBh-1; my++) /* ignore boundary blocks */
2915                    for (mx = 1; mx < (uint32_t)MBw-1; mx++) /* theirs MVs are often wrong */
2916                          {                          {
2917                                  *currMV = newMV;                          const int mbnum = mx + my * MBw;
2918                                  iMinSAD = iSAD;                          MACROBLOCK *const pMB = &pMBs[mbnum];
2919                          }                          const uint8_t *const pCur = current->image.y + 16*(my*iEdgedWidth + mx);
2920                            if ( (sad16 ( pCur, pCur+1 , iEdgedWidth, 65536) >= gradx )
2921                             &&  (sad16 ( pCur, pCur+iEdgedWidth, iEdgedWidth, 65536) >= grady ) )
2922                             {      pMB->mcsel = 1;
2923                                    gmc.duv[0].x += pMB->mvs[0].x;
2924                                    gmc.duv[0].y += pMB->mvs[0].y;
2925                                    num++;
2926                  }                  }
2927          }          }
2928    
2929  /***************        Choose best MV found     **************/                  if (gmc.duv[0].x)
2930                            gmc.duv[0].x /= num;
2931                    if (gmc.duv[0].y)
2932                            gmc.duv[0].y /= num;
2933            } else {
2934    
2935  EPZS8_Terminate_with_Refine:                  gmc.duv[0].x=(int)(sol[0]+0.5);
2936          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);  
2937    
2938  EPZS8_Terminate_without_Refine:                  gmc.duv[1].x=(int)(sol[1]*pParam->width+0.5);
2939                    gmc.duv[1].y=(int)(-sol[2]*pParam->width+0.5);
2940    
2941          currPMV->x = currMV->x - pmv[0].x;                  gmc.duv[2].x=-gmc.duv[1].y;             /* two warp points only */
2942          currPMV->y = currMV->y - pmv[0].y;                  gmc.duv[2].y=gmc.duv[1].x;
2943          return iMinSAD;          }
2944            if (num>maxblocks)
2945            {       for (my = 1; my < (uint32_t)MBh-1; my++)
2946                    for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2947                    {
2948                            const int mbnum = mx + my * MBw;
2949                            if (pMBs[mbnum-1].mcsel)
2950                                    pMBs[mbnum].mcsel=0;
2951                            else
2952                                    if (pMBs[mbnum-MBw].mcsel)
2953                                            pMBs[mbnum].mcsel=0;
2954                    }
2955            }
2956            return gmc;
2957  }  }
2958    
2959    int
2960    GlobalMotionEstRefine(
2961                                    WARPPOINTS *const startwp,
2962                                    MACROBLOCK * const pMBs,
2963                                    const MBParam * const pParam,
2964                                    const FRAMEINFO * const current,
2965                                    const FRAMEINFO * const reference,
2966                                    const IMAGE * const pCurr,
2967                                    const IMAGE * const pRef,
2968                                    const IMAGE * const pRefH,
2969                                    const IMAGE * const pRefV,
2970                                    const IMAGE * const pRefHV)
2971    {
2972            uint8_t* GMCblock = (uint8_t*)malloc(16*pParam->edged_width);
2973            WARPPOINTS bestwp=*startwp;
2974            WARPPOINTS centerwp,currwp;
2975            int gmcminSAD=0;
2976            int gmcSAD=0;
2977            int direction;
2978    //      int mx,my;
2979    
2980    /* use many blocks... */
2981    /*              for (my = 0; my < (uint32_t)pParam->mb_height; my++)
2982                    for (mx = 0; mx < (uint32_t)pParam->mb_width; mx++)
2983                    {
2984                            const int mbnum = mx + my * pParam->mb_width;
2985                            pMBs[mbnum].mcsel=1;
2986                    }
2987    */
2988    
2989    /* or rather don't use too many blocks... */
2990    /*
2991                    for (my = 1; my < (uint32_t)MBh-1; my++)
2992                    for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2993                    {
2994                            const int mbnum = mx + my * MBw;
2995                            if (MBmask[mbnum-1])
2996                                    MBmask[mbnum-1]=0;
2997                            else
2998                                    if (MBmask[mbnum-MBw])
2999                                            MBmask[mbnum-1]=0;
3000    
3001                    }
3002    */
3003                    gmcminSAD = globalSAD(&bestwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3004    
3005  /* ***********************************************************                  if ( (reference->coding_type == S_VOP)
3006          bvop motion estimation                          && ( (reference->warp.duv[1].x != bestwp.duv[1].x)
3007  // TODO: need to incorporate prediction here (eg. sad += calc_delta_16)                            || (reference->warp.duv[1].y != bestwp.duv[1].y)
3008  ***************************************************************/                            || (reference->warp.duv[0].x != bestwp.duv[0].x)
3009                              || (reference->warp.duv[0].y != bestwp.duv[0].y)
3010                              || (reference->warp.duv[2].x != bestwp.duv[2].x)
3011  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)  
3012  {  {
3013      const uint32_t mb_width = pParam->mb_width;                          gmcSAD = globalSAD(&reference->warp, pParam, pMBs,
3014      const uint32_t mb_height = pParam->mb_height;                                                                  current, pRef, pCurr, GMCblock);
         const int32_t edged_width = pParam->edged_width;  
3015    
3016          uint32_t i,j;                          if (gmcSAD < gmcminSAD)
3017                            {       bestwp = reference->warp;
3018                                    gmcminSAD = gmcSAD;
3019                            }
3020                    }
3021    
3022          int32_t f_sad16;          do {
3023          int32_t b_sad16;                  direction = 0;
3024          int32_t i_sad16;                  centerwp = bestwp;
         int32_t d_sad16;  
         int32_t best_sad;  
3025    
3026          VECTOR pmv_dontcare;                  currwp = centerwp;
3027    
3028          // note: i==horizontal, j==vertical                  currwp.duv[0].x--;
3029      for (j = 0; j < mb_height; j++)                  gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3030                    if (gmcSAD < gmcminSAD)
3031                    {       bestwp = currwp;
3032                            gmcminSAD = gmcSAD;
3033                            direction = 1;
3034                    }
3035                    else
3036          {          {
3037                  for (i = 0; i < mb_width; i++)                  currwp = centerwp; currwp.duv[0].x++;
3038                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3039                    if (gmcSAD < gmcminSAD)
3040                    {       bestwp = currwp;
3041                            gmcminSAD = gmcSAD;
3042                            direction = 2;
3043                    }
3044                    }
3045                    if (direction) continue;
3046    
3047                    currwp = centerwp; currwp.duv[0].y--;
3048                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3049                    if (gmcSAD < gmcminSAD)
3050                    {       bestwp = currwp;
3051                            gmcminSAD = gmcSAD;
3052                            direction = 4;
3053                    }
3054                    else
3055                  {                  {
3056                          MACROBLOCK *mb = &frame->mbs[i + j*mb_width];                  currwp = centerwp; currwp.duv[0].y++;
3057                          const MACROBLOCK *f_mb = &f_mbs[i + j*mb_width];                  gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3058                          const MACROBLOCK *b_mb = &b_mbs[i + j*mb_width];                  if (gmcSAD < gmcminSAD)
3059                    {       bestwp = currwp;
3060                          if (b_mb->mode == MODE_INTER                          gmcminSAD = gmcSAD;
3061                                  && b_mb->cbp == 0                          direction = 8;
3062                                  && b_mb->mvs[0].x == 0                  }
3063                                  && b_mb->mvs[0].y == 0)                  }
3064                          {                  if (direction) continue;
3065                                  mb->mode = MODE_NOT_CODED;  
3066                                  mb->mvs[0].x = 0;                  currwp = centerwp; currwp.duv[1].x++;
3067                                  mb->mvs[0].y = 0;                  gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3068                                  mb->b_mvs[0].x = 0;                  if (gmcSAD < gmcminSAD)
3069                                  mb->b_mvs[0].y = 0;                  {       bestwp = currwp;
3070                                  continue;                          gmcminSAD = gmcSAD;
3071                            direction = 32;
3072                    }
3073                    currwp.duv[2].y++;
3074                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3075                    if (gmcSAD < gmcminSAD)
3076                    {       bestwp = currwp;
3077                            gmcminSAD = gmcSAD;
3078                            direction = 1024;
3079                    }
3080    
3081                    currwp = centerwp; currwp.duv[1].x--;
3082                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3083                    if (gmcSAD < gmcminSAD)
3084                    {       bestwp = currwp;
3085                            gmcminSAD = gmcSAD;
3086                            direction = 16;
3087                          }                          }
3088                    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)  
3089                          {                          {
3090                                  best_sad = f_sad16;                  currwp = centerwp; currwp.duv[1].x++;
3091                                  mb->mode = MODE_FORWARD;                  gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3092                    if (gmcSAD < gmcminSAD)
3093                    {       bestwp = currwp;
3094                            gmcminSAD = gmcSAD;
3095                            direction = 32;
3096                    }
3097                    }
3098                    if (direction) continue;
3099    
3100    
3101                    currwp = centerwp; currwp.duv[1].y--;
3102                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3103                    if (gmcSAD < gmcminSAD)
3104                    {       bestwp = currwp;
3105                            gmcminSAD = gmcSAD;
3106                            direction = 64;
3107                          }                          }
3108                          else                          else
3109                          {                          {
3110                                  best_sad = b_sad16;                  currwp = centerwp; currwp.duv[1].y++;
3111                                  mb->mode = MODE_BACKWARD;                  gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3112                    if (gmcSAD < gmcminSAD)
3113                    {       bestwp = currwp;
3114                            gmcminSAD = gmcSAD;
3115                            direction = 128;
3116                    }
3117                    }
3118                    if (direction) continue;
3119    
3120                    currwp = centerwp; currwp.duv[2].x--;
3121                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3122                    if (gmcSAD < gmcminSAD)
3123                    {       bestwp = currwp;
3124                            gmcminSAD = gmcSAD;
3125                            direction = 256;
3126                          }                          }
3127                    else
                         if (i_sad16 < best_sad)  
3128                          {                          {
3129                                  best_sad = i_sad16;                  currwp = centerwp; currwp.duv[2].x++;
3130                                  mb->mode = MODE_INTERPOLATE;                  gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3131                    if (gmcSAD < gmcminSAD)
3132                    {       bestwp = currwp;
3133                            gmcminSAD = gmcSAD;
3134                            direction = 512;
3135                    }
3136                    }
3137                    if (direction) continue;
3138    
3139                    currwp = centerwp; currwp.duv[2].y--;
3140                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3141                    if (gmcSAD < gmcminSAD)
3142                    {       bestwp = currwp;
3143                            gmcminSAD = gmcSAD;
3144                            direction = 1024;
3145                          }                          }
3146                    else
                         if (d_sad16 < best_sad)  
3147                          {                          {
3148                                  best_sad = d_sad16;                  currwp = centerwp; currwp.duv[2].y++;
3149                                  mb->mode = MODE_DIRECT;                  gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3150                    if (gmcSAD < gmcminSAD)
3151                    {       bestwp = currwp;
3152                            gmcminSAD = gmcSAD;
3153                            direction = 2048;
3154                    }
3155                          }                          }
3156            } while (direction);
3157            free(GMCblock);
3158    
3159            *startwp = bestwp;
3160    
3161            return gmcminSAD;
3162                  }                  }
3163    
3164    int
3165    globalSAD(const WARPPOINTS *const wp,
3166                      const MBParam * const pParam,
3167                      const MACROBLOCK * const pMBs,
3168                      const FRAMEINFO * const current,
3169                      const IMAGE * const pRef,
3170                      const IMAGE * const pCurr,
3171                      uint8_t *const GMCblock)
3172    {
3173            NEW_GMC_DATA gmc_data;
3174            int iSAD, gmcSAD=0;
3175            int num=0;
3176            unsigned int mx, my;
3177    
3178            generate_GMCparameters( 3, 3, wp, pParam->width, pParam->height, &gmc_data);
3179    
3180            for (my = 0; my < (uint32_t)pParam->mb_height; my++)
3181                    for (mx = 0; mx < (uint32_t)pParam->mb_width; mx++) {
3182    
3183                    const int mbnum = mx + my * pParam->mb_width;
3184                    const int iEdgedWidth = pParam->edged_width;
3185    
3186                    if (!pMBs[mbnum].mcsel)
3187                            continue;
3188    
3189                    gmc_data.predict_16x16(&gmc_data, GMCblock,
3190                                                    pRef->y,
3191                                                    iEdgedWidth,
3192                                                    iEdgedWidth,
3193                                                    mx, my,
3194                                                    pParam->m_rounding_type);
3195    
3196                    iSAD = sad16 ( pCurr->y + 16*(my*iEdgedWidth + mx),
3197                                                    GMCblock , iEdgedWidth, 65536);
3198                    iSAD -= pMBs[mbnum].sad16;
3199    
3200                    if (iSAD<0)
3201                            gmcSAD += iSAD;
3202                    num++;
3203          }          }
3204            return gmcSAD;
3205  }  }
3206    

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

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