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

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

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