[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 3, Fri Mar 8 02:46:11 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   *  08.02.2002 split up PMVfast into three routines: PMVFast, PMVFast_MainLoop   *  Copyright(C) 2002 Christoph Lampert <gruel@web.de>
7   *             PMVFast_Refine to support multiple searches with different start points   *               2002 Michael Militzer <michael@xvid.org>
8   *      07.01.2002 uv-block-based interpolation   *               2002-2003 Radoslaw Czyz <xvid@syskin.cjb.net>
  *  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>
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"
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            offset = (bx>>1) + (by>>1)*stride;
135            filter = ((bx & 1) << 1) | (by & 1);
136    
137            if (filter != 0) {
138                    b_refu = data->RefQ + 16;
139                    b_refv = data->RefQ + 24;
140                    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            sad = sad8bi(data->CurU, b_refu, f_refu, stride);
148            sad += sad8bi(data->CurV, b_refv, f_refv, stride);
149    
150            return sad;
151    }
152    
153    static int32_t
154    ChromaSAD(const int dx, const int dy, const SearchData * const data)
155    {
156            int sad;
157            const uint32_t stride = data->iEdgedWidth/2;
158            int offset = (dx>>1) + (dy>>1)*stride;
159    
160            if (dx == data->temp[5] && dy == data->temp[6]) return data->temp[7]; /* it has been checked recently */
161            data->temp[5] = dx; data->temp[6] = dy; /* backup */
162    
163            switch (((dx & 1) << 1) | (dy & 1))     {
164                    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  /* sad16(0,0) bias; mpeg4 spec suggests nb/2+1 */                          interpolate8x8_halfpel_hv(data->RefQ, data->RefP[5] + offset, stride, data->rounding);
181  /* nb  = vop pixels * 2^(bpp-8) */                          sad += sad8(data->CurV, data->RefQ, stride);
182  #define MV16_00_BIAS    (128+1)                          break;
183            }
184            data->temp[7] = sad; /* backup, part 2 */
185            return sad;
186    }
187    
188    static __inline const uint8_t *
189    GetReferenceB(const int x, const int y, const uint32_t dir, const SearchData * const data)
190    {
191            /* dir : 0 = forward, 1 = backward */
192            const uint8_t *const *const direction = ( dir == 0 ? data->RefP : data->b_RefP );
193            const int picture = ((x&1)<<1) | (y&1);
194            const int offset = (x>>1) + (y>>1)*data->iEdgedWidth;
195            return direction[picture] + offset;
196    }
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    static uint8_t *
208    Interpolate8x8qpel(const int x, const int y, const uint32_t block, const uint32_t dir, const SearchData * const data)
209    {
210            /* create or find a qpel-precision reference picture; return pointer to it */
211            uint8_t * Reference = data->RefQ + 16*dir;
212            const uint32_t iEdgedWidth = data->iEdgedWidth;
213            const uint32_t rounding = data->rounding;
214            const int halfpel_x = x/2;
215            const int halfpel_y = y/2;
216            const uint8_t *ref1, *ref2, *ref3, *ref4;
217    
218            ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
219            ref1 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
220            switch( ((x&1)<<1) + (y&1) ) {
221            case 3: /* x and y in qpel resolution - the "corners" (top left/right and */
222                            /* bottom left/right) during qpel refinement */
223                    ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
224                    ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
225                    ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);
226                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
227                    ref3 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
228                    ref4 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
229                    interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
230                    break;
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            case 2: /* x qpel, y halfpel - left or right during qpel refinement */
239                    ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
240                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
241                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
242                    break;
243    
244            default: /* pure halfpel position */
245                    return (uint8_t *) ref1;
246    
247            }
248            return Reference;
249    }
250    
251    static uint8_t *
252    Interpolate16x16qpel(const int x, const int y, const uint32_t dir, const SearchData * const data)
253    {
254            /* create or find a qpel-precision reference picture; return pointer to it */
255            uint8_t * Reference = data->RefQ + 16*dir;
256            const uint32_t iEdgedWidth = data->iEdgedWidth;
257            const uint32_t rounding = data->rounding;
258            const int halfpel_x = x/2;
259            const int halfpel_y = y/2;
260            const uint8_t *ref1, *ref2, *ref3, *ref4;
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  /* INTER bias for INTER/INTRA decision; mpeg4 spec suggests 2*nb */          case 1: /* x halfpel, y qpel - top or bottom during qpel refinement */
279  #define INTER_BIAS      512                  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  /* Parameters which control inter/inter4v decision */          case 2: /* x qpel, y halfpel - left or right during qpel refinement */
287  #define IMV16X16                        5                  ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
288                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
289                    interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
290                    interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
291                    interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
292                    break;
293    
 /* vector map (vlc delta size) smoother parameters */  
 #define NEIGH_TEND_16X16        2  
 #define NEIGH_TEND_8X8          2  
294    
295            default: /* pure halfpel position */
296                    return (uint8_t *) ref1;
297            }
298            return Reference;
299    }
300    
301  // fast ((A)/2)*2  /* CHECK_CANDIATE FUNCTIONS START */
 #define EVEN(A)         (((A)<0?(A)+1:(A)) & ~1)  
302    
303    static void
304    CheckCandidate16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
305    {
306            int xc, yc;
307            const uint8_t * Reference;
308            VECTOR * current;
309            int32_t sad; uint32_t t;
310    
311  #define MIN(X, Y) ((X)<(Y)?(X):(Y))          if ( (x > data->max_dx) || (x < data->min_dx)
312  #define MAX(X, Y) ((X)>(Y)?(X):(Y))                  || (y > data->max_dy) || (y < data->min_dy) ) return;
 #define ABS(X) (((X)>0)?(X):-(X))  
 #define SIGN(X) (((X)>0)?1:-1)  
313    
314            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  int32_t PMVfastSearch8(          sad = sad16v(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
325                                          const uint8_t * const pRef,          t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
                                         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, int start_y,  
                                         const uint32_t iQuality,  
                                         MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV);  
326    
327  int32_t PMVfastSearch16(          sad += (data->lambda16 * t * sad)>>10;
328                                          const uint8_t * const pRef,          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;
                                         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 iQuality,  
                                         MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV);  
329    
330            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  /* diamond search stuff          if (data->temp[1] < data->iMinSAD[1]) {
341     keep the the sequence in circular order (so optimization works)                  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  typedef struct  static void
351    CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
352  {  {
353          int32_t dx;          int32_t sad; uint32_t t;
354          int32_t dy;          const uint8_t * Reference;
355            VECTOR * current;
356    
357            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                    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  }  }
 DPOINT;  
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  static const DPOINT diamond_small[4] =          sad += (data->lambda8 * t * (sad+NEIGH_8X8_BIAS))>>10;
 {  
         {0, 1}, {1, 0}, {0, -1}, {-1, 0}  
 };  
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 const DPOINT diamond_large[8] =  static void
381    CheckCandidate32(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
382  {  {
383          {0, 2}, {1, 1}, {2, 0}, {1, -1}, {0, -2}, {-1, -1}, {-2, 0}, {-1, 1}          uint32_t t;
384  };          const uint8_t * Reference;
   
385    
386  // mv.length table          if ( (!(x&1) && x !=0) || (!(y&1) && y !=0) || /* non-zero even value */
387  static const uint32_t mvtab[33] = {                  (x > data->max_dx) || (x < data->min_dx)
388      1,  2,  3,  4,  6,  7,  7,  7,                  || (y > data->max_dy) || (y < data->min_dy) ) return;
     9,  9,  9,  10, 10, 10, 10, 10,  
     10, 10, 10, 10, 10, 10, 10, 10,  
     10, 11, 11, 11, 11, 11, 11, 12, 12  
 };  
389    
390            Reference = GetReference(x, y, data);
391            t = d_mv_bits(x, y, data->predMV, data->iFcode, 0, 1);
392    
393  static __inline uint32_t mv_bits(int32_t component, const uint32_t iFcode)          data->temp[0] = sad32v_c(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
 {  
     if (component == 0)  
                 return 1;  
394    
395      if (component < 0)          data->temp[0] += (data->lambda16 * t * data->temp[0]) >> 10;
396                  component = -component;          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;
397    
398      if (iFcode == 1)          if (data->temp[0] < data->iMinSAD[0]) {
399      {                  data->iMinSAD[0] = data->temp[0];
400                  if (component > 32)                  data->currentMV[0].x = x; data->currentMV[0].y = y;
401                      component = 32;                  *dir = Direction; }
402    
403                  return mvtab[component] + 1;          if (data->temp[1] < data->iMinSAD[1]) {
404                    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      component += (1 << (iFcode - 1)) - 1;  static void
414      component >>= (iFcode - 1);  CheckCandidate16no4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
415    {
416            int32_t sad, xc, yc;
417            const uint8_t * Reference;
418            uint32_t t;
419            VECTOR * current;
420    
421            if ( (x > data->max_dx) || ( x < data->min_dx)
422                    || (y > data->max_dy) || (y < data->min_dy) ) return;
423    
424      if (component > 32)          if (data->rrv && (!(x&1) && x !=0) | (!(y&1) && y !=0) ) return; /* non-zero even value */
                 component = 32;  
425    
426      return mvtab[component] + 1 + iFcode - 1;          if (data->qpel_precision) { /* x and y are in 1/4 precision */
427                    Reference = Interpolate16x16qpel(x, y, 0, data);
428                    current = data->currentQMV;
429                    xc = x/2; yc = y/2;
430            } 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            sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
439            sad += (data->lambda16 * t * sad)>>10;
440    
441  static __inline uint32_t calc_delta_16(const int32_t dx, const int32_t dy, const uint32_t iFcode)          if (data->chroma && sad < *data->iMinSAD)
442  {                  sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
443          return NEIGH_TEND_16X16 * (mv_bits(dx, iFcode) + mv_bits(dy, iFcode));                                                          (yc >> 1) + roundtab_79[yc & 0x3], data);
 }  
444    
445  static __inline uint32_t calc_delta_8(const int32_t dx, const int32_t dy, const uint32_t iFcode)          if (sad < *(data->iMinSAD)) {
446                    *(data->iMinSAD) = sad;
447                    current->x = x; current->y = y;
448                    *dir = Direction;
449            }
450    }
451    
452    static void
453    CheckCandidate16I(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
454  {  {
455      return NEIGH_TEND_8X8 * (mv_bits(dx, iFcode) + mv_bits(dy, iFcode));          int sad;
456  }  //      int xc, yc;
457            const uint8_t * Reference;
458    //      VECTOR * current;
459    
460            if ( (x > data->max_dx) || ( x < data->min_dx)
461                    || (y > data->max_dy) || (y < data->min_dy) ) return;
462    
463            Reference = GetReference(x, y, data);
464    //      xc = x; yc = y;
465    
466            sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
467    //      sad += d_mv_bits(x, y, data->predMV, data->iFcode, 0, 0);
468    
469  /* calculate the min/max range (in halfpixels)  /*      if (data->chroma) sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
470          relative to the _MACROBLOCK_ position                                                                                  (yc >> 1) + roundtab_79[yc & 0x3], data);
471  */  */
472    
473  static void __inline get_range(          if (sad < data->iMinSAD[0]) {
474                          int32_t * const min_dx, int32_t * const max_dx,                  data->iMinSAD[0] = sad;
475                          int32_t * const min_dy, int32_t * const max_dy,                  data->currentMV[0].x = x; data->currentMV[0].y = y;
476                          const uint32_t x, const uint32_t y,                  *dir = Direction;
477                          const uint32_t block_sz,                                        // block dimension, 8 or 16          }
                         const uint32_t width, const uint32_t height,  
                         const uint32_t fcode)  
 {  
         const int search_range = 32 << (fcode - 1);  
     const int high = search_range - 1;  
     const int low = -search_range;  
   
         // convert full-pixel measurements to half pixel  
         const int hp_width = 2 * width;  
         const int hp_height = 2 * height;  
         const int hp_edge = 2 * block_sz;  
         const int hp_x = 2 * (x) * block_sz;            // we need _right end_ of block, not x-coordinate  
         const int hp_y = 2 * (y) * block_sz;            // same for _bottom end_  
   
     *max_dx = MIN(high, hp_width - hp_x);  
     *max_dy = MIN(high, hp_height - hp_y);  
     *min_dx = MAX(low,  -(hp_edge + hp_x));  
     *min_dy = MAX(low,  -(hp_edge + hp_y));  
478  }  }
479    
480    static void
481    CheckCandidate32I(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
482    {
483            /* maximum speed - for P/B/I decision */
484            int32_t sad;
485    
486  /* getref: calculate reference image pointer          if ( (x > data->max_dx) || (x < data->min_dx)
487  the decision to use interpolation h/v/hv or the normal image is                  || (y > data->max_dy) || (y < data->min_dy) ) return;
 based on dx & dy.  
 */  
488    
489  static __inline const uint8_t * get_ref(          sad = sad32v_c(data->Cur, data->RefP[0] + (x>>1) + (y>>1)*((int)data->iEdgedWidth),
490                                  const uint8_t * const refn,                                          data->iEdgedWidth, data->temp+1);
491                                  const uint8_t * const refh,  
492                                  const uint8_t * const refv,          if (sad < *(data->iMinSAD)) {
493                                  const uint8_t * const refhv,                  *(data->iMinSAD) = sad;
494                                  const uint32_t x, const uint32_t y,                  data->currentMV[0].x = x; data->currentMV[0].y = y;
495                                  const uint32_t block,                                   // block dimension, 8 or 16                  *dir = Direction;
                                 const int32_t dx, const int32_t dy,  
                                 const uint32_t stride)  
 {  
         switch ( ((dx&1)<<1) + (dy&1) )         // ((dx%2)?2:0)+((dy%2)?1:0)  
     {  
         case 0 : return refn + (x*block+dx/2) + (y*block+dy/2)*stride;  
     case 1 : return refv + (x*block+dx/2) + (y*block+(dy-1)/2)*stride;  
         case 2 : return refh + (x*block+(dx-1)/2) + (y*block+dy/2)*stride;  
         default :  
         case 3 : return refhv + (x*block+(dx-1)/2) + (y*block+(dy-1)/2)*stride;  
496          }          }
497            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    
506  }  }
507    
508    static void
509    CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)
510    {
511            int32_t sad, xb, yb, xcf, ycf, xcb, ycb;
512            uint32_t t;
513            const uint8_t *ReferenceF, *ReferenceB;
514            VECTOR *current;
515    
516  /* This is somehow a copy of get_ref, but with MV instead of X,Y */          if ((xf > data->max_dx) || (xf < data->min_dx) ||
517                    (yf > data->max_dy) || (yf < data->min_dy))
518                    return;
519    
520  static __inline const uint8_t * get_ref_mv(          if (!data->qpel_precision) {
521                                  const uint8_t * const refn,                  ReferenceF = GetReference(xf, yf, data);
522                                  const uint8_t * const refh,                  xb = data->currentMV[1].x; yb = data->currentMV[1].y;
523                                  const uint8_t * const refv,                  ReferenceB = GetReferenceB(xb, yb, 1, data);
524                                  const uint8_t * const refhv,                  current = data->currentMV;
525                                  const uint32_t x, const uint32_t y,                  xcf = xf; ycf = yf;
526                                  const uint32_t block,                   // block dimension, 8 or 16                  xcb = xb; ycb = yb;
527                                  const VECTOR* mv,       // measured in half-pel!          } else {
528                                  const uint32_t stride)                  ReferenceF = Interpolate16x16qpel(xf, yf, 0, data);
529  {                  xb = data->currentQMV[1].x; yb = data->currentQMV[1].y;
530          switch ( (((mv->x)&1)<<1) + ((mv->y)&1) )                  current = data->currentQMV;
531      {                  ReferenceB = Interpolate16x16qpel(xb, yb, 1, data);
532          case 0 : return refn + (x*block+(mv->x)/2) + (y*block+(mv->y)/2)*stride;                  xcf = xf/2; ycf = yf/2;
533          case 1 : return refv + (x*block+(mv->x)/2) + (y*block+((mv->y)-1)/2)*stride;                  xcb = xb/2; ycb = yb/2;
         case 2 : return refh + (x*block+((mv->x)-1)/2) + (y*block+(mv->y)/2)*stride;  
         default :  
         case 3 : return refhv + (x*block+((mv->x)-1)/2) + (y*block+((mv->y)-1)/2)*stride;  
         }  
534  }  }
535    
536  #ifndef SEARCH16          t = d_mv_bits(xf, yf, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0)
537  #define SEARCH16        PMVfastSearch16                   + d_mv_bits(xb, yb, data->bpredMV, data->iFcode, data->qpel^data->qpel_precision, 0);
 #endif  
538    
539  #ifndef SEARCH8          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
540  #define SEARCH8         PMVfastSearch8          sad += (data->lambda16 * t * sad)>>10;
 #endif  
541    
542  bool MotionEstimation(          if (data->chroma && sad < *data->iMinSAD)
543                          MACROBLOCK * const pMBs,                  sad += ChromaSAD2((xcf >> 1) + roundtab_79[xcf & 0x3],
544                          MBParam * const pParam,                                                          (ycf >> 1) + roundtab_79[ycf & 0x3],
545                      const IMAGE * const pRef,                                                          (xcb >> 1) + roundtab_79[xcb & 0x3],
546                          const IMAGE * const pRefH,                                                          (ycb >> 1) + roundtab_79[ycb & 0x3], data);
                     const IMAGE * const pRefV,  
                         const IMAGE * const pRefHV,  
                     IMAGE * const pCurrent,  
                         const uint32_t iLimit)  
547    
548  {          if (sad < *(data->iMinSAD)) {
549      const uint32_t iWcount = pParam->mb_width;                  *(data->iMinSAD) = sad;
550      const uint32_t iHcount = pParam->mb_height;                  current->x = xf; current->y = yf;
551                    *dir = Direction;
552            }
553    }
554    
555          uint32_t i, j, iIntra = 0;  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      VECTOR mv16;          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
     VECTOR pmv16;  
565    
566      int32_t sad8 = 0;          for (k = 0; k < 4; k++) {
567      int32_t sad16;                  mvs.x = data->directmvF[k].x + x;
568      int32_t deviation;                  b_mvs.x = ((x == 0) ?
569                            data->directmvB[k].x
570                            : mvs.x - data->referencemv[k].x);
571    
572          // note: i==horizontal, j==vertical                  mvs.y = data->directmvF[k].y + y;
573      for (i = 0; i < iHcount; i++)                  b_mvs.y = ((y == 0) ?
574                  for (j = 0; j < iWcount; j++)                          data->directmvB[k].y
575                  {                          : mvs.y - data->referencemv[k].y);
                         MACROBLOCK *pMB = &pMBs[j + i * iWcount];  
576    
577                          sad16 = SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,                  if ((mvs.x > data->max_dx)   || (mvs.x < data->min_dx)   ||
578                                            j, i, pParam->motion_flags,                          (mvs.y > data->max_dy)   || (mvs.y < data->min_dy)   ||
579                                            pParam, pMBs, &mv16, &pmv16);                          (b_mvs.x > data->max_dx) || (b_mvs.x < data->min_dx) ||
580                          pMB->sad16=sad16;                          (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                  /* decide: MODE_INTER or MODE_INTRA                  ReferenceF = Interpolate8x8qpel(mvs.x, mvs.y, k, 0, data);
594                          if (dev_intra < sad_inter - 2 * nb) use_intra                  ReferenceB = Interpolate8x8qpel(b_mvs.x, b_mvs.y, k, 1, data);
                 */  
595    
596                  deviation = dev16(pCurrent->y + j*16 + i*16*pParam->edged_width, pParam->edged_width);                  sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
597                                                    ReferenceF, ReferenceB, data->iEdgedWidth);
598                    if (sad > *(data->iMinSAD)) return;
599            }
600    
601                  if (deviation < (sad16 - INTER_BIAS))          sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;
                 {  
                         pMB->mode = MODE_INTRA;  
                         pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = 0;  
                         pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = 0;  
602    
603                          iIntra++;          if (data->chroma && sad < *data->iMinSAD)
604                          if(iIntra >= iLimit)                  sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],
605                                  return 1;                                                          (ycf >> 3) + roundtab_76[ycf & 0xf],
606                                                            (xcb >> 3) + roundtab_76[xcb & 0xf],
607                                                            (ycb >> 3) + roundtab_76[ycb & 0xf], data);
608    
609                          continue;          if (sad < *(data->iMinSAD)) {
610                    *(data->iMinSAD) = sad;
611                    data->currentMV->x = x; data->currentMV->y = y;
612                    *dir = Direction;
613            }
614                  }                  }
615    
616                  if (pParam->global_flags & XVID_INTER4V)  static void
617    CheckCandidateDirectno4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
618                  {                  {
619                          pMB->sad8[0] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,          int32_t sad, xcf, ycf, xcb, ycb;
620                                          2 * j, 2 * i, mv16.x, mv16.y, pParam->motion_flags,          const uint8_t *ReferenceF;
621                                          pParam, pMBs, &pMB->mvs[0], &pMB->pmvs[0]);          const uint8_t *ReferenceB;
622            VECTOR mvs, b_mvs;
623    
624                          pMB->sad8[1] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
                                         2 * j + 1, 2 * i, mv16.x, mv16.y, pParam->motion_flags,  
                                         pParam, pMBs, &pMB->mvs[1], &pMB->pmvs[1]);  
625    
626                          pMB->sad8[2] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,          mvs.x = data->directmvF[0].x + x;
627                                          2 * j, 2 * i + 1, mv16.x, mv16.y, pParam->motion_flags,          b_mvs.x = ((x == 0) ?
628                                          pParam, pMBs, &pMB->mvs[2], &pMB->pmvs[2]);                  data->directmvB[0].x
629                    : mvs.x - data->referencemv[0].x);
630    
631                          pMB->sad8[3] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,          mvs.y = data->directmvF[0].y + y;
632                                          2 * j + 1, 2 * i + 1, mv16.x, mv16.y, pParam->motion_flags,          b_mvs.y = ((y == 0) ?
633                                          pParam, pMBs, &pMB->mvs[3], &pMB->pmvs[3]);                  data->directmvB[0].y
634                    : mvs.y - data->referencemv[0].y);
635    
636                          sad8 = pMB->sad8[0] + pMB->sad8[1] + pMB->sad8[2] + pMB->sad8[3];          if ( (mvs.x > data->max_dx) || (mvs.x < data->min_dx)
637                  }                  || (mvs.y > data->max_dy) || (mvs.y < data->min_dy)
638                    || (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            if (data->qpel) {
642                    xcf = 4*(mvs.x/2); ycf = 4*(mvs.y/2);
643                    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                  /* decide: MODE_INTER or MODE_INTER4V          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
654                          mpeg4:   if (sad8 < sad16 - nb/2+1) use_inter4v          sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;
                 */  
655    
656                  if (pMB->dquant == NO_CHANGE) {          if (data->chroma && sad < *data->iMinSAD)
657                          if (((pParam->global_flags & XVID_INTER4V)==0) ||                  sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],
658                                  (sad16 < (sad8 + (int32_t)(IMV16X16 * pParam->quant)))) {                                                          (ycf >> 3) + roundtab_76[ycf & 0xf],
659                                                            (xcb >> 3) + roundtab_76[xcb & 0xf],
660                                                            (ycb >> 3) + roundtab_76[ycb & 0xf], data);
661    
662                                  sad8 = sad16;          if (sad < *(data->iMinSAD)) {
663                                  pMB->mode = MODE_INTER;                  *(data->iMinSAD) = sad;
664                                  pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = mv16.x;                  data->currentMV->x = x; data->currentMV->y = y;
665                                  pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = mv16.y;                  *dir = Direction;
                                 pMB->pmvs[0].x = pmv16.x;  
                                 pMB->pmvs[0].y = pmv16.y;  
666                          }                          }
                         else  
                                 pMB->mode = MODE_INTER4V;  
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                          sad8 = sad16;  
674                          pMB->mode = MODE_INTER;          int16_t *in = data->dctSpace, *coeff = data->dctSpace + 64;
675                          pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = mv16.x;          int32_t rd = 0;
676                          pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = mv16.y;          VECTOR * current;
677                          pMB->pmvs[0].x = pmv16.x;          const uint8_t * ptr;
678                          pMB->pmvs[0].y = pmv16.y;          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    
693          return 0;          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  #define MVzero(A) ( ((A).x)==(0) && ((A).y)==(0) )          rd += t = BITS_MULT*d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
700    
701  #define MVequal(A,B) ( ((A).x)==((B).x) && ((A).y)==((B).y) )          if (data->temp[0] + t < data->iMinSAD[1]) {
702                    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            if (data->temp[1] < data->iMinSAD[2]) {
704                    data->iMinSAD[2] = data->temp[1]; current[2].x = x; current[2].y = y; data->cbp[1] = (data->cbp[1]&~16) | (cbp&16); }
705            if (data->temp[2] < data->iMinSAD[3]) {
706                    data->iMinSAD[3] = data->temp[2]; current[3].x = x; current[3].y = y; data->cbp[1] = (data->cbp[1]&~8) | (cbp&8); }
707            if (data->temp[3] < data->iMinSAD[4]) {
708                    data->iMinSAD[4] = data->temp[3]; current[4].x = x; current[4].y = y; data->cbp[1] = (data->cbp[1]&~4) | (cbp&4); }
709    
710            rd += BITS_MULT*xvid_cbpy_tab[15-(cbp>>2)].len;
711    
712  #define CHECK_MV16_ZERO {\          if (rd >= data->iMinSAD[0]) return;
   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 <= iQuant * 96)    \  
         iSAD -= MV16_00_BIAS; \  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=0; currMV->y=0; }  }     \  
 }  
   
   
 #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 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; } } \  
 }  
713    
714  /* too slow and not fully functional at the moment */          /* chroma */
715  /*          xc = (xc >> 1) + roundtab_79[xc & 0x3];
716  int32_t ZeroSearch16(          yc = (yc >> 1) + roundtab_79[yc & 0x3];
                                         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,  
                                         MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
 {  
         const int32_t iEdgedWidth = pParam->edged_width;  
         const int32_t iQuant = pParam->quant;  
         const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;  
         int32_t iSAD;  
         int32_t pred_x,pred_y;  
   
         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;  
717    
718          return iSAD;          /* chroma U */
719            ptr = interpolate8x8_switch2(data->RefQ, data->RefP[4], 0, 0, xc, yc, data->iEdgedWidth/2, data->rounding);
720            transfer_8to16subro(in, data->CurU, ptr, data->iEdgedWidth/2);
721            rd += Block_CalcBits(coeff, in, data->dctSpace + 128, data->iQuant, data->quant_type, &cbp, 4);
722            if (rd >= data->iMinSAD[0]) return;
723    
724  }          /* chroma V */
725  */          ptr = interpolate8x8_switch2(data->RefQ, data->RefP[5], 0, 0, xc, yc, data->iEdgedWidth/2, data->rounding);
726            transfer_8to16subro(in, data->CurV, ptr, data->iEdgedWidth/2);
727            rd += Block_CalcBits(coeff, in, data->dctSpace + 128, data->iQuant, data->quant_type, &cbp, 5);
728    
729  int32_t PMVfastSearch16_MainSearch(          rd += BITS_MULT*mcbpc_inter_tab[(MODE_INTER & 7) | ((cbp & 3) << 3)].len;
730                                          const uint8_t * const pRef,  
731                                          const uint8_t * const pRefH,          if (rd < data->iMinSAD[0]) {
732                                          const uint8_t * const pRefV,                  data->iMinSAD[0] = rd;
733                                          const uint8_t * const pRefHV,                  current[0].x = x; current[0].y = y;
734                                          const uint8_t * const cur,                  *dir = Direction;
735                                          const int x, const int y,                  *data->cbp = cbp;
                                         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_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);  
736                  }                  }
         else  
                 {  
                         currMV->x = startx;  
                         currMV->y = starty;  
737                  }                  }
738          return iMinSAD;  
739    static void
740    CheckCandidateRD8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
741    {
742    
743            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            if ( (x > data->max_dx) || (x < data->min_dx)
750                    || (y > data->max_dy) || (y < data->min_dy) ) return;
751    
752            if (!data->qpel_precision) {
753                    ptr = GetReference(x, y, data);
754                    current = data->currentMV;
755            } else { /* x and y are in 1/4 precision */
756                    ptr = Interpolate8x8qpel(x, y, 0, 0, data);
757                    current = data->currentQMV;
758  }  }
759    
760  int32_t PMVfastSearch16_Refine(          transfer_8to16subro(in, data->Cur, ptr, data->iEdgedWidth);
761                                          const uint8_t * const pRef,          rd = Block_CalcBits(coeff, in, data->dctSpace + 128, data->iQuant, data->quant_type, &cbp, 5);
762                                          const uint8_t * const pRefH,          rd += BITS_MULT*d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x, const int y,  
                                         VECTOR * const currMV,  
                                         int32_t iMinSAD,  
                                         const VECTOR * const pmv,  
                                         const int32_t min_dx, const int32_t max_dx,  
                                         const int32_t min_dy, const int32_t max_dy,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         const int32_t iEdgedWidth)  
 {  
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
   
         int32_t iSAD;  
         VECTOR backupMV = *currMV;  
   
         CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y-1);  
         CHECK_MV16_CANDIDATE(backupMV.x  ,backupMV.y-1);  
         CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y-1);  
         CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y+1);  
         CHECK_MV16_CANDIDATE(backupMV.x  ,backupMV.y+1);  
         CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y+1);  
763    
764          return iMinSAD;          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  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)  /* CHECK_CANDIATE FUNCTIONS END */
773    
774  int32_t PMVfastSearch16(  /* MAINSEARCH FUNCTIONS START */
775                                          const uint8_t * const pRef,  
776                                          const uint8_t * const pRefH,  static void
777                                          const uint8_t * const pRefV,  AdvDiamondSearch(int x, int y, const SearchData * const data, int bDirection)
                                         const uint8_t * const pRefHV,  
                                         const IMAGE * const pCur,  
                                         const int x, const int y,  
                                         const uint32_t MotionFlags,  
                                         MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
778  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iFcode = pParam->fixed_code;  
         const int32_t iQuant = pParam->quant;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
779    
780          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
781    
782          int32_t iDiamondSize;          int iDirection;
783    
784          int32_t min_dx;          for(;;) { /* forever */
785          int32_t max_dx;                  iDirection = 0;
786          int32_t min_dy;                  if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
787          int32_t max_dy;                  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          int32_t iFound;                  /* now we're doing diagonal checks near our candidate */
792    
793          VECTOR newMV;                  if (iDirection) {               /* if anything found */
794          VECTOR backupMV;        /* just for PMVFAST */                          bDirection = iDirection;
795                            iDirection = 0;
796                            x = data->currentMV->x; y = data->currentMV->y;
797                            if (bDirection & 3) {   /* our candidate is left or right */
798                                    CHECK_CANDIDATE(x, y + iDiamondSize, 8);
799                                    CHECK_CANDIDATE(x, y - iDiamondSize, 4);
800                            } else {                        /* what remains here is up or down */
801                                    CHECK_CANDIDATE(x + iDiamondSize, y, 2);
802                                    CHECK_CANDIDATE(x - iDiamondSize, y, 1);
803                            }
804    
805          VECTOR pmv[4];                          if (iDirection) {
806          int32_t psad[4];                                  bDirection += iDirection;
807                                    x = data->currentMV->x; y = data->currentMV->y;
808                            }
809                    } else {                                /* about to quit, eh? not so fast.... */
810                            switch (bDirection) {
811                            case 2:
812                                    CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
813                                    CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
814                                    break;
815                            case 1:
816                                    CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
817                                    CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
818                                    break;
819                            case 2 + 4:
820                                    CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
821                                    CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
822                                    CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
823                                    break;
824                            case 4:
825                                    CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
826                                    CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
827                                    break;
828                            case 8:
829                                    CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
830                                    CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
831                                    break;
832                            case 1 + 4:
833                                    CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
834                                    CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
835                                    CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
836                                    break;
837                            case 2 + 8:
838                                    CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
839                                    CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
840                                    CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
841                                    break;
842                            case 1 + 8:
843                                    CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
844                                    CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
845                                    CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
846                                    break;
847                            default:                /* 1+2+4+8 == we didn't find anything at all */
848                                    CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
849                                    CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
850                                    CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
851                                    CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
852                                    break;
853                            }
854                            if (!iDirection) break;         /* ok, the end. really */
855                            bDirection = iDirection;
856                            x = data->currentMV->x; y = data->currentMV->y;
857                    }
858            }
859    }
860    
861          MACROBLOCK * const pMB = pMBs + x + y * iWcount;  static void
862    SquareSearch(int x, int y, const SearchData * const data, int bDirection)
863    {
864            int iDirection;
865    
866          static int32_t threshA,threshB;          do {
867          int32_t bPredEq;                  iDirection = 0;
868          int32_t iMinSAD,iSAD;                  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  /* Get maximum range */                  bDirection = iDirection;
878          get_range(&min_dx, &max_dx, &min_dy, &max_dy,                  x = data->currentMV->x; y = data->currentMV->y;
879                          x, y, 16, iWidth, iHeight, iFcode);          } while (iDirection);
880    }
881    
882  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  static void
883    DiamondSearch(int x, int y, const SearchData * const data, int bDirection)
884    {
885    
886          if (!(MotionFlags & PMV_HALFPEL16 ))  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
         { min_dx = EVEN(min_dx);  
           max_dx = EVEN(max_dx);  
           min_dy = EVEN(min_dy);  
           max_dy = EVEN(max_dy);  
         }               /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
887    
888            int iDirection;
889    
890          bPredEq  = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);          do {
891                    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          if ((x==0) && (y==0) )                  /* now we're doing diagonal checks near our candidate */
         {  
                 threshA =  512;  
                 threshB = 1024;  
898    
899                    if (iDirection) {               /* checking if anything found */
900                            bDirection = iDirection;
901                            iDirection = 0;
902                            x = data->currentMV->x; y = data->currentMV->y;
903                            if (bDirection & 3) {   /* our candidate is left or right */
904                                    CHECK_CANDIDATE(x, y + iDiamondSize, 8);
905                                    CHECK_CANDIDATE(x, y - iDiamondSize, 4);
906                            } 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                          bDirection += iDirection;
911          {                          x = data->currentMV->x; y = data->currentMV->y;
912                  threshA = psad[0];                  }
913                  threshB = threshA+256;          }
914                  if (threshA< 512) threshA =  512;          while (iDirection);
                 if (threshA>1024) threshA = 1024;  
                 if (threshB>1792) threshB = 1792;  
915          }          }
916    
917          iFound=0;  /* MAINSEARCH FUNCTIONS END */
918    
919  /* Step 2: Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  static void
920          vector of the median.  SubpelRefine(const SearchData * const data)
921          If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  {
922  */  /* Do a half-pel or q-pel refinement */
923            const VECTOR centerMV = data->qpel_precision ? *data->currentQMV : *data->currentMV;
924            int iDirection; /* only needed because macro expects it */
925    
926          if ((bPredEq) && (MVequal(pmv[0],pMB->mvs[0]) ) )          CHECK_CANDIDATE(centerMV.x, centerMV.y - 1, 0);
927                  iFound=2;          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  /* Step 3: If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.  static __inline int
937          Otherwise select large Diamond Search.  SkipDecisionP(const IMAGE * current, const IMAGE * reference,
938  */                                                          const int x, const int y,
939                                                            const uint32_t stride, const uint32_t iQuant, int rrv)
940    
941          if ( (pmv[0].x != 0) || (pmv[0].y != 0) || (threshB<1536) || (bPredEq) )  {
942                  iDiamondSize=1; // halfpel!          int offset = (x + y*stride)*8;
943          else          if(!rrv) {
944                  iDiamondSize=2; // halfpel!                  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          if (!(MotionFlags & PMV_HALFPELDIAMOND16) )  static __inline void
964                  iDiamondSize*=2;  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  /* Step 4: Calculate SAD around the Median prediction.  static __inline void
973          MinSAD=SAD  ModeDecision(SearchData * const Data,
974          If Motion Vector equal to Previous frame motion vector                          MACROBLOCK * const pMB,
975                  and MinSAD<PrevFrmSAD goto Step 10.                          const MACROBLOCK * const pMBs,
976          If SAD<=256 goto Step 10.                          const int x, const int y,
977  */                          const MBParam * const pParam,
978                            const uint32_t MotionFlags,
979                            const uint32_t VopFlags,
980                            const uint32_t VolFlags,
981                            const IMAGE * const pCurrent,
982                            const IMAGE * const pRef,
983                            const IMAGE * const vGMC,
984                            const int coding_type)
985    {
986            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            const int skip_possible = (coding_type == P_VOP) && (pMB->dquant == 0);
992    
993  // Prepare for main loop          pMB->mcsel = 0;
994    
995          *currMV=pmv[0];         /* current best := prediction */          if (!(VopFlags & XVID_VOP_MODEDECISION_RD)) { /* normal, fast, SAD-based mode decision */
996          if (!(MotionFlags & PMV_HALFPEL16 ))                  int sad;
997          {       /* This should NOT be necessary! */                  int InterBias = MV16_INTER_BIAS;
998                  currMV->x = EVEN(currMV->x);                  if (inter4v == 0 || Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
999                  currMV->y = EVEN(currMV->y);                          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          if (currMV->x > max_dx)                  /* 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                          currMV->x=max_dx;                          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          if (currMV->x < min_dx)  
1017                  {                  /* mcsel */
1018                          currMV->x=min_dx;                  if (coding_type == S_VOP) {
1019    
1020                            int32_t iSAD = sad16(Data->Cur,
1021                                    vGMC->y + 16*y*Data->iEdgedWidth + 16*x, Data->iEdgedWidth, 65536);
1022    
1023                            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          if (currMV->y > max_dy)  
1028                  {                          if (iSAD <= sad) {              /* mode decision GMC */
1029                          currMV->y=max_dy;                                  mode = MODE_INTER;
1030                                    mcsel = 1;
1031                                    sad = iSAD;
1032                  }                  }
1033          if (currMV->y < min_dy)  
                 {  
                         currMV->y=min_dy;  
1034                  }                  }
1035    
1036          iMinSAD = sad16( cur,                  /* intra decision */
                 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;  
1037    
1038          if ( (iMinSAD < 256 ) || ( (MVequal(*currMV,pMB->mvs[0])) && (iMinSAD < pMB->sad16) ) )                  if (iQuant > 8) InterBias += 100 * (iQuant - 8); /* to make high quants work */
1039                  {                  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                    if (Data->chroma) InterBias += 50; /* dev8(chroma) ??? <-- yes, we need dev8 (no big difference though) */
1045                    if (Data->rrv) InterBias *= 4;
1046    
1047                    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                          if (MotionFlags & PMV_QUICKSTOP16)                          if (deviation < (sad - InterBias)) mode = MODE_INTRA;
                                 goto step10b;  
                         if (MotionFlags & PMV_EARLYSTOP16)  
                                 goto step10;  
1058                  }                  }
1059    
1060  /*                  pMB->cbp = 63;
1061  Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
         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. ******** WHAT'S THIS 'OFFSET' ??? ***********  
 */  
1062    
1063  // (0,0) is always possible          } else { /* Rate-Distortion */
1064    
1065          CHECK_MV16_ZERO;                  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  // previous frame MV is always possible                  v = Data->qpel ? Data->currentQMV : Data->currentMV;
1071          CHECK_MV16_CANDIDATE(pMB->mvs[0].x,pMB->mvs[0].y);                  for (i = 0; i < 5; i++) {
1072                            Data->iMinSAD[i] = 256*4096;
1073                            backup[i] = v[i];
1074                    }
1075    
1076  // left neighbour, if allowed                  min_rd = findRDinter(Data, pMBs, x, y, pParam, MotionFlags);
1077          if (x != 0)                  cbp = *Data->cbp;
1078          {  
1079                  if (!(MotionFlags & PMV_HALFPEL16 ))                  if (coding_type == S_VOP) {
1080                  {       pmv[1].x = EVEN(pmv[1].x);                          int gmc_rd;
1081                          pmv[1].y = EVEN(pmv[1].y);                          *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                  }                  }
                 CHECK_MV16_CANDIDATE(pmv[1].x,pmv[1].y);  
1089          }          }
1090    
1091  // top neighbour, if allowed                  if (inter4v) {
1092          if (y != 0)                          int v4_rd;
1093          {                          v4_rd = findRDinter4v(Data, pMB, pMBs, x, y, pParam, MotionFlags, backup);
1094                  if (!(MotionFlags & PMV_HALFPEL16 ))                          if (v4_rd < min_rd) {
1095                  {       pmv[2].x = EVEN(pmv[2].x);                                  Data->iMinSAD[0] = min_rd = v4_rd;
1096                          pmv[2].y = EVEN(pmv[2].y);                                  mode = MODE_INTER4V;
1097                                    cbp = *Data->cbp;
1098                            }
1099                  }                  }
                 CHECK_MV16_CANDIDATE(pmv[2].x,pmv[2].y);  
1100    
1101  // top right neighbour, if allowed                  intra_rd = findRDintra(Data);
1102                  if (x != (iWcount-1))                  if (intra_rd < min_rd) {
1103                  {                          *Data->iMinSAD = min_rd = intra_rd;
1104                          if (!(MotionFlags & PMV_HALFPEL16 ))                          mode = MODE_INTRA;
                         {       pmv[3].x = EVEN(pmv[3].x);  
                                 pmv[3].y = EVEN(pmv[3].y);  
1105                          }                          }
1106                          CHECK_MV16_CANDIDATE(pmv[3].x,pmv[3].y);  
1107                    pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = 0;
1108                    pMB->cbp = cbp;
1109                  }                  }
1110    
1111            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 6: If MinSAD <= thresa goto Step 10.          if (mode == MODE_INTER && mcsel == 0) {
1117     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.                  pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
 */  
1118    
1119          if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[0]) && (iMinSAD < pMB->sad16) ) )                  if(Data->qpel) {
1120                  {                          pMB->qmvs[0] = pMB->qmvs[1]
1121                          if (MotionFlags & PMV_QUICKSTOP16)                                  = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1122                                  goto step10b;                          pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1123                          if (MotionFlags & PMV_EARLYSTOP16)                          pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;
1124                                  goto step10;                  } 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            } else if (mode == MODE_INTER ) { // but mcsel == 1
1130    
1131  /************ (Diamond Search)  **************/                  pMB->mcsel = 1;
1132  /*                  if (Data->qpel) {
1133  Step 7: Perform Diamond search, with either the small or large diamond.                          pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] = pMB->qmvs[3] = pMB->amv;
1134          If Found=2 only examine one Diamond pattern, and afterwards goto step 10                          pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = pMB->amv.x/2;
1135  Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.                          pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = pMB->amv.y/2;
1136          If center then goto step 10.                  } else
1137  Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->amv;
         Refine by using small diamond and goto step 10.  
 */  
1138    
1139          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */          } else
1140                    if (mode == MODE_INTER4V) ; /* anything here? */
1141            else    /* INTRA, NOT_CODED */
1142                    ZeroMacroblockP(pMB, 0);
1143    
1144  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          pMB->mode = mode;
1145          iSAD = PMVfastSearch16_MainSearch(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, iFound);  
1146    
1147          if (iSAD < iMinSAD)  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 = newMV;          MACROBLOCK *const pMBs = current->mbs;
1158                  iMinSAD = iSAD;          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                                            }
1236          }          }
1237    
1238          if (MotionFlags & PMV_EXTSEARCH16)                          if ((current->vop_flags & XVID_VOP_CARTOON) &&
1239          {                                  (sad00 < pMB->quant * 4 * skip_thresh)) { /* favorize (0,0) vector for cartoons */
1240  /* extended: search (up to) two more times: orignal prediction and (0,0) */                                  ZeroMacroblockP(pMB, sad00);
1241                                    continue;
1242                            }
1243    
1244                  if (!(MVequal(pmv[0],backupMV)) )                          SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1245                  {       iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,                                          y, MotionFlags, current->vop_flags, current->vol_flags,
1246                                  x, y,                                          &Data, pParam, pMBs, reference->mbs, pMB);
1247                          pmv[0].x, pmv[0].y, iMinSAD, &newMV,  
1248                          pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);                          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 (iSAD < iMinSAD)                          if (pMB->mode == MODE_INTRA)
1253                          {                                  if (++iIntra > iLimit) return 1;
1254                                  *currMV = newMV;                  }
                                 iMinSAD = iSAD;  
1255                          }                          }
1256    
1257            return 0;
1258                  }                  }
1259    
                 if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )  
                 {       iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,  
                                 x, y,  
                         0, 0, iMinSAD, &newMV,  
                         pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);  
1260    
1261                          if (iSAD < iMinSAD)  static __inline int
1262    make_mask(const VECTOR * const pmv, const int i)
1263                          {                          {
1264                                  *currMV = newMV;          int mask = 255, j;
1265                                  iMinSAD = iSAD;          for (j = 0; j < i; j++) {
1266                    if (MVequal(pmv[i], pmv[j])) return 0; /* same vector has been checked already */
1267                    if (pmv[i].x == pmv[j].x) {
1268                            if (pmv[i].y == pmv[j].y + iDiamondSize) mask &= ~4;
1269                            else if (pmv[i].y == pmv[j].y - iDiamondSize) mask &= ~8;
1270                    } 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  /*  static __inline void
1280          Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  PreparePredictionsP(VECTOR * const pmv, int x, int y, int iWcount,
1281  */                          int iHcount, const MACROBLOCK * const prevMB, int rrv)
1282    {
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  step10:          if ( (y != 0) && (x < (iWcount-1)) ) {          /* [5] top-right neighbour */
1287          if (MotionFlags & PMV_HALFPELREFINE16)          // perform final half-pel step                  pmv[5].x = EVEN(pmv[3].x);
1288                  iMinSAD = PMVfastSearch16_Refine( pRef, pRefH, pRefV, pRefHV, cur,                  pmv[5].y = EVEN(pmv[3].y);
1289                                  x, y,          } else pmv[5].x = pmv[5].y = 0;
                                 currMV, iMinSAD,  
                                 pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);  
1290    
1291  step10b:          if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }/* pmv[3] is left neighbour */
1292          currPMV->x = currMV->x - pmv[0].x;          else pmv[3].x = pmv[3].y = 0;
         currPMV->y = currMV->y - pmv[0].y;  
         return iMinSAD;  
 }  
1293    
1294            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            /* [1] median prediction */
1298            pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
1299    
1300            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            pmv[2].x = EVEN(prevMB->mvs[0].x); /* [2] is last frame */
1303            pmv[2].y = EVEN(prevMB->mvs[0].y);
1304    
1305            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  int32_t PMVfastSearch8_MainSearch(          if (rrv) {
1311                                          const uint8_t * const pRef,                  int i;
1312                                          const uint8_t * const pRefH,                  for (i = 0; i < 7; i++) {
1313                                          const uint8_t * const pRefV,                          pmv[i].x = RRV_MV_SCALEUP(pmv[i].x);
1314                                          const uint8_t * const pRefHV,                          pmv[i].y = RRV_MV_SCALEUP(pmv[i].y);
                                         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);  
1315                  }                  }
         else  
                 {  
                         currMV->x = startx;  
                         currMV->y = starty;  
1316                  }                  }
         return iMinSAD;  
1317  }  }
1318    
1319  int32_t PMVfastSearch8_Refine(  static void
1320                                          const uint8_t * const pRef,  SearchP(const IMAGE * const pRef,
1321                                          const uint8_t * const pRefH,                                          const uint8_t * const pRefH,
1322                                          const uint8_t * const pRefV,                                          const uint8_t * const pRefV,
1323                                          const uint8_t * const pRefHV,                                          const uint8_t * const pRefHV,
1324                                          const uint8_t * const cur,                  const IMAGE * const pCur,
1325                                          const int x, const int y,                  const int x,
1326                                          VECTOR * const currMV,                  const int y,
1327                                          int32_t iMinSAD,                  const uint32_t MotionFlags,
1328                                          const VECTOR * const pmv,                  const uint32_t VopFlags,
1329                                          const int32_t min_dx, const int32_t max_dx,                  const uint32_t VolFlags,
1330                                          const int32_t min_dy, const int32_t max_dy,                  SearchData * const Data,
1331                                          const int32_t iFcode,                  const MBParam * const pParam,
1332                                          const int32_t iQuant,                  const MACROBLOCK * const pMBs,
1333                                          const int32_t iEdgedWidth)                  const MACROBLOCK * const prevMBs,
1334  {                  MACROBLOCK * const pMB)
1335  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  {
1336    
1337            int i, iDirection = 255, mask, threshA;
1338            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            get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);
1345    
1346            Data->temp[5] = Data->temp[6] = 0; /* chroma-sad cache */
1347            i = Data->rrv ? 2 : 1;
1348            Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16*i;
1349            Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1350            Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
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            Data->lambda16 = lambda_vec16[pMB->quant];
1360            Data->lambda8 = lambda_vec8[pMB->quant];
1361            Data->qpel_precision = 0;
1362    
1363            memset(Data->currentMV, 0, 5*sizeof(VECTOR));
1364    
1365            if (Data->qpel) Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1366            else Data->predMV = pmv[0];
1367    
1368            i = d_mv_bits(0, 0, Data->predMV, Data->iFcode, 0, 0);
1369            Data->iMinSAD[0] = pMB->sad16 + ((Data->lambda16 * i * pMB->sad16)>>10);
1370            Data->iMinSAD[1] = pMB->sad8[0] + ((Data->lambda8 * i * (pMB->sad8[0]+NEIGH_8X8_BIAS)) >> 10);
1371            Data->iMinSAD[2] = pMB->sad8[1];
1372            Data->iMinSAD[3] = pMB->sad8[2];
1373            Data->iMinSAD[4] = pMB->sad8[3];
1374    
1375          int32_t iSAD;          if ((!(VopFlags & XVID_VOP_MODEDECISION_RD)) && (x | y)) {
1376          VECTOR backupMV = *currMV;                  threshA = Data->temp[0]; /* that's where we keep this SAD atm */
1377                    if (threshA < 512) threshA = 512;
1378                    else if (threshA > 1024) threshA = 1024;
1379            } else
1380                    threshA = 512;
1381    
1382          CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y-1);          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
1383          CHECK_MV8_CANDIDATE(backupMV.x  ,backupMV.y-1);                                          prevMBs + x + y * pParam->mb_width, Data->rrv);
         CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y-1);  
         CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y+1);  
         CHECK_MV8_CANDIDATE(backupMV.x  ,backupMV.y+1);  
         CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y+1);  
1384    
1385          return iMinSAD;          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  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)          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  int32_t PMVfastSearch8(          if ((Data->iMinSAD[0] <= threshA) ||
1399                                          const uint8_t * const pRef,                          (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
1400                                          const uint8_t * const pRefH,                          (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16)))
1401                                          const uint8_t * const pRefV,                  inter4v = 0;
1402                                          const uint8_t * const pRefHV,          else {
                                         const IMAGE * const pCur,  
                                         const int x, const int y,  
                                         const int start_x, int start_y,  
                                         const uint32_t MotionFlags,  
                                         MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
 {  
         const uint32_t iWcount = pParam->mb_width;  
1403    
1404          const int32_t iFcode = pParam->fixed_code;                  MainSearchFunc * MainSearchPtr;
1405          const int32_t iQuant = pParam->quant;                  if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1406          const int32_t iWidth = pParam->width;                  else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1407          const int32_t iHeight = pParam->height;                          else MainSearchPtr = DiamondSearch;
         const int32_t iEdgedWidth = pParam->edged_width;  
1408    
1409          const uint8_t * cur = pCur->y + x*8 + y*8*iEdgedWidth;                  MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
1410    
1411          int32_t iDiamondSize;  /* extended search, diamond starting in 0,0 and in prediction.
1412            note that this search is/might be done in halfpel positions,
1413            which makes it more different than the diamond above */
1414    
1415          int32_t min_dx;                  if (MotionFlags & XVID_ME_EXTSEARCH16) {
1416          int32_t max_dx;                          int32_t bSAD;
1417          int32_t min_dy;                          VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
1418          int32_t max_dy;                          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          VECTOR pmv[4];                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1426          int32_t psad[4];                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1427          VECTOR newMV;                                  if (bSAD < Data->iMinSAD[0]) {
1428          VECTOR backupMV;                                          Data->currentMV[0] = backupMV;
1429                                            Data->iMinSAD[0] = bSAD; }
1430                            }
1431    
1432          MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;                          backupMV = Data->currentMV[0];
1433                            startMV.x = startMV.y = 1;
1434                            if (!(MVequal(startMV, backupMV))) {
1435                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1436    
1437          static int32_t threshA,threshB;                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1438          int32_t iFound,bPredEq;                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1439          int32_t iMinSAD,iSAD;                                  if (bSAD < Data->iMinSAD[0]) {
1440                                            Data->currentMV[0] = backupMV;
1441                                            Data->iMinSAD[0] = bSAD; }
1442                            }
1443                    }
1444            }
1445    
1446          int32_t iSubBlock = ((y&1)<<1) + (x&1);          if (MotionFlags & XVID_ME_HALFPELREFINE16)
1447                            SubpelRefine(Data);
1448    
1449  /* Get maximum range */          for(i = 0; i < 5; i++) {
1450      get_range(&min_dx, &max_dx, &min_dy, &max_dy,                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; /* initialize qpel vectors */
1451                          x, y, 8, iWidth, iHeight, iFcode);                  Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
1452            }
1453    
1454  /* we work with abs. MVs, not relative to prediction, so range is relative to 0,0 */          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 (!(MotionFlags & PMV_HALFPELDIAMOND8 ))          if (Data->iMinSAD[0] < (int32_t)pMB->quant * 30)
1463          { min_dx = EVEN(min_dx);                  inter4v = 0;
           max_dx = EVEN(max_dx);  
           min_dy = EVEN(min_dy);  
           max_dy = EVEN(max_dy);  
         }               /* because we might use IF (dx>max_dx) THEN dx=max_dx; */  
1464    
1465            if (inter4v) {
1466                    SearchData Data8;
1467                    memcpy(&Data8, Data, sizeof(SearchData)); /* quick copy of common data */
1468    
1469          bPredEq  = get_pmvdata(pMBs, (x>>1), (y>>1), iWcount, iSubBlock, pmv, psad);                  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 ((x==0) && (y==0) )                  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                  threshA =  512/4;                          int sumx = 0, sumy = 0;
                 threshB = 1024/4;  
1477    
1478                            if (Data->qpel)
1479                                    for (i = 1; i < 5; i++) {
1480                                            sumx += Data->currentQMV[i].x/2;
1481                                            sumy += Data->currentQMV[i].y/2;
1482          }          }
1483          else          else
1484          {                                  for (i = 1; i < 5; i++) {
1485                  threshA = psad[0]/4;                    /* good estimate */                                          sumx += Data->currentMV[i].x;
1486                  threshB = threshA+256/4;                                          sumy += Data->currentMV[i].y;
                 if (threshA< 512/4) threshA =  512/4;  
                 if (threshA>1024/4) threshA = 1024/4;  
                 if (threshB>1792/4) threshB = 1792/4;  
1487          }          }
1488    
1489          iFound=0;                          Data->iMinSAD[1] += ChromaSAD(  (sumx >> 3) + roundtab_76[sumx & 0xf],
1490                                                                                            (sumy >> 3) + roundtab_76[sumy & 0xf], Data);
1491  /* Step 2: Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion                  }
1492          vector of the median.          } else Data->iMinSAD[1] = 4096*256;
1493          If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  }
 */  
   
         if ((bPredEq) && (MVequal(pmv[0],pMB->mvs[iSubBlock]) ) )  
                 iFound=2;  
1494    
1495  /* Step 3: If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.  static void
1496          Otherwise select large Diamond Search.  Search8(const SearchData * const OldData,
1497  */                  const int x, const int y,
1498                    const uint32_t MotionFlags,
1499                    const MBParam * const pParam,
1500                    MACROBLOCK * const pMB,
1501                    const MACROBLOCK * const pMBs,
1502                    const int block,
1503                    SearchData * const Data)
1504    {
1505            int i = 0;
1506            Data->iMinSAD = OldData->iMinSAD + 1 + block;
1507            Data->currentMV = OldData->currentMV + 1 + block;
1508            Data->currentQMV = OldData->currentQMV + 1 + block;
1509    
1510          if ( (pmv[0].x != 0) || (pmv[0].y != 0) || (threshB<1536/4) || (bPredEq) )          if(Data->qpel) {
1511                  iDiamondSize=1; // 1 halfpel!                  Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1512          else                  if (block != 0) i = d_mv_bits(  Data->currentQMV->x, Data->currentQMV->y,
1513                  iDiamondSize=2; // 2 halfpel = 1 full pixel!                                                                                  Data->predMV, Data->iFcode, 0, 0);
1514            } else {
1515                    Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1516                    if (block != 0) i = d_mv_bits(  Data->currentMV->x, Data->currentMV->y,
1517                                                                                    Data->predMV, Data->iFcode, 0, Data->rrv);
1518            }
1519    
1520          if (!(MotionFlags & PMV_HALFPELDIAMOND8) )          *(Data->iMinSAD) += (Data->lambda8 * i * (*Data->iMinSAD + NEIGH_8X8_BIAS))>>10;
                 iDiamondSize*=2;  
1521    
1522  /* Step 4: Calculate SAD around the Median prediction.          if (MotionFlags & (XVID_ME_EXTSEARCH8|XVID_ME_HALFPELREFINE8|XVID_ME_QUARTERPELREFINE8)) {
1523          MinSAD=SAD  
1524          If Motion Vector equal to Previous frame motion vector                  if (Data->rrv) i = 16; else i = 8;
1525                  and MinSAD<PrevFrmSAD goto Step 10.  
1526          If SAD<=256 goto Step 10.                  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                    Data->Cur = OldData->Cur + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1532                    Data->qpel_precision = 0;
1533    
1534                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 3,
1535                                            pParam->width, pParam->height, Data->iFcode - Data->qpel, 1, Data->rrv);
1536    
1537                    if (!Data->rrv) CheckCandidate = CheckCandidate8;
1538                    else CheckCandidate = CheckCandidate16no4v;
1539    
1540                    if (MotionFlags & XVID_ME_EXTSEARCH8 && (!(MotionFlags & XVID_ME_EXTSEARCH_RD))) {
1541                            int32_t temp_sad = *(Data->iMinSAD); /* store current MinSAD */
1542    
1543                            MainSearchFunc *MainSearchPtr;
1544                            if (MotionFlags & XVID_ME_USESQUARES8) MainSearchPtr = SquareSearch;
1545                                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1546                                            else MainSearchPtr = DiamondSearch;
1547    
1548                            MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, 255);
1549    
1550                            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                    if (MotionFlags & XVID_ME_HALFPELREFINE8) {
1557                            int32_t temp_sad = *(Data->iMinSAD); /* store current MinSAD */
1558    
1559                            SubpelRefine(Data); /* perform halfpel refine of current best vector */
1560    
1561                            if(*(Data->iMinSAD) < temp_sad) { /* we have found a better match */
1562                                    Data->currentQMV->x = 2 * Data->currentMV->x; /* update our qpel vector */
1563                                    Data->currentQMV->y = 2 * Data->currentMV->y;
1564                            }
1565                    }
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            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(Data->qpel) {
1581                    pMB->pmvs[block].x = Data->currentQMV->x - Data->predMV.x;
1582                    pMB->pmvs[block].y = Data->currentQMV->y - Data->predMV.y;
1583                    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    
1593    /* motion estimation for B-frames */
1594    
1595    static __inline VECTOR
1596    ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1597    {
1598    /* the stupidiest function ever */
1599            return (mode == MODE_FORWARD ? pMB->mvs[0] : pMB->b_mvs[0]);
1600    }
1601    
1602    static void __inline
1603    PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
1604                                                            const uint32_t iWcount,
1605                                                            const MACROBLOCK * const pMB,
1606                                                            const uint32_t mode_curr)
1607    {
1608    
1609            /* [0] is prediction */
1610            pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
1611    
1612            pmv[1].x = pmv[1].y = 0; /* [1] is zero */
1613    
1614  // Prepare for main loop          pmv[2] = ChoosePred(pMB, mode_curr);
1615            pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
1616    
1617          currMV->x=start_x;              /* start with mv16 */          if ((y != 0)&&(x != (int)(iWcount+1))) {                        /* [3] top-right neighbour */
1618          currMV->y=start_y;                  pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
1619                    pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
1620            } else pmv[3].x = pmv[3].y = 0;
1621    
1622          iMinSAD = sad8( cur,          if (y != 0) {
1623                  get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV, iEdgedWidth),                  pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
1624                  iEdgedWidth);                  pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
1625          iMinSAD += calc_delta_8(currMV->x - pmv[0].x, currMV->y - pmv[0].y, (uint8_t)iFcode) * iQuant;          } else pmv[4].x = pmv[4].y = 0;
1626    
1627          if ( (iMinSAD < 256/4 ) || ( (MVequal(*currMV,pMB->mvs[iSubBlock])) && (iMinSAD < pMB->sad8[iSubBlock]) ) )          if (x != 0) {
1628                  {                  pmv[5] = ChoosePred(pMB-1, mode_curr);
1629                          if (MotionFlags & PMV_QUICKSTOP8)                  pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1630                                  goto step10_8b;          } else pmv[5].x = pmv[5].y = 0;
1631                          if (MotionFlags & PMV_EARLYSTOP8)  
1632                                  goto step10_8;          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    
1638    
1639    /* search backward or forward */
1640    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    
1657            int i, iDirection = 255, mask;
1658            VECTOR pmv[7];
1659            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            if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1692            else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1693                    else MainSearchPtr = DiamondSearch;
1694    
1695            MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
1696    
1697            SubpelRefine(Data);
1698    
1699            if (Data->qpel && *Data->iMinSAD < *best_sad + 300) {
1700                    Data->currentQMV->x = 2*Data->currentMV->x;
1701                    Data->currentQMV->y = 2*Data->currentMV->y;
1702                    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 (mode_current == MODE_FORWARD) *Data->iMinSAD += 4 * Data->lambda16;
1711            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. ******** WHAT'S THIS 'OFFSET' ??? ***********  
1875  */  */
1876    
1877  // the prediction might be even better than mv16          if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1878          CHECK_MV8_CANDIDATE(pmv[0].x,pmv[0].y);                  else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1879                            else MainSearchPtr = DiamondSearch;
1880    
1881            MainSearchPtr(0, 0, Data, 255);
1882    
1883            SubpelRefine(Data);
1884    
1885            *best_sad = *Data->iMinSAD;
1886    
1887            if (Data->qpel || b_mb->mode == MODE_INTER4V) pMB->mode = MODE_DIRECT;
1888            else pMB->mode = MODE_DIRECT_NO4V; /* for faster compensation */
1889    
1890            pMB->pmvs[3] = *Data->currentMV;
1891    
1892            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    static void
1920    SearchInterpolate(const IMAGE * const f_Ref,
1921                                    const uint8_t * const f_RefH,
1922                                    const uint8_t * const f_RefV,
1923                                    const uint8_t * const f_RefHV,
1924                                    const IMAGE * const b_Ref,
1925                                    const uint8_t * const b_RefH,
1926                                    const uint8_t * const b_RefV,
1927                                    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            }
2044    }
2045    
2046    void
2047    MotionEstimationBVOP(MBParam * const pParam,
2048                                             FRAMEINFO * const frame,
2049                                             const int32_t time_bp,
2050                                             const int32_t time_pp,
2051                                             /* 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            uint32_t i, j;
2065            int32_t best_sad;
2066            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                                    }
2109    
2110                            Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
2111                            Data.CurU = frame->image.u + (j * Data.iEdgedWidth/2 + i) * 8;
2112                            Data.CurV = frame->image.v + (j * Data.iEdgedWidth/2 + i) * 8;
2113                            pMB->quant = frame->quant;
2114    
2115    /* direct search comes first, because it (1) checks for SKIP-mode
2116            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                                                                            b_ref, b_refH->y, b_refV->y, b_refHV->y,
2119                                                                            &frame->image,
2120                                                                            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                    }
2184            }
2185    }
2186    
2187  // (0,0) is always possible  static __inline void
2188          CHECK_MV8_ZERO;  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  // previous frame MV is always possible          int i, mask;
2198          CHECK_MV8_CANDIDATE(pMB->mvs[iSubBlock].x,pMB->mvs[iSubBlock].y);          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  // left neighbour, if allowed          for (i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;
2203          if (psad[1] != MV_MAX_ERROR)  
2204            /* 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            else
2207                    if (x == 1) /* left macroblock does not have any vector now */
2208                            Data->predMV = (pMB - pParam->mb_width)->mvs[0]; /* top instead of median */
2209                    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            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);
2215    
2216            Data->Cur = pCur + (x + y * pParam->edged_width) * 16;
2217            Data->RefP[0] = pRef + (x + y * pParam->edged_width) * 16;
2218    
2219            pmv[1].x = EVEN(pMB->mvs[0].x);
2220            pmv[1].y = EVEN(pMB->mvs[0].y);
2221            pmv[2].x = EVEN(Data->predMV.x);
2222            pmv[2].y = EVEN(Data->predMV.y);
2223            pmv[0].x = pmv[0].y = 0;
2224    
2225            CheckCandidate32I(0, 0, 255, &i, Data);
2226    
2227            if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP) {
2228    
2229                    if (!(mask = make_mask(pmv, 1)))
2230                            CheckCandidate32I(pmv[1].x, pmv[1].y, mask, &i, Data);
2231                    if (!(mask = make_mask(pmv, 2)))
2232                            CheckCandidate32I(pmv[2].x, pmv[2].y, mask, &i, Data);
2233    
2234                    if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP) /* diamond only if needed */
2235                            DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, i);
2236            }
2237    
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    #define INTRA_THRESH    2200
2247    #define INTER_THRESH    50
2248    #define INTRA_THRESH2   95
2249    
2250    int
2251    MEanalysis(     const IMAGE * const pRef,
2252                            const FRAMEINFO * const Current,
2253                            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                            MEanalyzeMB(pRef->y, pCurrent->y, x, y, pParam, pMBs, &Data);
2304    
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                                    if (pMB->mvs[0].x == 0 && pMB->mvs[0].y == 0)
2318                                            if (dev > 500 && pMB->sad16 < 1000)
2319                                                    sSAD += 1000;
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            sSAD /= complexity + 4*blocks;
2328    
2329            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    
2336    /* functions which perform BITS-based search/bitcount */
2337    
2338    static int
2339    findRDinter(SearchData * const Data,
2340                            const MACROBLOCK * const pMBs, const int x, const int y,
2341                            const MBParam * const pParam,
2342                            const uint32_t MotionFlags)
2343          {          {
2344                  if (!(MotionFlags & PMV_HALFPEL8 ))          int i, iDirection;
2345                  {       pmv[1].x = EVEN(pmv[1].x);          int32_t bsad[5];
2346                          pmv[1].y = EVEN(pmv[1].y);  
2347            CheckCandidate = CheckCandidateRD16;
2348    
2349            if (Data->qpel) {
2350                    for(i = 0; i < 5; i++) {
2351                            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                    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            } else { /* not qpel */
2367    
2368                    CheckCandidateRD16(Data->currentMV[0].x, Data->currentMV[0].y, 255, &iDirection, Data);
2369            }
2370    
2371            if (MotionFlags&XVID_ME_EXTSEARCH_RD) SquareSearch(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
2372    
2373            if (MotionFlags&XVID_ME_HALFPELREFINE16_RD) SubpelRefine(Data);
2374    
2375            if (Data->qpel) {
2376                    if (MotionFlags&(XVID_ME_EXTSEARCH_RD | XVID_ME_HALFPELREFINE16_RD)) { /* there was halfpel-precision search */
2377                            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                            /* 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 (MotionFlags&XVID_ME_CHECKPREDICTION_RD) { /* let's check vector equal to prediction */
2391                    VECTOR * v = Data->qpel ? Data->currentQMV : Data->currentMV;
2392                    if (!(Data->predMV.x == v->x && Data->predMV.y == v->y))
2393                            CheckCandidateRD16(Data->predMV.x, Data->predMV.y, 255, &iDirection, Data);
2394                  }                  }
2395                  CHECK_MV8_CANDIDATE(pmv[1].x,pmv[1].y);          return Data->iMinSAD[0];
2396          }          }
2397    
2398  // top neighbour, if allowed  static int
2399          if (psad[2] != MV_MAX_ERROR)  findRDinter4v(const SearchData * const Data,
2400                                    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                  if (!(MotionFlags & PMV_HALFPEL8 ))  
2406                  {       pmv[2].x = EVEN(pmv[2].x);          int cbp = 0, bits = 0, t = 0, i, iDirection;
2407                          pmv[2].y = EVEN(pmv[2].y);          SearchData Data2, *Data8 = &Data2;
2408            int sumx = 0, sumy = 0;
2409            int16_t *in = Data->dctSpace, *coeff = Data->dctSpace + 64;
2410            uint8_t * ptr;
2411    
2412            memcpy(Data8, Data, sizeof(SearchData));
2413            CheckCandidate = CheckCandidateRD8;
2414    
2415            for (i = 0; i < 4; i++) { /* for all luma blocks */
2416    
2417                    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                    if(Data->qpel) {
2428                            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                                                                                    Data8->predMV, Data8->iFcode, 0, 0);
2431                    } 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                  }                  }
                 CHECK_MV8_CANDIDATE(pmv[2].x,pmv[2].y);  
2436    
2437  // top right neighbour, if allowed                  get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 3,
2438                  if (psad[3] != MV_MAX_ERROR)                                          pParam->width, pParam->height, Data8->iFcode, Data8->qpel+1, 0);
2439    
2440                    *Data8->iMinSAD += BITS_MULT*t;
2441    
2442                    Data8->qpel_precision = Data8->qpel;
2443                    /* 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_HALFPEL8 ))                          VECTOR *v = Data8->qpel ? Data8->currentQMV : Data8->currentMV;
2446                  {       pmv[3].x = EVEN(pmv[3].x);                          if (!MVequal (*v, backup[i+1]) )
2447                          pmv[3].y = EVEN(pmv[3].y);                                  CheckCandidateRD8(backup[i+1].x, backup[i+1].y, 255, &iDirection, Data8);
2448                    }
2449    
2450                    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                                    if (Data8->currentQMV->x & 1 || Data8->currentQMV->y & 1)
2460                                            CheckCandidateRD8(Data8->currentMV->x, Data8->currentMV->y, 255, &iDirection, Data8);
2461    
2462                                    if (MotionFlags & XVID_ME_EXTSEARCH8 && MotionFlags & XVID_ME_EXTSEARCH_RD)
2463                                            SquareSearch(Data8->currentMV->x, Data8->currentMV->x, Data8, 255);
2464    
2465                                    if (MotionFlags & XVID_ME_HALFPELREFINE8_RD)
2466                                            SubpelRefine(Data8);
2467    
2468                                    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                          CHECK_MV8_CANDIDATE(pmv[3].x,pmv[3].y);  
2473                                    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                  }                  }
2478                            if (MotionFlags & XVID_ME_QUARTERPELREFINE8_RD) SubpelRefine(Data8);
2479    
2480                    } else { /* not qpel */
2481    
2482                            if (MotionFlags & XVID_ME_EXTSEARCH8 && MotionFlags & XVID_ME_EXTSEARCH_RD) /* extsearch */
2483                                    SquareSearch(Data8->currentMV->x, Data8->currentMV->x, Data8, 255);
2484    
2485                            if (MotionFlags & XVID_ME_HALFPELREFINE8_RD)
2486                                    SubpelRefine(Data8); /* halfpel refinement */
2487          }          }
2488    
2489  /* Step 6: If MinSAD <= thresa goto Step 10.                  /* checking vector equal to predicion */
2490     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.                  if (i != 0 && MotionFlags & XVID_ME_CHECKPREDICTION_RD) {
2491  */                          const VECTOR * v = Data->qpel ? Data8->currentQMV : Data8->currentMV;
2492                            if (!MVequal(*v, Data8->predMV))
2493                                    CheckCandidateRD8(Data8->predMV.x, Data8->predMV.y, 255, &iDirection, Data8);
2494                    }
2495    
2496                    bits += *Data8->iMinSAD;
2497                    if (bits >= Data->iMinSAD[0]) return bits; /* no chances for INTER4V */
2498    
2499                    /* MB structures for INTER4V mode; we have to set them here, we don't have predictor anywhere else */
2500                    if(Data->qpel) {
2501                            pMB->pmvs[i].x = Data8->currentQMV->x - Data8->predMV.x;
2502                            pMB->pmvs[i].y = Data8->currentQMV->y - Data8->predMV.y;
2503                            pMB->qmvs[i] = *Data8->currentQMV;
2504                            sumx += Data8->currentQMV->x/2;
2505                            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            } /* end - for all luma blocks */
2517    
2518            bits += BITS_MULT*xvid_cbpy_tab[15-(cbp>>2)].len;
2519    
2520            /* let's check chroma */
2521            sumx = (sumx >> 3) + roundtab_76[sumx & 0xf];
2522            sumy = (sumy >> 3) + roundtab_76[sumy & 0xf];
2523    
2524            /* chroma U */
2525            ptr = interpolate8x8_switch2(Data->RefQ + 64, Data->RefP[4], 0, 0, sumx, sumy, Data->iEdgedWidth/2, Data->rounding);
2526            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            if (bits >= *Data->iMinSAD) return bits;
2530    
2531            /* chroma V */
2532            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          if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[iSubBlock]) && (iMinSAD < pMB->sad8[iSubBlock]) ) )          bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTER4V & 7) | ((cbp & 3) << 3)].len;
2537    
2538            *Data->cbp = cbp;
2539            return bits;
2540    }
2541    
2542    static int
2543    findRDintra(const SearchData * const Data)
2544                  {                  {
2545                          if (MotionFlags & PMV_QUICKSTOP8)          int bits = BITS_MULT*1; /* this one is ac/dc prediction flag bit */
2546                                  goto step10_8b;          int cbp = 0, i, dc = 0;
2547                          if (MotionFlags & PMV_EARLYSTOP8)          int16_t *in = Data->dctSpace, * coeff = Data->dctSpace + 64;
2548                                  goto step10_8;  
2549            for(i = 0; i < 4; i++) {
2550                    int s = 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2551                    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 (bits >= Data->iMinSAD[0]) return bits;
2555                  }                  }
2556    
2557  /************ (Diamond Search)  **************/          bits += BITS_MULT*xvid_cbpy_tab[cbp>>2].len;
2558  /*  
2559  Step 7: Perform Diamond search, with either the small or large diamond.          /*chroma U */
2560          If Found=2 only examine one Diamond pattern, and afterwards goto step 10          transfer_8to16copy(in, Data->CurU, Data->iEdgedWidth/2);
2561  Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.          bits += Block_CalcBitsIntra(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 4, &dc);
2562          If center then goto step 10.  
2563  Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.          if (bits >= Data->iMinSAD[0]) return bits;
2564          Refine by using small diamond and goto step 10.  
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            bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTRA & 7) | ((cbp & 3) << 3)].len;
2570    
2571            return bits;
2572    }
2573    
2574    static int
2575    findRDgmc(const SearchData * const Data, const IMAGE * const vGMC, const int x, const int y)
2576    {
2577            int bits = BITS_MULT*1; /* this one is mcsel */
2578            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            bits += BITS_MULT*xvid_cbpy_tab[15-(cbp>>2)].len;
2589    
2590            /*chroma U */
2591            transfer_8to16subro(in, Data->CurU, vGMC->u + 8*(x+y*(Data->iEdgedWidth/2)), Data->iEdgedWidth/2);
2592            bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 4);
2593    
2594            if (bits >= Data->iMinSAD[0]) return bits;
2595    
2596            /* chroma V */
2597            transfer_8to16subro(in, Data->CurV , vGMC->v + 8*(x+y*(Data->iEdgedWidth/2)), Data->iEdgedWidth/2);
2598            bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 5);
2599    
2600            bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTER & 7) | ((cbp & 3) << 3)].len;
2601    
2602            *Data->cbp = cbp;
2603    
2604            return bits;
2605    }
2606    
2607    
2608    
2609    
2610    static __inline void
2611    GMEanalyzeMB (  const uint8_t * const pCur,
2612                                    const uint8_t * const pRef,
2613                                    const uint8_t * const pRefH,
2614                                    const uint8_t * const pRefV,
2615                                    const uint8_t * const pRefHV,
2616                                    const int x,
2617                                    const int y,
2618                                    const MBParam * const pParam,
2619                                    MACROBLOCK * const pMBs,
2620                                    SearchData * const Data)
2621    {
2622    
2623            int i=0;
2624            MACROBLOCK * const pMB = &pMBs[x + y * pParam->mb_width];
2625    
2626            Data->iMinSAD[0] = MV_MAX_ERROR;
2627    
2628            Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
2629    
2630            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            Data->Cur = pCur + 16*(x + y * pParam->edged_width);
2634            Data->RefP[0] = pRef + 16*(x + y * pParam->edged_width);
2635            Data->RefP[1] = pRefV + 16*(x + y * pParam->edged_width);
2636            Data->RefP[2] = pRefH + 16*(x + y * pParam->edged_width);
2637            Data->RefP[3] = pRefHV + 16*(x + y * pParam->edged_width);
2638    
2639            Data->currentMV[0].x = Data->currentMV[0].y = 0;
2640            CheckCandidate16I(0, 0, 255, &i, Data);
2641    
2642            if ( (Data->predMV.x !=0) || (Data->predMV.y != 0) )
2643                    CheckCandidate16I(Data->predMV.x, Data->predMV.y, 255, &i, Data);
2644    
2645            AdvDiamondSearch(Data->currentMV[0].x, Data->currentMV[0].y, Data, 255);
2646    
2647            SubpelRefine(Data);
2648    
2649    
2650            /* 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          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
2662            pMB->sad16 = Data->iMinSAD[0];
2663            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    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            int32_t iMinSAD[5], temp[5];
2682            VECTOR currentMV[5];
2683            SearchData Data;
2684            memset(&Data, 0, sizeof(SearchData));
2685    
2686            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            CheckCandidate = CheckCandidate16I;
2695    
2696            if (sadInit) (*sadInit) ();
2697    
2698            for (y = 0; y < pParam->mb_height; y ++) {
2699                    for (x = 0; x < pParam->mb_width; x ++) {
2700    
2701                            GMEanalyzeMB(pCurrent->y, pReference->y, pRefH->y, pRefV->y, pRefHV->y, x, y, pParam, pMBs, &Data);
2702                    }
2703            }
2704            return;
2705    }
2706    
 /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  
         iSAD = PMVfastSearch8_MainSearch(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, iFound);  
2707    
2708          if (iSAD < iMinSAD)  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                  *currMV = newMV;  
2718                  iMinSAD = iSAD;          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            double sol[4] = { 0., 0., 0., 0. };
2724    
2725            WARPPOINTS gmc;
2726    
2727            uint32_t mx, my;
2728    
2729            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            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;
2738    
2739            GMEanalysis(pParam,current, reference, pRefH, pRefV, pRefHV);
2740    
2741            /* block based ME isn't done, yet, so do a quick presearch */
2742    
2743    // filter mask of all blocks
2744    
2745            for (my = 0; my < (uint32_t)MBh; my++)
2746            for (mx = 0; mx < (uint32_t)MBw; mx++)
2747            {
2748                    const int mbnum = mx + my * MBw;
2749                            pMBs[mbnum].mcsel = 0;
2750          }          }
2751    
2752          if (MotionFlags & PMV_EXTSEARCH8)  
2753            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  /* extended: search (up to) two more times: orignal prediction and (0,0) */                  const int mbnum = mx + my * MBw;
2757                    MACROBLOCK *const pMB = &pMBs[mbnum];
2758                    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    
2777                    /* only use "structured" blocks */
2778                    }
2779            }
2780            emms();
2781    
2782                  if (!(MVequal(pmv[0],backupMV)) )          /*      further filtering would be possible, but during iteration, remaining
2783                  {       iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,                  outliers usually are removed, too */
                                 x, y,  
                         pmv[0].x, pmv[0].y, iMinSAD, &newMV,  
                         pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);  
2784    
2785                          if (iSAD < iMinSAD)          if (num>= minblocks)
2786            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                                  *currMV = newMV;                          const int mbnum = mx + my * MBw;
2797                                  iMinSAD = iSAD;                          const VECTOR mv = pMBs[mbnum].mvs[0];
2798    
2799                            if (!pMBs[mbnum].mcsel)
2800                                    continue;
2801    
2802                            n++;
2803                            a += 16*mx+8;
2804                            b += 16*my+8;
2805                            c += (16*mx+8)*(16*mx+8)+(16*my+8)*(16*my+8);
2806    
2807                            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            invdenom = a*a+b*b-c*n;
2814    
2815    /* 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            sol[0] = -c*DtimesF[0] + a*DtimesF[1] + b*DtimesF[2];
2819            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            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                            if (!pMBs[mbnum].mcsel)
2837                                    continue;
2838    
2839                            oldnum++;
2840                            meanx += fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - (double)mv.x );
2841                            meany += fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - (double)mv.y );
2842                  }                  }
2843    
2844                  if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )          if (4*meanx > oldnum)   /* better fit than 0.25 (=1/4pel) is useless */
2845                  {       iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,                  meanx /= oldnum;
2846                                  x, y,          else
2847                          0, 0, iMinSAD, &newMV,                  meanx = 0.25;
                         pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);  
2848    
2849                          if (iSAD < iMinSAD)          if (4*meany > oldnum)
2850                    meany /= oldnum;
2851            else
2852                    meany = 0.25;
2853    
2854            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            } while ( (oldnum != num) && (num>= minblocks) );
2872    
2873            if (num < minblocks)
2874            {
2875                    const int iEdgedWidth = pParam->edged_width;
2876                    num = 0;
2877    
2878    /*              fprintf(stderr,"Warning! Unreliable GME (%d/%d blocks), falling back to translation.\n",num,MBh*MBw);
2879    */
2880                    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;
2881    
2882                    if (!(current->motion_flags & XVID_ME_GME_REFINE))
2883                            return gmc;
2884    
2885                    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                            const int mbnum = mx + my * MBw;
2889                            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  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.                  if (gmc.duv[0].x)
2901           By performing an optional local half-pixel search, we can refine this result even further.                          gmc.duv[0].x /= num;
2902                    if (gmc.duv[0].y)
2903                            gmc.duv[0].y /= num;
2904            } else {
2905    
2906                    gmc.duv[0].x=(int)(sol[0]+0.5);
2907                    gmc.duv[0].y=(int)(sol[3]+0.5);
2908    
2909                    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                    gmc.duv[2].x=-gmc.duv[1].y;             /* two warp points only */
2913                    gmc.duv[2].y=gmc.duv[1].x;
2914            }
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  step10_8:  /* or rather don't use too many blocks... */
2961          if (MotionFlags & PMV_HALFPELREFINE8)           // perform final half-pel step  /*
2962                  iMinSAD = PMVfastSearch8_Refine( pRef, pRefH, pRefV, pRefHV, cur,                  for (my = 1; my < (uint32_t)MBh-1; my++)
2963                                  x, y,                  for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2964                                  currMV, iMinSAD,                  {
2965                                  pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);                          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  step10_8b:                  }
2973    */
2974                    gmcminSAD = globalSAD(&bestwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
2975    
2976          currPMV->x = currMV->x - pmv[0].x;                  if ( (reference->coding_type == S_VOP)
2977          currPMV->y = currMV->y - pmv[0].y;                          && ( (reference->warp.duv[1].x != bestwp.duv[1].x)
2978                              || (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                              || (reference->warp.duv[2].y != bestwp.duv[2].y) ) )
2983                    {
2984                            gmcSAD = globalSAD(&reference->warp, pParam, pMBs,
2985                                                                    current, pRef, pCurr, GMCblock);
2986    
2987                            if (gmcSAD < gmcminSAD)
2988                            {       bestwp = reference->warp;
2989                                    gmcminSAD = gmcSAD;
2990                            }
2991                    }
2992    
2993            do {
2994                    direction = 0;
2995                    centerwp = bestwp;
2996    
2997                    currwp = centerwp;
2998    
2999                    currwp.duv[0].x--;
3000                    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                    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                    currwp = centerwp; currwp.duv[0].y++;
3028                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3029                    if (gmcSAD < gmcminSAD)
3030                    {       bestwp = currwp;
3031                            gmcminSAD = gmcSAD;
3032                            direction = 8;
3033                    }
3034                    }
3035                    if (direction) continue;
3036    
3037                    currwp = centerwp; currwp.duv[1].x++;
3038                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3039                    if (gmcSAD < gmcminSAD)
3040                    {       bestwp = currwp;
3041                            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
3060                    {
3061                    currwp = centerwp; currwp.duv[1].x++;
3062                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3063                    if (gmcSAD < gmcminSAD)
3064                    {       bestwp = currwp;
3065                            gmcminSAD = gmcSAD;
3066                            direction = 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
3080                    {
3081                    currwp = centerwp; currwp.duv[1].y++;
3082                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3083                    if (gmcSAD < gmcminSAD)
3084                    {       bestwp = currwp;
3085                            gmcminSAD = gmcSAD;
3086                            direction = 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
3099                    {
3100                    currwp = centerwp; currwp.duv[2].x++;
3101                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3102                    if (gmcSAD < gmcminSAD)
3103                    {       bestwp = currwp;
3104                            gmcminSAD = gmcSAD;
3105                            direction = 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
3118                    {
3119                    currwp = centerwp; currwp.duv[2].y++;
3120                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3121                    if (gmcSAD < gmcminSAD)
3122                    {       bestwp = currwp;
3123                            gmcminSAD = gmcSAD;
3124                            direction = 2048;
3125                    }
3126                    }
3127            } while (direction);
3128            free(GMCblock);
3129    
3130            *startwp = bestwp;
3131    
3132            return gmcminSAD;
3133    }
3134    
3135          return iMinSAD;  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.3  
changed lines
  Added in v.1129

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