[cvs] / xvidcore / src / motion / motion_est.c Repository:
ViewVC logotype

Diff of /xvidcore/src/motion/motion_est.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.1.44.2.1  
changed lines
  Added in v.1.58.2.29

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