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

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

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