[svn] / branches / dev-api-4 / xvidcore / src / motion / motion_est.c Repository:
ViewVC logotype

Diff of /branches/dev-api-4/xvidcore/src/motion/motion_est.c

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

trunk/xvidcore/src/motion/motion_est.c revision 348, Sun Jul 28 17:10:39 2002 UTC branches/dev-api-4/xvidcore/src/motion/motion_est.c revision 1137, Fri Sep 5 10:01:50 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: motion_est.c,v 1.58.2.34 2003-09-05 10:01:50 Isibaar Exp $
   
 /**************************************************************************  
  *  
  *  Modifications:  
  *  
  *      01.05.2002      updated MotionEstimationBVOP  
  *      25.04.2002 partial prevMB conversion  
  *  22.04.2002 remove some compile warning by chenm001 <chenm001@163.com>  
  *  14.04.2002 added MotionEstimationBVOP()  
  *  02.04.2002 add EPZS(^2) as ME algorithm, use PMV_USESQUARES to choose between  
  *             EPZS and EPZS^2  
  *  08.02.2002 split up PMVfast into three routines: PMVFast, PMVFast_MainLoop  
  *             PMVFast_Refine to support multiple searches with different start points  
  *  07.01.2002 uv-block-based interpolation  
  *  06.01.2002 INTER/INTRA-decision is now done before any SEARCH8 (speedup)  
  *             changed INTER_BIAS to 150 (as suggested by suxen_drol)  
  *             removed halfpel refinement step in PMVfastSearch8 + quality=5  
  *             added new quality mode = 6 which performs halfpel refinement  
  *             filesize difference between quality 5 and 6 is smaller than 1%  
  *             (Isibaar)  
  *  31.12.2001 PMVfastSearch16 and PMVfastSearch8 (gruel)  
  *  30.12.2001 get_range/MotionSearchX simplified; blue/green bug fix  
  *  22.12.2001 commented best_point==99 check  
  *  19.12.2001 modified get_range (purple bug fix)  
  *  15.12.2001 moved pmv displacement from mbprediction  
  *  02.12.2001 motion estimation/compensation split (Isibaar)  
  *  16.11.2001 rewrote/tweaked search algorithms; pross@cs.rmit.edu.au  
  *  10.11.2001 support for sad16/sad8 functions  
  *  28.08.2001 reactivated MODE_INTER4V for EXT_MODE  
  *  24.08.2001 removed MODE_INTER4V_Q, disabled MODE_INTER4V for EXT_MODE  
  *  22.08.2001 added MODE_INTER4V_Q  
  *  20.08.2001 added pragma to get rid of internal compiler error with VC6  
  *             idea by Cyril. Thanks.  
25   *   *
26   *  Michael Militzer <isibaar@videocoding.de>   ****************************************************************************/
  *  
  **************************************************************************/  
27    
28  #include <assert.h>  #include <assert.h>
29  #include <stdio.h>  #include <stdio.h>
30  #include <stdlib.h>  #include <stdlib.h>
31    #include <string.h>     /* memcpy */
32    #include <math.h>       /* lrint */
33    
34  #include "../encoder.h"  #include "../encoder.h"
35  #include "../utils/mbfunctions.h"  #include "../utils/mbfunctions.h"
36  #include "../prediction/mbprediction.h"  #include "../prediction/mbprediction.h"
37  #include "../global.h"  #include "../global.h"
38  #include "../utils/timer.h"  #include "../utils/timer.h"
39    #include "../image/interpolate8x8.h"
40    #include "motion_est.h"
41  #include "motion.h"  #include "motion.h"
42  #include "sad.h"  #include "sad.h"
43    #include "gmc.h"
44    #include "../utils/emms.h"
45    #include "../dct/fdct.h"
46    
47    /*****************************************************************************
48     * Modified rounding tables -- declared in motion.h
49     * Original tables see ISO spec tables 7-6 -> 7-9
50     ****************************************************************************/
51    
52    const uint32_t roundtab[16] =
53    {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2 };
54    
55    /* K = 4 */
56    const uint32_t roundtab_76[16] =
57    { 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1 };
58    
59    /* K = 2 */
60    const uint32_t roundtab_78[8] =
61    { 0, 0, 1, 1, 0, 0, 0, 1  };
62    
63    /* K = 1 */
64    const uint32_t roundtab_79[4] =
65    { 0, 1, 0, 0 };
66    
67    #define INITIAL_SKIP_THRESH     (10)
68    #define FINAL_SKIP_THRESH       (50)
69    #define MAX_SAD00_FOR_SKIP      (20)
70    #define MAX_CHROMA_SAD_FOR_SKIP (22)
71    
72    #define CHECK_CANDIDATE(X,Y,D) { \
73    CheckCandidate((X),(Y), data, (D) ); }
74    
75    
76    /*****************************************************************************
77     * Code
78     ****************************************************************************/
79    
80    static __inline uint32_t
81    d_mv_bits(int x, int y, const VECTOR pred, const uint32_t iFcode, const int qpel, const int rrv)
82    {
83            int bits;
84            const int q = (1 << (iFcode - 1)) - 1;
85    
86            x <<= qpel;
87  static int32_t lambda_vec16[32] =       /* rounded values for lambda param for weight of motion bits as in modified H.26L */          y <<= qpel;
88  { 0, (int) (1.00235 + 0.5), (int) (1.15582 + 0.5), (int) (1.31976 + 0.5),          if (rrv) { x = RRV_MV_SCALEDOWN(x); y = RRV_MV_SCALEDOWN(y); }
89                  (int) (1.49591 + 0.5), (int) (1.68601 + 0.5),  
90          (int) (1.89187 + 0.5), (int) (2.11542 + 0.5), (int) (2.35878 + 0.5),          x -= pred.x;
91                  (int) (2.62429 + 0.5), (int) (2.91455 + 0.5),          bits = (x != 0 ? iFcode:0);
92          (int) (3.23253 + 0.5), (int) (3.58158 + 0.5), (int) (3.96555 + 0.5),          x = abs(x);
93                  (int) (4.38887 + 0.5), (int) (4.85673 + 0.5),          x += q;
94          (int) (5.37519 + 0.5), (int) (5.95144 + 0.5), (int) (6.59408 + 0.5),          x >>= (iFcode - 1);
95                  (int) (7.31349 + 0.5), (int) (8.12242 + 0.5),          bits += mvtab[x];
96          (int) (9.03669 + 0.5), (int) (10.0763 + 0.5), (int) (11.2669 + 0.5),  
97                  (int) (12.6426 + 0.5), (int) (14.2493 + 0.5),          y -= pred.y;
98          (int) (16.1512 + 0.5), (int) (18.442 + 0.5), (int) (21.2656 + 0.5),          bits += (y != 0 ? iFcode:0);
99                  (int) (24.8580 + 0.5), (int) (29.6436 + 0.5),          y = abs(y);
100          (int) (36.4949 + 0.5)          y += q;
101            y >>= (iFcode - 1);
102            bits += mvtab[y];
103    
104            return bits;
105    }
106    
107    static int32_t ChromaSAD2(const int fx, const int fy, const int bx, const int by,
108                                                            const SearchData * const data)
109    {
110            int sad;
111            const uint32_t stride = data->iEdgedWidth/2;
112            uint8_t *f_refu, *f_refv, *b_refu, *b_refv;
113    
114            const INTERPOLATE8X8_PTR interpolate8x8_halfpel[] = {
115                    NULL,
116                    interpolate8x8_halfpel_v,
117                    interpolate8x8_halfpel_h,
118                    interpolate8x8_halfpel_hv
119  };  };
120    
121  static int32_t *lambda_vec8 = lambda_vec16;     /* same table for INTER and INTER4V for now */          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  // mv.length table          if (filter != 0) {
138  static const uint32_t mvtab[33] = {                  b_refu = data->RefQ + 16;
139          1, 2, 3, 4, 6, 7, 7, 7,                  b_refv = data->RefQ + 24;
140          9, 9, 9, 10, 10, 10, 10, 10,                  interpolate8x8_halfpel[filter](b_refu, data->b_RefP[4] + offset, stride, data->rounding);
141          10, 10, 10, 10, 10, 10, 10, 10,                  interpolate8x8_halfpel[filter](b_refv, data->b_RefP[5] + offset, stride, data->rounding);
142          10, 11, 11, 11, 11, 11, 11, 12, 12          } 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  static __inline uint32_t          return sad;
151  mv_bits(int32_t component,  }
152                  const uint32_t iFcode)  
153    static int32_t
154    ChromaSAD(const int dx, const int dy, const SearchData * const data)
155  {  {
156          if (component == 0)          int sad;
157                  return 1;          const uint32_t stride = data->iEdgedWidth/2;
158            int offset = (dx>>1) + (dy>>1)*stride;
159            int next = 1;
160    
161          if (component < 0)          if (dx == data->temp[5] && dy == data->temp[6]) return data->temp[7]; /* it has been checked recently */
162                  component = -component;          data->temp[5] = dx; data->temp[6] = dy; /* backup */
163    
164          if (iFcode == 1) {          switch (((dx & 1) << 1) | (dy & 1))     {
165                  if (component > 32)                  case 0:
166                          component = 32;                          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                  return mvtab[component] + 1;                          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          component += (1 << (iFcode - 1)) - 1;          return sad;
         component >>= (iFcode - 1);  
   
         if (component > 32)  
                 component = 32;  
   
         return mvtab[component] + 1 + iFcode - 1;  
185  }  }
186    
187    static __inline const uint8_t *
188  static __inline uint32_t  GetReferenceB(const int x, const int y, const uint32_t dir, const SearchData * const data)
 calc_delta_16(const int32_t dx,  
                           const int32_t dy,  
                           const uint32_t iFcode,  
                           const uint32_t iQuant)  
189  {  {
190          return NEIGH_TEND_16X16 * lambda_vec16[iQuant] * (mv_bits(dx, iFcode) +          /* dir : 0 = forward, 1 = backward */
191                                                                                                            mv_bits(dy, iFcode));          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  static __inline uint32_t  /* this is a simpler copy of GetReferenceB, but as it's __inline anyway, we can keep the two separate */
198  calc_delta_8(const int32_t dx,  static __inline const uint8_t *
199                           const int32_t dy,  GetReference(const int x, const int y, const SearchData * const data)
                          const uint32_t iFcode,  
                          const uint32_t iQuant)  
200  {  {
201          return NEIGH_TEND_8X8 * lambda_vec8[iQuant] * (mv_bits(dx, iFcode) +          const int picture = ((x&1)<<1) | (y&1);
202                                                                                                     mv_bits(dy, iFcode));          const int offset = (x>>1) + (y>>1)*data->iEdgedWidth;
203            return data->RefP[picture] + offset;
204  }  }
205    
206  bool  static uint8_t *
207  MotionEstimation(MBParam * const pParam,  Interpolate8x8qpel(const int x, const int y, const uint32_t block, const uint32_t dir, const SearchData * const data)
                                  FRAMEINFO * const current,  
                                  FRAMEINFO * const reference,  
                                  const IMAGE * const pRefH,  
                                  const IMAGE * const pRefV,  
                                  const IMAGE * const pRefHV,  
                                  const uint32_t iLimit)  
208  {  {
209          const uint32_t iWcount = pParam->mb_width;          /* create or find a qpel-precision reference picture; return pointer to it */
210          const uint32_t iHcount = pParam->mb_height;          uint8_t * Reference = data->RefQ + 16*dir;
211          MACROBLOCK *const pMBs = current->mbs;          const uint32_t iEdgedWidth = data->iEdgedWidth;
212          MACROBLOCK *const prevMBs = reference->mbs;          const uint32_t rounding = data->rounding;
213          const IMAGE *const pCurrent = &current->image;          const int halfpel_x = x/2;
214          const IMAGE *const pRef = &reference->image;          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          static const VECTOR zeroMV = { 0, 0 };          case 1: /* x halfpel, y qpel - top or bottom during qpel refinement */
232          VECTOR predMV;                  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          int32_t x, y;          case 2: /* x qpel, y halfpel - left or right during qpel refinement */
238          int32_t iIntra = 0;                  ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
239          VECTOR pmv;                  ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
240                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
241                    break;
242    
243          if (sadInit)          default: /* pure halfpel position */
244                  (*sadInit) ();                  return (uint8_t *) ref1;
245    
246          for (y = 0; y < iHcount; y++)   {          }
247                  for (x = 0; x < iWcount; x ++)  {          return Reference;
248    }
249    
250                          MACROBLOCK *const pMB = &pMBs[x + y * iWcount];  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                          predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          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                          pMB->sad16 =          case 1: /* x halfpel, y qpel - top or bottom during qpel refinement */
278                                  SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
279                                                   x, y, predMV.x, predMV.y, predMV.x, predMV.y,                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
280                                                   current->motion_flags, current->quant,                  interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
281                                                   current->fcode, pParam, pMBs, prevMBs, &pMB->mv16,                  interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
282                                                   &pMB->pmvs[0]);                  interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
283                    break;
284    
285                          if (0 < (pMB->sad16 - MV16_INTER_BIAS)) {          case 2: /* x qpel, y halfpel - left or right during qpel refinement */
286                                  int32_t deviation;                  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    
                                 deviation =  
                                         dev16(pCurrent->y + x * 16 + y * 16 * pParam->edged_width,  
                                                   pParam->edged_width);  
293    
294                                  if (deviation < (pMB->sad16 - MV16_INTER_BIAS)) {          default: /* pure halfpel position */
295                                          pMB->mode = MODE_INTRA;                  return (uint8_t *) ref1;
296                                          pMB->mv16 = pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =          }
297                                                  pMB->mvs[3] = zeroMV;          return Reference;
298                                          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =  }
                                                 pMB->sad8[3] = 0;  
299    
300                                          iIntra++;  /* CHECK_CANDIATE FUNCTIONS START */
                                         if (iIntra >= iLimit)  
                                                 return 1;  
301    
302                                          continue;  static void
303    CheckCandidate16(const int x, const int y, const SearchData * const data, const int Direction)
304    {
305            int xc, yc;
306            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)
311                    || (y > data->max_dy) || (y < data->min_dy) ) return;
312    
313            if (!data->qpel_precision) {
314                    Reference = GetReference(x, y, data);
315                    current = data->currentMV;
316                    xc = x; yc = y;
317            } 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                          pmv = pMB->pmvs[0];          if (data->temp[0] < data->iMinSAD[1]) {
340                          if (current->global_flags & XVID_INTER4V)                  data->iMinSAD[1] = data->temp[0]; current[1].x = x; current[1].y = y; }
341                                  if ((!(current->global_flags & XVID_LUMIMASKING) ||          if (data->temp[1] < data->iMinSAD[2]) {
342                                           pMB->dquant == NO_CHANGE)) {                  data->iMinSAD[2] = data->temp[1]; current[2].x = x; current[2].y = y; }
343                                          int32_t sad8 = IMV16X16 * current->quant;          if (data->temp[2] < data->iMinSAD[3]) {
344                    data->iMinSAD[3] = data->temp[2]; current[3].x = x; current[3].y = y; }
345                                          if (sad8 < pMB->sad16) {          if (data->temp[3] < data->iMinSAD[4]) {
346                                                  sad8 += pMB->sad8[0] =                  data->iMinSAD[4] = data->temp[3]; current[4].x = x; current[4].y = y; }
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x, 2 * y,  
                                                                         pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,  
                                                                         current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[0],  
                                                                         &pMB->pmvs[0]);  
                                         }  
                                         if (sad8 < pMB->sad16) {  
   
                                                 predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 1);  
                                                 sad8 += pMB->sad8[1] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x + 1, 2 * y,  
                                                                         pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,  
                                                                         current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[1],  
                                                                         &pMB->pmvs[1]);  
                                         }  
                                         if (sad8 < pMB->sad16) {  
                                                 predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 2);  
                                                 sad8 += pMB->sad8[2] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x, 2 * y + 1,  
                                                                         pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,  
                                                                         current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[2],  
                                                                         &pMB->pmvs[2]);  
                                         }  
                                         if (sad8 < pMB->sad16) {  
                                                 predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 3);  
                                                 sad8 += pMB->sad8[3] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x + 1, 2 * y + 1,  
                                                                         pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,  
                                                                         current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs,  
                                                                         &pMB->mvs[3],  
                                                                         &pMB->pmvs[3]);  
347                                          }                                          }
348    
349                                          /* decide: MODE_INTER or MODE_INTER4V  static void
350                                             mpeg4:   if (sad8 < pMB->sad16 - nb/2+1) use_inter4v  CheckCandidate16_subpel(const int x, const int y, const SearchData * const data, const int Direction)
351                                           */  {
352            int xc, yc;
353            const uint8_t *Reference;
354            VECTOR *current, *current2;
355            int32_t sad; uint32_t t;
356    
357                                          if (sad8 < pMB->sad16) {          if ( (x > data->max_dx) || (x < data->min_dx)
358                                                  pMB->mode = MODE_INTER4V;                  || (y > data->max_dy) || (y < data->min_dy) ) return;
359                                                  pMB->sad8[0] *= 4;  
360                                                  pMB->sad8[1] *= 4;          if (!data->qpel_precision) {
361                                                  pMB->sad8[2] *= 4;                  Reference = GetReference(x, y, data);
362                                                  pMB->sad8[3] *= 4;                  current = data->currentMV;
363                                                  continue;                  current2 = data->currentMV2;
364                    xc = x; yc = y;
365            } else { /* x and y are in 1/4 precision */
366                    Reference = Interpolate16x16qpel(x, y, 0, data);
367                    xc = x/2; yc = y/2; /* for chroma sad */
368                    current = data->currentQMV;
369                    current2 = data->currentQMV2;
370                                          }                                          }
371    
372            sad = sad16v(data->Cur, Reference, data->iEdgedWidth, data->temp);
373            t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
374    
375            sad += (data->lambda16 * t * sad)>>10;
376            data->temp[0] += (data->lambda8 * t * (data->temp[0] + NEIGH_8X8_BIAS))>>10;
377    
378            if (data->chroma && sad < data->iMinSAD[0])
379                    sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
380                                                            (yc >> 1) + roundtab_79[yc & 0x3], data);
381    
382            if (data->temp[0] < data->iMinSAD[1]) {
383                    data->iMinSAD[1] = data->temp[0]; current[1].x = x; current[1].y = y; }
384            if (data->temp[1] < data->iMinSAD[2]) {
385                    data->iMinSAD[2] = data->temp[1]; current[2].x = x; current[2].y = y; }
386            if (data->temp[2] < data->iMinSAD[3]) {
387                    data->iMinSAD[3] = data->temp[2]; current[3].x = x; current[3].y = y; }
388            if (data->temp[3] < data->iMinSAD[4]) {
389                    data->iMinSAD[4] = data->temp[3]; current[4].x = x; current[4].y = y; }
390    
391            if (sad < data->iMinSAD[0]) {
392                    *(data->iMinSAD2) = *(data->iMinSAD);
393                    current2->x = current->x; current2->y = current->y;
394    
395                    data->iMinSAD[0] = sad;
396                    current[0].x = x; current[0].y = y;
397                    *data->dir = Direction;
398                    return;
399                                  }                                  }
400    
401                          pMB->mode = MODE_INTER;          if (sad < *(data->iMinSAD2)) {
402                          pMB->pmvs[0] = pmv;     /* pMB->pmvs[1] = pMB->pmvs[2] = pMB->pmvs[3]  are not needed for INTER */                  *(data->iMinSAD2) = sad;
403                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mv16;                  current2->x = x; current2->y = y;
404                          pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] =                  *data->dir = Direction;
                                 pMB->sad16;  
405                          }                          }
406                          }                          }
407    
408          return 0;  static void
409    CheckCandidate8(const int x, const int y, const SearchData * const data, const int Direction)
410    {
411            int32_t sad; uint32_t t;
412            const uint8_t * Reference;
413            VECTOR * current;
414    
415            if ( (x > data->max_dx) || (x < data->min_dx)
416                    || (y > data->max_dy) || (y < data->min_dy) ) return;
417    
418            if (!data->qpel_precision) {
419                    Reference = GetReference(x, y, data);
420                    current = data->currentMV;
421            } else { /* x and y are in 1/4 precision */
422                    Reference = Interpolate8x8qpel(x, y, 0, 0, data);
423                    current = data->currentQMV;
424  }  }
425    
426            sad = sad8(data->Cur, Reference, data->iEdgedWidth);
427            t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
428    
429  #define CHECK_MV16_ZERO {\          sad += (data->lambda8 * t * (sad+NEIGH_8X8_BIAS))>>10;
430    if ( (0 <= max_dx) && (0 >= min_dx) \  
431      && (0 <= max_dy) && (0 >= min_dy) ) \          if (sad < *(data->iMinSAD)) {
432    { \                  *(data->iMinSAD) = sad;
433      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \                  current->x = x; current->y = y;
434      iSAD += calc_delta_16(-center_x, -center_y, (uint8_t)iFcode, iQuant);\                  *data->dir = Direction;
435      if (iSAD < iMinSAD) \          }
     {  iMinSAD=iSAD; currMV->x=0; currMV->y=0; }  }     \  
 }  
   
 #define NOCHECK_MV16_CANDIDATE(X,Y) { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \  
 }  
   
 #define CHECK_MV16_CANDIDATE(X,Y) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_CANDIDATE_DIR(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \  
 }  
   
 #define CHECK_MV16_CANDIDATE_FOUND(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
 }  
   
   
 #define CHECK_MV8_ZERO {\  
   iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, 0, 0 , iEdgedWidth), iEdgedWidth); \  
   iSAD += calc_delta_8(-center_x, -center_y, (uint8_t)iFcode, iQuant);\  
   if (iSAD < iMinSAD) \  
   { iMinSAD=iSAD; currMV->x=0; currMV->y=0; } \  
 }  
   
 #define NOCHECK_MV8_CANDIDATE(X,Y) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \  
 }  
   
 #define CHECK_MV8_CANDIDATE(X,Y) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV8_CANDIDATE_DIR(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \  
 }  
   
 #define CHECK_MV8_CANDIDATE_FOUND(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
436  }  }
437    
438  /* too slow and not fully functional at the moment */  static void
439  /*  CheckCandidate32(const int x, const int y, const SearchData * const data, const int Direction)
 int32_t ZeroSearch16(  
                                         const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const IMAGE * const pCur,  
                                         const int x, const int y,  
                                         const uint32_t MotionFlags,  
                                         const uint32_t iQuant,  
                                         const uint32_t iFcode,  
                                         MBParam * const pParam,  
                                         const MACROBLOCK * const pMBs,  
                                         const MACROBLOCK * const prevMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
440  {  {
441          const int32_t iEdgedWidth = pParam->edged_width;          uint32_t t;
442          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;          const uint8_t * Reference;
443          int32_t iSAD;          int sad;
         VECTOR pred;  
444    
445            if ( (!(x&1) && x !=0) || (!(y&1) && y !=0) || /* non-zero even value */
446                    (x > data->max_dx) || (x < data->min_dx)
447                    || (y > data->max_dy) || (y < data->min_dy) ) return;
448    
449          pred = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          Reference = GetReference(x, y, data);
450            t = d_mv_bits(x, y, data->predMV, data->iFcode, 0, 1);
451    
452          iSAD = sad16( cur,          sad = sad32v_c(data->Cur, Reference, data->iEdgedWidth, data->temp);
                 get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth),  
                 iEdgedWidth, MV_MAX_ERROR);  
         if (iSAD <= iQuant * 96)  
                 iSAD -= MV16_00_BIAS;  
453    
454          currMV->x = 0;          sad += (data->lambda16 * t * sad) >> 10;
455          currMV->y = 0;          data->temp[0] += (data->lambda8 * t * (data->temp[0] + NEIGH_8X8_BIAS))>>10;
         currPMV->x = -pred.x;  
         currPMV->y = -pred.y;  
   
         return iSAD;  
456    
457            if (sad < data->iMinSAD[0]) {
458                    data->iMinSAD[0] = sad;
459                    data->currentMV[0].x = x; data->currentMV[0].y = y;
460                    *data->dir = Direction;
461  }  }
 */  
462    
463  int32_t          if (data->temp[0] < data->iMinSAD[1]) {
464  Diamond16_MainSearch(const uint8_t * const pRef,                  data->iMinSAD[1] = data->temp[0]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
465                                           const uint8_t * const pRefH,          if (data->temp[1] < data->iMinSAD[2]) {
466                                           const uint8_t * const pRefV,                  data->iMinSAD[2] = data->temp[1]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
467                                           const uint8_t * const pRefHV,          if (data->temp[2] < data->iMinSAD[3]) {
468                                           const uint8_t * const cur,                  data->iMinSAD[3] = data->temp[2]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
469                                           const int x,          if (data->temp[3] < data->iMinSAD[4]) {
470                                           const int y,                  data->iMinSAD[4] = data->temp[3]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
                                    const int start_x,  
                                    const int start_y,  
                                    int iMinSAD,  
                                    VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                          const int32_t min_dx,  
                                          const int32_t max_dx,  
                                          const int32_t min_dy,  
                                          const int32_t max_dy,  
                                          const int32_t iEdgedWidth,  
                                          const int32_t iDiamondSize,  
                                          const int32_t iFcode,  
                                          const int32_t iQuant,  
                                          int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iDirectionBackup;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
   
         if (iDirection) {  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;  
                         iDirectionBackup = iDirection;  
   
                         if (iDirectionBackup != 2)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                    backupMV.y, 1);  
                         if (iDirectionBackup != 1)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                    backupMV.y, 2);  
                         if (iDirectionBackup != 4)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,  
                                                                                    backupMV.y - iDiamondSize, 3);  
                         if (iDirectionBackup != 3)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,  
                                                                                    backupMV.y + iDiamondSize, 4);  
471                  }                  }
472    
473    static void
474    CheckCandidate16no4v(const int x, const int y, const SearchData * const data, const int Direction)
475    {
476            int32_t sad, xc, yc;
477            const uint8_t * Reference;
478            uint32_t t;
479            VECTOR * current;
480    
481            if ( (x > data->max_dx) || ( x < data->min_dx)
482                    || (y > data->max_dy) || (y < data->min_dy) ) return;
483    
484            if (data->rrv && (!(x&1) && x !=0) | (!(y&1) && y !=0) ) return; /* non-zero even value */
485    
486            if (data->qpel_precision) { /* x and y are in 1/4 precision */
487                    Reference = Interpolate16x16qpel(x, y, 0, data);
488                    current = data->currentQMV;
489                    xc = x/2; yc = y/2;
490          } else {          } else {
491                  currMV->x = start_x;                  Reference = GetReference(x, y, data);
492                  currMV->y = start_y;                  current = data->currentMV;
493                    xc = x; yc = y;
494            }
495            t = d_mv_bits(x, y, data->predMV, data->iFcode,
496                                            data->qpel^data->qpel_precision, data->rrv);
497    
498            sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
499            sad += (data->lambda16 * t * sad)>>10;
500    
501            if (data->chroma && sad < *data->iMinSAD)
502                    sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
503                                                            (yc >> 1) + roundtab_79[yc & 0x3], data);
504    
505            if (sad < *(data->iMinSAD)) {
506                    *(data->iMinSAD) = sad;
507                    current->x = x; current->y = y;
508                    *data->dir = Direction;
509          }          }
         return iMinSAD;  
510  }  }
511    
512  int32_t  static void
513  Square16_MainSearch(const uint8_t * const pRef,  CheckCandidate16I(const int x, const int y, const SearchData * const data, const int Direction)
514                                          const uint8_t * const pRefH,  {
515                                          const uint8_t * const pRefV,          int sad;
516                                          const uint8_t * const pRefHV,  //      int xc, yc;
517                                          const uint8_t * const cur,          const uint8_t * Reference;
518                                          const int x,  //      VECTOR * current;
519                                          const int y,  
520                                     const int start_x,          if ( (x > data->max_dx) || ( x < data->min_dx)
521                                     const int start_y,                  || (y > data->max_dy) || (y < data->min_dy) ) return;
522                                     int iMinSAD,  
523                                     VECTOR * const currMV,          Reference = GetReference(x, y, data);
524                                     const int center_x,  //      xc = x; yc = y;
525                                     const int center_y,  
526                                          const int32_t min_dx,          sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
527                                          const int32_t max_dx,  //      sad += d_mv_bits(x, y, data->predMV, data->iFcode, 0, 0);
528                                          const int32_t min_dy,  
529                                          const int32_t max_dy,  /*      if (data->chroma) sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
530                                          const int32_t iEdgedWidth,                                                                                  (yc >> 1) + roundtab_79[yc & 0x3], data);
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a square search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* It's one search with full square pattern, and new parts for all following diamonds */  
   
 /*   new direction are extra, so 1-4 is normal diamond  
       537  
       1*2  
       648  
531  */  */
532    
533          CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);          if (sad < data->iMinSAD[0]) {
534          CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);                  data->iMinSAD[0] = sad;
535          CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);                  data->currentMV[0].x = x; data->currentMV[0].y = y;
536          CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);                  *data->dir = Direction;
537            }
538          CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  }
                                                          backupMV.y - iDiamondSize, 5);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 6);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 7);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 8);  
   
   
         if (iDirection) {  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;  
539    
540                          switch (iDirection) {  static void
541                          case 1:  CheckCandidate32I(const int x, const int y, const SearchData * const data, const int Direction)
542                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  {
543                                                                                     backupMV.y, 1);          /* maximum speed - for P/B/I decision */
544                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          int32_t sad;
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
                         case 2:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
545    
546                          case 3:          if ( (x > data->max_dx) || (x < data->min_dx)
547                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                  || (y > data->max_dy) || (y < data->min_dy) ) return;
                                                                                  4);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
548    
549                          case 4:          sad = sad32v_c(data->Cur, data->RefP[0] + x + y*((int)data->iEdgedWidth),
550                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,                                          data->iEdgedWidth, data->temp);
                                                                                  3);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 break;  
   
                         case 5:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
   
                         case 6:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
   
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
551    
552                                  break;          if (sad < *(data->iMinSAD)) {
553                    *(data->iMinSAD) = sad;
554                    data->currentMV[0].x = x; data->currentMV[0].y = y;
555                    *data->dir = Direction;
556            }
557            if (data->temp[0] < data->iMinSAD[1]) {
558                    data->iMinSAD[1] = data->temp[0]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
559            if (data->temp[1] < data->iMinSAD[2]) {
560                    data->iMinSAD[2] = data->temp[1]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
561            if (data->temp[2] < data->iMinSAD[3]) {
562                    data->iMinSAD[3] = data->temp[2]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
563            if (data->temp[3] < data->iMinSAD[4]) {
564                    data->iMinSAD[4] = data->temp[3]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
565    
566                          case 7:  }
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                    backupMV.y, 1);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
567    
568                          case 8:  static void
569                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  CheckCandidateInt(const int xf, const int yf, const SearchData * const data, const int Direction)
570                                                                                   2);  {
571                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,          int32_t sad, xb, yb, xcf, ycf, xcb, ycb;
572                                                                                   4);          uint32_t t;
573                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          const uint8_t *ReferenceF, *ReferenceB;
574                                                                                   backupMV.y + iDiamondSize, 6);          VECTOR *current;
575                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
576                                                                                   backupMV.y - iDiamondSize, 7);          if ((xf > data->max_dx) || (xf < data->min_dx) ||
577                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                  (yf > data->max_dy) || (yf < data->min_dy))
578                                                                                   backupMV.y + iDiamondSize, 8);                  return;
579                                  break;  
580                          default:          if (!data->qpel_precision) {
581                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,                  ReferenceF = GetReference(xf, yf, data);
582                                                                                   1);                  xb = data->currentMV[1].x; yb = data->currentMV[1].y;
583                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,                  ReferenceB = GetReferenceB(xb, yb, 1, data);
584                                                                                   2);                  current = data->currentMV;
585                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,                  xcf = xf; ycf = yf;
586                                                                                   3);                  xcb = xb; ycb = yb;
587                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,          } else {
588                                                                                   4);                  ReferenceF = Interpolate16x16qpel(xf, yf, 0, data);
589                    xb = data->currentQMV[1].x; yb = data->currentQMV[1].y;
590                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  current = data->currentQMV;
591                                                                                   backupMV.y - iDiamondSize, 5);                  ReferenceB = Interpolate16x16qpel(xb, yb, 1, data);
592                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  xcf = xf/2; ycf = yf/2;
593                                                                                   backupMV.y + iDiamondSize, 6);                  xcb = xb/2; ycb = yb/2;
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
594                          }                          }
595    
596            t = d_mv_bits(xf, yf, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0)
597                     + d_mv_bits(xb, yb, data->bpredMV, data->iFcode, data->qpel^data->qpel_precision, 0);
598    
599            sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
600            sad += (data->lambda16 * t * sad)>>10;
601    
602            if (data->chroma && sad < *data->iMinSAD)
603                    sad += ChromaSAD2((xcf >> 1) + roundtab_79[xcf & 0x3],
604                                                            (ycf >> 1) + roundtab_79[ycf & 0x3],
605                                                            (xcb >> 1) + roundtab_79[xcb & 0x3],
606                                                            (ycb >> 1) + roundtab_79[ycb & 0x3], data);
607    
608            if (sad < *(data->iMinSAD)) {
609                    *(data->iMinSAD) = sad;
610                    current->x = xf; current->y = yf;
611                    *data->dir = Direction;
612                  }                  }
613    }
614    
615    static void
616    CheckCandidateDirect(const int x, const int y, const SearchData * const data, const int Direction)
617    {
618            int32_t sad = 0, xcf = 0, ycf = 0, xcb = 0, ycb = 0;
619            uint32_t k;
620            const uint8_t *ReferenceF;
621            const uint8_t *ReferenceB;
622            VECTOR mvs, b_mvs;
623    
624            if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
625    
626            for (k = 0; k < 4; k++) {
627                    mvs.x = data->directmvF[k].x + x;
628                    b_mvs.x = ((x == 0) ?
629                            data->directmvB[k].x
630                            : mvs.x - data->referencemv[k].x);
631    
632                    mvs.y = data->directmvF[k].y + y;
633                    b_mvs.y = ((y == 0) ?
634                            data->directmvB[k].y
635                            : mvs.y - data->referencemv[k].y);
636    
637                    if ((mvs.x > data->max_dx)   || (mvs.x < data->min_dx)   ||
638                            (mvs.y > data->max_dy)   || (mvs.y < data->min_dy)   ||
639                            (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) )
641                            return;
642    
643                    if (data->qpel) {
644                            xcf += mvs.x/2; ycf += mvs.y/2;
645                            xcb += b_mvs.x/2; ycb += b_mvs.y/2;
646          } else {          } else {
647                  currMV->x = start_x;                          xcf += mvs.x; ycf += mvs.y;
648                  currMV->y = start_y;                          xcb += b_mvs.x; ycb += b_mvs.y;
649                            mvs.x *= 2; mvs.y *= 2; /* we move to qpel precision anyway */
650                            b_mvs.x *= 2; b_mvs.y *= 2;
651          }          }
652          return iMinSAD;  
653                    ReferenceF = Interpolate8x8qpel(mvs.x, mvs.y, k, 0, data);
654                    ReferenceB = Interpolate8x8qpel(b_mvs.x, b_mvs.y, k, 1, data);
655    
656                    sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
657                                                    ReferenceF, ReferenceB, data->iEdgedWidth);
658                    if (sad > *(data->iMinSAD)) return;
659  }  }
660    
661            sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;
662    
663  int32_t          if (data->chroma && sad < *data->iMinSAD)
664  Full16_MainSearch(const uint8_t * const pRef,                  sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],
665                                    const uint8_t * const pRefH,                                                          (ycf >> 3) + roundtab_76[ycf & 0xf],
666                                    const uint8_t * const pRefV,                                                          (xcb >> 3) + roundtab_76[xcb & 0xf],
667                                    const uint8_t * const pRefHV,                                                          (ycb >> 3) + roundtab_76[ycb & 0xf], data);
                                   const uint8_t * const cur,  
                                   const int x,  
                                   const int y,  
                                    const int start_x,  
                                    const int start_y,  
                                    int iMinSAD,  
                                    VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                   const int32_t min_dx,  
                                   const int32_t max_dx,  
                                   const int32_t min_dy,  
                                   const int32_t max_dy,  
                                   const int32_t iEdgedWidth,  
                                   const int32_t iDiamondSize,  
                                   const int32_t iFcode,  
                                   const int32_t iQuant,  
                                   int iFound)  
 {  
         int32_t iSAD;  
         int32_t dx, dy;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV16_CANDIDATE(dx, dy);  
668    
669          return iMinSAD;          if (sad < *(data->iMinSAD)) {
670                    *(data->iMinSAD) = sad;
671                    data->currentMV->x = x; data->currentMV->y = y;
672                    *data->dir = Direction;
673            }
674  }  }
675    
676  int32_t  static void
677  AdvDiamond16_MainSearch(const uint8_t * const pRef,  CheckCandidateDirectno4v(const int x, const int y, const SearchData * const data, const int Direction)
                                                 const uint8_t * const pRefH,  
                                                 const uint8_t * const pRefV,  
                                                 const uint8_t * const pRefHV,  
                                                 const uint8_t * const cur,  
                                                 const int x,  
                                                 const int y,  
                                            int start_x,  
                                            int start_y,  
                                            int iMinSAD,  
                                            VECTOR * const currMV,  
                                            const int center_x,  
                                            const int center_y,  
                                                 const int32_t min_dx,  
                                                 const int32_t max_dx,  
                                                 const int32_t min_dy,  
                                                 const int32_t max_dy,  
                                                 const int32_t iEdgedWidth,  
                                                 const int32_t iDiamondSize,  
                                                 const int32_t iFcode,  
                                                 const int32_t iQuant,  
                                                 int iDirection)  
678  {  {
679            int32_t sad, xcf, ycf, xcb, ycb;
680            const uint8_t *ReferenceF;
681            const uint8_t *ReferenceB;
682            VECTOR mvs, b_mvs;
683    
684          int32_t iSAD;          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
685    
686  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */          mvs.x = data->directmvF[0].x + x;
687            b_mvs.x = ((x == 0) ?
688                    data->directmvB[0].x
689                    : mvs.x - data->referencemv[0].x);
690    
691          if (iDirection) {          mvs.y = data->directmvF[0].y + y;
692                  CHECK_MV16_CANDIDATE(start_x - iDiamondSize, start_y);          b_mvs.y = ((y == 0) ?
693                  CHECK_MV16_CANDIDATE(start_x + iDiamondSize, start_y);                  data->directmvB[0].y
694                  CHECK_MV16_CANDIDATE(start_x, start_y - iDiamondSize);                  : mvs.y - data->referencemv[0].y);
                 CHECK_MV16_CANDIDATE(start_x, start_y + iDiamondSize);  
         } else {  
                 int bDirection = 1 + 2 + 4 + 8;  
695    
696                  do {          if ( (mvs.x > data->max_dx) || (mvs.x < data->min_dx)
697                          iDirection = 0;                  || (mvs.y > data->max_dy) || (mvs.y < data->min_dy)
698                          if (bDirection & 1)     //we only want to check left if we came from the right (our last motion was to the left, up-left or down-left)                  || (b_mvs.x > data->max_dx) || (b_mvs.x < data->min_dx)
699                                  CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);                  || (b_mvs.y > data->max_dy) || (b_mvs.y < data->min_dy) ) return;
700    
701                          if (bDirection & 2)          if (data->qpel) {
702                                  CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);                  xcf = 4*(mvs.x/2); ycf = 4*(mvs.y/2);
703                    xcb = 4*(b_mvs.x/2); ycb = 4*(b_mvs.y/2);
704                    ReferenceF = Interpolate16x16qpel(mvs.x, mvs.y, 0, data);
705                    ReferenceB = Interpolate16x16qpel(b_mvs.x, b_mvs.y, 1, data);
706            } else {
707                    xcf = 4*mvs.x; ycf = 4*mvs.y;
708                    xcb = 4*b_mvs.x; ycb = 4*b_mvs.y;
709                    ReferenceF = GetReference(mvs.x, mvs.y, data);
710                    ReferenceB = GetReferenceB(b_mvs.x, b_mvs.y, 1, data);
711            }
712    
713                          if (bDirection & 4)          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
714                                  CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);          sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;
715    
716                          if (bDirection & 8)          if (data->chroma && sad < *data->iMinSAD)
717                                  CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);                  sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],
718                                                            (ycf >> 3) + roundtab_76[ycf & 0xf],
719                                                            (xcb >> 3) + roundtab_76[xcb & 0xf],
720                                                            (ycb >> 3) + roundtab_76[ycb & 0xf], data);
721    
722                          /* now we're doing diagonal checks near our candidate */          if (sad < *(data->iMinSAD)) {
723                    *(data->iMinSAD) = sad;
724                    data->currentMV->x = x; data->currentMV->y = y;
725                    *data->dir = Direction;
726            }
727    }
728    
729                          if (iDirection)         //checking if anything found  
730                          {  static void
731                                  bDirection = iDirection;  CheckCandidateRD16(const int x, const int y, const SearchData * const data, const int Direction)
                                 iDirection = 0;  
                                 start_x = currMV->x;  
                                 start_y = currMV->y;  
                                 if (bDirection & 3)     //our candidate is left or right  
732                                  {                                  {
733                                          CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
734                                          CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);          int16_t *in = data->dctSpace, *coeff = data->dctSpace + 64;
735                                  } else                  // what remains here is up or down          int32_t rd = 0;
736            VECTOR * current;
737            const uint8_t * ptr;
738            int i, cbp = 0, t, xc, yc;
739    
740            if ( (x > data->max_dx) || (x < data->min_dx)
741                    || (y > data->max_dy) || (y < data->min_dy) ) return;
742    
743            if (!data->qpel_precision) {
744                    ptr = GetReference(x, y, data);
745                    current = data->currentMV;
746                    xc = x; yc = y;
747            } else { /* x and y are in 1/4 precision */
748                    ptr = Interpolate16x16qpel(x, y, 0, data);
749                    current = data->currentQMV;
750                    xc = x/2; yc = y/2;
751            }
752    
753            for(i = 0; i < 4; i++) {
754                    int s = 8*((i&1) + (i>>1)*data->iEdgedWidth);
755                    transfer_8to16subro(in, data->Cur + s, ptr + s, data->iEdgedWidth);
756                    rd += data->temp[i] = Block_CalcBits(coeff, in, data->dctSpace + 128, data->iQuant, data->quant_type, &cbp, i);
757            }
758    
759            rd += t = BITS_MULT*d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
760    
761            if (data->temp[0] + t < data->iMinSAD[1]) {
762                    data->iMinSAD[1] = data->temp[0] + t; current[1].x = x; current[1].y = y; data->cbp[1] = (data->cbp[1]&~32) | (cbp&32); }
763            if (data->temp[1] < data->iMinSAD[2]) {
764                    data->iMinSAD[2] = data->temp[1]; current[2].x = x; current[2].y = y; data->cbp[1] = (data->cbp[1]&~16) | (cbp&16); }
765            if (data->temp[2] < data->iMinSAD[3]) {
766                    data->iMinSAD[3] = data->temp[2]; current[3].x = x; current[3].y = y; data->cbp[1] = (data->cbp[1]&~8) | (cbp&8); }
767            if (data->temp[3] < data->iMinSAD[4]) {
768                    data->iMinSAD[4] = data->temp[3]; current[4].x = x; current[4].y = y; data->cbp[1] = (data->cbp[1]&~4) | (cbp&4); }
769    
770            rd += BITS_MULT*xvid_cbpy_tab[15-(cbp>>2)].len;
771    
772            if (rd >= data->iMinSAD[0]) return;
773    
774            /* chroma */
775            xc = (xc >> 1) + roundtab_79[xc & 0x3];
776            yc = (yc >> 1) + roundtab_79[yc & 0x3];
777    
778            /* chroma U */
779            ptr = interpolate8x8_switch2(data->RefQ, data->RefP[4], 0, 0, xc, yc, data->iEdgedWidth/2, data->rounding);
780            transfer_8to16subro(in, data->CurU, ptr, data->iEdgedWidth/2);
781            rd += Block_CalcBits(coeff, in, data->dctSpace + 128, data->iQuant, data->quant_type, &cbp, 4);
782            if (rd >= data->iMinSAD[0]) return;
783    
784            /* chroma V */
785            ptr = interpolate8x8_switch2(data->RefQ, data->RefP[5], 0, 0, xc, yc, data->iEdgedWidth/2, data->rounding);
786            transfer_8to16subro(in, data->CurV, ptr, data->iEdgedWidth/2);
787            rd += Block_CalcBits(coeff, in, data->dctSpace + 128, data->iQuant, data->quant_type, &cbp, 5);
788    
789            rd += BITS_MULT*mcbpc_inter_tab[(MODE_INTER & 7) | ((cbp & 3) << 3)].len;
790    
791            if (rd < data->iMinSAD[0]) {
792                    data->iMinSAD[0] = rd;
793                    current[0].x = x; current[0].y = y;
794                    *data->dir = Direction;
795                    *data->cbp = cbp;
796            }
797    }
798    
799    static void
800    CheckCandidateRD8(const int x, const int y, const SearchData * const data, const int Direction)
801                                  {                                  {
802                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
803                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);          int16_t *in = data->dctSpace, *coeff = data->dctSpace + 64;
804            int32_t rd;
805            VECTOR * current;
806            const uint8_t * ptr;
807            int cbp = 0;
808    
809            if ( (x > data->max_dx) || (x < data->min_dx)
810                    || (y > data->max_dy) || (y < data->min_dy) ) return;
811    
812            if (!data->qpel_precision) {
813                    ptr = GetReference(x, y, data);
814                    current = data->currentMV;
815            } else { /* x and y are in 1/4 precision */
816                    ptr = Interpolate8x8qpel(x, y, 0, 0, data);
817                    current = data->currentQMV;
818                                  }                                  }
819    
820                                  if (iDirection) {          transfer_8to16subro(in, data->Cur, ptr, data->iEdgedWidth);
821                                          bDirection += iDirection;          rd = Block_CalcBits(coeff, in, data->dctSpace + 128, data->iQuant, data->quant_type, &cbp, 5);
822                                          start_x = currMV->x;          rd += BITS_MULT*d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
823                                          start_y = currMV->y;  
824            if (rd < data->iMinSAD[0]) {
825                    *data->cbp = cbp;
826                    data->iMinSAD[0] = rd;
827                    current[0].x = x; current[0].y = y;
828                    *data->dir = Direction;
829            }
830                                  }                                  }
831                          } else                          //about to quit, eh? not so fast....  
832    /* CHECK_CANDIATE FUNCTIONS END */
833    
834    /* MAINSEARCH FUNCTIONS START */
835    
836    static void
837    AdvDiamondSearch(int x, int y, const SearchData * const data, int bDirection, CheckFunc * const CheckCandidate)
838                          {                          {
839    
840    /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
841    
842            unsigned int * const iDirection = data->dir;
843    
844            for(;;) { /* forever */
845                    *iDirection = 0;
846                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
847                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
848                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
849                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
850    
851                    /* now we're doing diagonal checks near our candidate */
852    
853                    if (*iDirection) {              /* if anything found */
854                            bDirection = *iDirection;
855                            *iDirection = 0;
856                            x = data->currentMV->x; y = data->currentMV->y;
857                            if (bDirection & 3) {   /* our candidate is left or right */
858                                    CHECK_CANDIDATE(x, y + iDiamondSize, 8);
859                                    CHECK_CANDIDATE(x, y - iDiamondSize, 4);
860                            } else {                        /* what remains here is up or down */
861                                    CHECK_CANDIDATE(x + iDiamondSize, y, 2);
862                                    CHECK_CANDIDATE(x - iDiamondSize, y, 1);
863                            }
864    
865                            if (*iDirection) {
866                                    bDirection += *iDirection;
867                                    x = data->currentMV->x; y = data->currentMV->y;
868                            }
869                    } else {                                /* about to quit, eh? not so fast.... */
870                                  switch (bDirection) {                                  switch (bDirection) {
871                                  case 2:                                  case 2:
872                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
873                                                                                           start_y - iDiamondSize, 2 + 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
874                                          break;                                          break;
875                                  case 1:                                  case 1:
876                                    CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
877                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
878                                          break;                                          break;
879                                  case 2 + 4:                                  case 2 + 4:
880                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
881                                                                                           start_y - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
882                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
883                                          break;                                          break;
884                                  case 4:                                  case 4:
885                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
886                                                                                           start_y - iDiamondSize, 2 + 4);                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y - iDiamondSize, 1 + 4);  
887                                          break;                                          break;
888                                  case 8:                                  case 8:
889                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
890                                                                                           start_y + iDiamondSize, 2 + 8);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
891                                          break;                                          break;
892                                  case 1 + 4:                                  case 1 + 4:
893                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
894                                                                                           start_y + iDiamondSize, 1 + 8);                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
895                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
896                                          break;                                          break;
897                                  case 2 + 8:                                  case 2 + 8:
898                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
899                                                                                           start_y - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
900                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
901                                          break;                                          break;
902                                  case 1 + 8:                                  case 1 + 8:
903                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
904                                                                                           start_y - iDiamondSize, 2 + 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
905                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
906                                                                                           start_y + iDiamondSize, 2 + 8);                                  break;
907                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                          default:                /* 1+2+4+8 == we didn't find anything at all */
908                                                                                           start_y + iDiamondSize, 1 + 8);                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
909                                          break;                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
910                                  default:                //1+2+4+8 == we didn't find anything at all                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
911                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
912                                          break;                                          break;
913                                  }                                  }
914                                  if (!iDirection)                          if (!*iDirection) break;                /* ok, the end. really */
915                                          break;          //ok, the end. really                          bDirection = *iDirection;
916                                  else {                          x = data->currentMV->x; y = data->currentMV->y;
917                                          bDirection = iDirection;                  }
918                                          start_x = currMV->x;          }
919                                          start_y = currMV->y;  }
                                 }  
                         }  
                 }  
                 while (1);                              //forever  
         }  
         return iMinSAD;  
 }  
   
 #define CHECK_MV16_F_INTERPOL(X,Y) { \  
   if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \  
     && ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, b_currMV->x, b_currMV->y, iEdgedWidth),   \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16((X) - f_center_x, (Y) - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16(b_currMV->x - b_center_x, b_currMV->y - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; f_currMV->x=(X); f_currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_F_INTERPOL_FOUND(X,Y) { \  
   if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \  
     && ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, b_currMV->x, b_currMV->y, iEdgedWidth),   \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16((X) - f_center_x, (Y) - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16(b_currMV->x - b_center_x, b_currMV->y - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; f_currMV->x=(X); f_currMV->y=(Y); iFound=0;} } \  
 }  
   
 #define CHECK_MV16_B_INTERPOL(X,Y) { \  
   if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \  
     && ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth),   \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16((X) - b_center_x, (Y) - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; b_currMV->x=(X); b_currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_B_INTERPOL_FOUND(X,Y) { \  
   if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \  
     && ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth),   \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16((X) - b_center_x, (Y) - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; b_currMV->x=(X); b_currMV->y=(Y); iFound=0;} } \  
 }  
   
 int32_t  
 Diamond16_InterpolMainSearch(  
                                         const uint8_t * const f_pRef,  
                                          const uint8_t * const f_pRefH,  
                                          const uint8_t * const f_pRefV,  
                                          const uint8_t * const f_pRefHV,  
   
                                          const uint8_t * const cur,  
   
                                         const uint8_t * const b_pRef,  
                                          const uint8_t * const b_pRefH,  
                                          const uint8_t * const b_pRefV,  
                                          const uint8_t * const b_pRefHV,  
920    
921                                           const int x,  static void
922                                           const int y,  SquareSearch(int x, int y, const SearchData * const data, int bDirection, CheckFunc * const CheckCandidate)
923    {
924            unsigned int * const iDirection = data->dir;
925    
926                                     const int f_start_x,          do {
927                                     const int f_start_y,                  *iDirection = 0;
928                                     const int b_start_x,                  if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);
929                                     const int b_start_y,                  if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);
930                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);
931                                     int iMinSAD,                  if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128);
932                                     VECTOR * const f_currMV,                  if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64);
933                                     VECTOR * const b_currMV,                  if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128);
934                    if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128);
935                                     const int f_center_x,                  if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128);
936                                     const int f_center_y,  
937                                     const int b_center_x,                  bDirection = *iDirection;
938                                     const int b_center_y,                  x = data->currentMV->x; y = data->currentMV->y;
939            } while (*iDirection);
940                                      const int32_t f_min_dx,  }
                                         const int32_t f_max_dx,  
                                         const int32_t f_min_dy,  
                                         const int32_t f_max_dy,  
   
                                     const int32_t b_min_dx,  
                                         const int32_t b_max_dx,  
                                         const int32_t b_min_dy,  
                                         const int32_t b_max_dy,  
   
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
   
                                         const int32_t f_iFcode,  
                                         const int32_t b_iFcode,  
   
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iSAD;  
   
         VECTOR f_backupMV;  
         VECTOR b_backupMV;  
   
         f_currMV->x = f_start_x;  
         f_currMV->y = f_start_y;  
         b_currMV->x = b_start_x;  
         b_currMV->y = b_start_y;  
   
         do  
         {  
                 iFound = 1;  
   
                 f_backupMV = *f_currMV;  
   
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x - iDiamondSize, f_backupMV.y);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x + iDiamondSize, f_backupMV.y);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y - iDiamondSize);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y + iDiamondSize);  
   
                 b_backupMV = *b_currMV;  
   
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x - iDiamondSize, b_backupMV.y);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x + iDiamondSize, b_backupMV.y);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y - iDiamondSize);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y + iDiamondSize);  
   
         } while (!iFound);  
   
         return iMinSAD;  
 }  
   
 /* Sorry, these MACROS really got too large... I'll turn them into function soon! */  
   
 #define CHECK_MV16_DIRECT_FOUND(X,Y) \  
         if ( (X)>=(-32) && (X)<=(31) && ((Y)>=-32) && ((Y)<=31) ) \  
         { int k;\  
         VECTOR mvs,b_mvs;       \  
         iSAD = 0;\  
         for (k = 0; k < 4; k++) {       \  
                                         mvs.x = (int32_t) ((TRB * directmv[k].x) / TRD + (X));          \  
                     b_mvs.x = (int32_t) (((X) == 0)                                                     \  
                                                                                 ? ((TRB - TRD) * directmv[k].x) / TRD   \  
                                             : mvs.x - directmv[k].x);                           \  
                                                                                                                                                                 \  
                     mvs.y = (int32_t) ((TRB * directmv[k].y) / TRD + (Y));              \  
                         b_mvs.y = (int32_t) (((Y) == 0)                                                         \  
                                                                                 ? ((TRB - TRD) * directmv[k].y) / TRD   \  
                                             : mvs.y - directmv[k].y);                           \  
                                                                                                                                                                 \  
   if ( (mvs.x <= max_dx) && (mvs.x >= min_dx) \  
     && (mvs.y <= max_dy) && (mvs.y >= min_dy)  \  
         && (b_mvs.x <= max_dx) && (b_mvs.x >= min_dx)  \  
     && (b_mvs.y <= max_dy) && (b_mvs.y >= min_dy) ) { \  
             iSAD += sad8bi( cur + 8*(k&1) + 8*(k>>1)*iEdgedWidth,                                                                                                       \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \  
                                         mvs.x, mvs.y, iEdgedWidth),                                                             \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \  
                                         b_mvs.x, b_mvs.y, iEdgedWidth),                                                         \  
                         iEdgedWidth); \  
                 }       \  
         else    \  
                 iSAD = 65535;   \  
         } \  
         iSAD += calc_delta_16((X),(Y), 1, iQuant);\  
         if (iSAD < iMinSAD) \  
             {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iFound=0; } \  
 }  
   
   
   
 int32_t  
 Diamond16_DirectMainSearch(  
                                         const uint8_t * const f_pRef,  
                                         const uint8_t * const f_pRefH,  
                                         const uint8_t * const f_pRefV,  
                                         const uint8_t * const f_pRefHV,  
   
                                         const uint8_t * const cur,  
   
                                         const uint8_t * const b_pRef,  
                                         const uint8_t * const b_pRefH,  
                                         const uint8_t * const b_pRefV,  
                                         const uint8_t * const b_pRefHV,  
941    
942                                          const int x,  static void
943                                          const int y,  DiamondSearch(int x, int y, const SearchData * const data, int bDirection, CheckFunc * const CheckCandidate)
944    {
945    
946    /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
947    
948                                          const int TRB,          unsigned int * const iDirection = data->dir;
                                         const int TRD,  
949    
950                                      const int start_x,          do {
951                                      const int start_y,                  *iDirection = 0;
952                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
953                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
954                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
955                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
956    
957                                      int iMinSAD,                  /* now we're doing diagonal checks near our candidate */
                                     VECTOR * const currMV,  
                                         const VECTOR * const directmv,  
958    
959                                      const int32_t min_dx,                  if (*iDirection) {              /* checking if anything found */
960                                          const int32_t max_dx,                          bDirection = *iDirection;
961                                          const int32_t min_dy,                          *iDirection = 0;
962                                          const int32_t max_dy,                          x = data->currentMV->x; y = data->currentMV->y;
963                            if (bDirection & 3) {   /* our candidate is left or right */
964                                    CHECK_CANDIDATE(x, y + iDiamondSize, 8);
965                                    CHECK_CANDIDATE(x, y - iDiamondSize, 4);
966                            } else {                        /* what remains here is up or down */
967                                    CHECK_CANDIDATE(x + iDiamondSize, y, 2);
968                                    CHECK_CANDIDATE(x - iDiamondSize, y, 1);
969                            }
970                            bDirection += *iDirection;
971                            x = data->currentMV->x; y = data->currentMV->y;
972                    }
973            }
974            while (*iDirection);
975    }
976    
977                                          const int32_t iEdgedWidth,  /* MAINSEARCH FUNCTIONS END */
                                         const int32_t iDiamondSize,  
978    
979                                          const int32_t iQuant,  static void
980                                          int iFound)  SubpelRefine_Fast(SearchData * data, CheckFunc * CheckCandidate)
981  {  {
982  /* Do a diamond search around given starting point, return SAD of best */  /* Do a half-pel or q-pel refinement */
983            VECTOR centerMV;
984            VECTOR second_best;
985            int best_sad = *data->iMinSAD;
986            int xo, yo, xo2, yo2;
987            int size = 2;
988            CheckFunc *backupFunc = CheckCandidate;
989    
990          int32_t iSAD;          if(data->qpel_precision)
991                    size = 1;
992    
993          VECTOR backupMV;          centerMV = *data->currentMV;
994            *data->iMinSAD = 256 * 4096;
995    
996          currMV->x = start_x;          CHECK_CANDIDATE(centerMV.x, centerMV.y - size, 0);
997          currMV->y = start_y;          CHECK_CANDIDATE(centerMV.x + size, centerMV.y - size, 0);
998            CHECK_CANDIDATE(centerMV.x + size, centerMV.y, 0);
999            CHECK_CANDIDATE(centerMV.x + size, centerMV.y + size, 0);
1000    
1001  /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */          CHECK_CANDIDATE(centerMV.x, centerMV.y + size, 0);
1002            CHECK_CANDIDATE(centerMV.x - size, centerMV.y + size, 0);
1003            CHECK_CANDIDATE(centerMV.x - size, centerMV.y, 0);
1004            CHECK_CANDIDATE(centerMV.x - size, centerMV.y - size, 0);
1005    
1006          do          second_best = *data->currentMV;
         {  
                 iFound = 1;  
1007    
1008                  backupMV = *currMV;          if(data->qpel_precision) {
1009                    second_best.x *= 2;     second_best.y *= 2;
1010            }
1011    
1012                  CHECK_MV16_DIRECT_FOUND(backupMV.x - iDiamondSize, backupMV.y);          data->currentMV[0] = centerMV;
1013                  CHECK_MV16_DIRECT_FOUND(backupMV.x + iDiamondSize, backupMV.y);          *data->iMinSAD = best_sad;
                 CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y - iDiamondSize);  
                 CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y + iDiamondSize);  
1014    
1015          } while (!iFound);      centerMV = data->qpel_precision ? *data->currentQMV : *data->currentMV;
1016    
1017          return iMinSAD;          xo = centerMV.x;
1018  }          yo = centerMV.y;
1019            xo2 = second_best.x;
1020            yo2 = second_best.y;
1021    
1022            CheckCandidate = CheckCandidate16_subpel;
1023            *data->iMinSAD2 = 256 * 4096;
1024    
1025  int32_t          if (yo == yo2)
 AdvDiamond8_MainSearch(const uint8_t * const pRef,  
                                            const uint8_t * const pRefH,  
                                            const uint8_t * const pRefV,  
                                            const uint8_t * const pRefHV,  
                                            const uint8_t * const cur,  
                                            const int x,  
                                            const int y,  
                                            int start_x,  
                                            int start_y,  
                                            int iMinSAD,  
                                            VECTOR * const currMV,  
                                            const int center_x,  
                                            const int center_y,  
                                            const int32_t min_dx,  
                                            const int32_t max_dx,  
                                            const int32_t min_dy,  
                                            const int32_t max_dy,  
                                            const int32_t iEdgedWidth,  
                                            const int32_t iDiamondSize,  
                                            const int32_t iFcode,  
                                            const int32_t iQuant,  
                                            int iDirection)  
1026  {  {
1027                    CHECK_CANDIDATE((xo+xo2)>>1, yo, 0);
1028                    CHECK_CANDIDATE(xo, yo-1, 0);
1029                    CHECK_CANDIDATE(xo, yo+1, 0);
1030    
1031          int32_t iSAD;                  if(best_sad <= *data->iMinSAD2)
1032                            goto ende;
1033    
1034  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */                  if(data->currentQMV[0].x == data->currentQMV2[0].x) {
1035                            CHECK_CANDIDATE((xo+xo2)>>1, yo-1, 0);
1036                            CHECK_CANDIDATE((xo+xo2)>>1, yo+1, 0);
1037                            goto ende;
1038                    }
1039                    else {
1040                            CHECK_CANDIDATE((xo+xo2)>>1,
1041                                    (data->currentQMV[0].x == xo) ? data->currentQMV[0].y : data->currentQMV2[0].y,
1042                                    0);
1043                            goto ende;
1044                    }
1045            }
1046    
1047          if (iDirection) {          if (xo == xo2)
1048                  CHECK_MV8_CANDIDATE(start_x - iDiamondSize, start_y);          {
1049                  CHECK_MV8_CANDIDATE(start_x + iDiamondSize, start_y);                  CHECK_CANDIDATE(xo, (yo+yo2)>>1, 0);
1050                  CHECK_MV8_CANDIDATE(start_x, start_y - iDiamondSize);                  CHECK_CANDIDATE(xo-1, yo, 0);
1051                  CHECK_MV8_CANDIDATE(start_x, start_y + iDiamondSize);                  CHECK_CANDIDATE(xo+1, yo, 0);
         } else {  
                 int bDirection = 1 + 2 + 4 + 8;  
1052    
1053                  do {                  if(best_sad < *data->iMinSAD2)
1054                          iDirection = 0;                          goto ende;
                         if (bDirection & 1)     //we only want to check left if we came from the right (our last motion was to the left, up-left or down-left)  
                                 CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
1055    
1056                          if (bDirection & 2)                  if(data->currentQMV[0].y == data->currentQMV2[0].y) {
1057                                  CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);                          CHECK_CANDIDATE(xo-1, (yo+yo2)>>1, 0);
1058                            CHECK_CANDIDATE(xo+1, (yo+yo2)>>1, 0);
1059                            goto ende;
1060                    }
1061                    else {
1062                            CHECK_CANDIDATE((data->currentQMV[0].y == yo) ? data->currentQMV[0].x : data->currentQMV2[0].x, (yo+yo2)>>1, 0);
1063                            goto ende;
1064                    }
1065            }
1066    
1067                          if (bDirection & 4)          CHECK_CANDIDATE(xo, (yo+yo2)>>1, 0);
1068                                  CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);          CHECK_CANDIDATE((xo+xo2)>>1, yo, 0);
1069    
1070                          if (bDirection & 8)          if(best_sad <= *data->iMinSAD2)
1071                                  CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);                  goto ende;
1072    
1073                          /* now we're doing diagonal checks near our candidate */          CHECK_CANDIDATE((xo+xo2)>>1, (yo+yo2)>>1, 0);
1074    
1075                          if (iDirection)         //checking if anything found  ende:
1076                          {          CheckCandidate = backupFunc;
                                 bDirection = iDirection;  
                                 iDirection = 0;  
                                 start_x = currMV->x;  
                                 start_y = currMV->y;  
                                 if (bDirection & 3)     //our candidate is left or right  
                                 {  
                                         CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);  
                                 } else                  // what remains here is up or down  
                                 {  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
1077                                  }                                  }
1078    
1079                                  if (iDirection) {  static void
1080                                          bDirection += iDirection;  SubpelRefine(const SearchData * const data, CheckFunc * const CheckCandidate)
                                         start_x = currMV->x;  
                                         start_y = currMV->y;  
                                 }  
                         } else                          //about to quit, eh? not so fast....  
1081                          {                          {
1082                                  switch (bDirection) {  /* Do a half-pel or q-pel refinement */
1083                                  case 2:          const VECTOR centerMV = data->qpel_precision ? *data->currentQMV : *data->currentMV;
1084                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
1085                                                                                          start_y - iDiamondSize, 2 + 4);          CHECK_CANDIDATE(centerMV.x, centerMV.y - 1, 0);
1086                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,          CHECK_CANDIDATE(centerMV.x + 1, centerMV.y - 1, 0);
1087                                                                                          start_y + iDiamondSize, 2 + 8);          CHECK_CANDIDATE(centerMV.x + 1, centerMV.y, 0);
1088                                          break;          CHECK_CANDIDATE(centerMV.x + 1, centerMV.y + 1, 0);
1089                                  case 1:          CHECK_CANDIDATE(centerMV.x, centerMV.y + 1, 0);
1090                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,          CHECK_CANDIDATE(centerMV.x - 1, centerMV.y + 1, 0);
1091                                                                                          start_y - iDiamondSize, 1 + 4);          CHECK_CANDIDATE(centerMV.x - 1, centerMV.y, 0);
1092                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,          CHECK_CANDIDATE(centerMV.x - 1, centerMV.y - 1, 0);
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 2 + 4:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 4:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         break;  
                                 case 8:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 1 + 4:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         break;  
                                 case 2 + 8:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1 + 8:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         break;  
                                 default:                //1+2+4+8 == we didn't find anything at all  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 }  
                                 if (!(iDirection))  
                                         break;          //ok, the end. really  
                                 else {  
                                         bDirection = iDirection;  
                                         start_x = currMV->x;  
                                         start_y = currMV->y;  
                                 }  
                         }  
1093                  }                  }
1094                  while (1);                              //forever  
1095    static __inline int
1096    SkipDecisionP(const IMAGE * current, const IMAGE * reference,
1097                                                            const int x, const int y,
1098                                                            const uint32_t stride, const uint32_t iQuant, int rrv)
1099    
1100    {
1101            int offset = (x + y*stride)*8;
1102            if(!rrv) {
1103                    uint32_t sadC = sad8(current->u + offset,
1104                                                    reference->u + offset, stride);
1105                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
1106                    sadC += sad8(current->v + offset,
1107                                                    reference->v + offset, stride);
1108                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
1109                    return 1;
1110    
1111            } else {
1112                    uint32_t sadC = sad16(current->u + 2*offset,
1113                                                    reference->u + 2*offset, stride, 256*4096);
1114                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
1115                    sadC += sad16(current->v + 2*offset,
1116                                                    reference->v + 2*offset, stride, 256*4096);
1117                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
1118                    return 1;
1119          }          }
         return iMinSAD;  
1120  }  }
1121    
1122    static __inline void
1123    ZeroMacroblockP(MACROBLOCK *pMB, const int32_t sad)
1124    {
1125            pMB->mode = MODE_INTER;
1126            pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = zeroMV;
1127            pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] = pMB->qmvs[3] = zeroMV;
1128            pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
1129    }
1130    
1131  int32_t  static __inline void
1132  Full8_MainSearch(const uint8_t * const pRef,  ModeDecision_Fast(SearchData * const Data,
1133                                   const uint8_t * const pRefH,                          MACROBLOCK * const pMB,
1134                                   const uint8_t * const pRefV,                          const MACROBLOCK * const pMBs,
1135                                   const uint8_t * const pRefHV,                          const int x, const int y,
1136                                   const uint8_t * const cur,                          const MBParam * const pParam,
1137                                   const int x,                          const uint32_t MotionFlags,
1138                                   const int y,                          const uint32_t VopFlags,
1139                             const int start_x,                          const uint32_t VolFlags,
1140                             const int start_y,                          const IMAGE * const pCurrent,
1141                             int iMinSAD,                          const IMAGE * const pRef,
1142                             VECTOR * const currMV,                          const IMAGE * const vGMC,
1143                             const int center_x,                          const int coding_type)
1144                             const int center_y,  {
1145                                   const int32_t min_dx,          int mode = MODE_INTER;
1146                                   const int32_t max_dx,          int mcsel = 0;
1147                                   const int32_t min_dy,          int inter4v = (VopFlags & XVID_VOP_INTER4V) && (pMB->dquant == 0);
1148                                   const int32_t max_dy,          const uint32_t iQuant = pMB->quant;
1149                                   const int32_t iEdgedWidth,          const int skip_possible = (coding_type == P_VOP) && (pMB->dquant == 0);
1150                                   const int32_t iDiamondSize,      int sad;
1151                                   const int32_t iFcode,          int min_rd = -1, intra_rd, i, cbp, c[2] = {0, 0};
1152                                   const int32_t iQuant,          VECTOR backup[5], *v;
1153                                   int iFound)          int sad_backup[5];
1154  {          int InterBias = MV16_INTER_BIAS;
1155          int32_t iSAD;          int thresh = 0;
1156          int32_t dx, dy;          int count = 0;
1157          VECTOR backupMV;          int top = 0, top_right = 0, left = 0;
1158    
1159          backupMV.x = start_x;          pMB->mcsel = 0;
1160          backupMV.y = start_y;  
1161            /* INTER <-> INTER4V decision */
1162          for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)          if ((Data->iMinSAD[0] + 50 < Data->iMinSAD[1] +
1163                  for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)                  Data->iMinSAD[2] + Data->iMinSAD[3] + Data->iMinSAD[4])) { /* normal, fast, SAD-based mode decision */
1164                          NOCHECK_MV8_CANDIDATE(dx, dy);                  if (inter4v == 0 || Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
1165                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant) {
1166          return iMinSAD;                          mode = MODE_INTER;
1167                            sad = Data->iMinSAD[0];
1168                    } else {
1169                            mode = MODE_INTER4V;
1170                            sad = Data->iMinSAD[1] + Data->iMinSAD[2] +
1171                                                    Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant;
1172                            Data->iMinSAD[0] = sad;
1173  }  }
1174    
1175  Halfpel8_RefineFuncPtr Halfpel8_Refine;                  /* final skip decision, a.k.a. "the vector you found, really that good?" */
1176                    if (skip_possible && (pMB->sad16 < (int)iQuant * MAX_SAD00_FOR_SKIP))
1177                            if ( (100*sad)/(pMB->sad16+1) > FINAL_SKIP_THRESH)
1178                                    if (Data->chroma || SkipDecisionP(pCurrent, pRef, x, y, Data->iEdgedWidth/2, iQuant, Data->rrv)) {
1179                                            mode = MODE_NOT_CODED;
1180                                            goto early_out;
1181                                    }
1182    
1183  int32_t                  /* mcsel */
1184  Halfpel16_Refine(const uint8_t * const pRef,                  if (coding_type == S_VOP) {
                                  const uint8_t * const pRefH,  
                                  const uint8_t * const pRefV,  
                                  const uint8_t * const pRefHV,  
                                  const uint8_t * const cur,  
                                  const int x,  
                                  const int y,  
                                  VECTOR * const currMV,  
                                  int32_t iMinSAD,  
                            const int center_x,  
                            const int center_y,  
                                  const int32_t min_dx,  
                                  const int32_t max_dx,  
                                  const int32_t min_dy,  
                                  const int32_t max_dy,  
                                  const int32_t iFcode,  
                                  const int32_t iQuant,  
                                  const int32_t iEdgedWidth)  
 {  
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
1185    
1186          int32_t iSAD;                          int32_t iSAD = sad16(Data->Cur,
1187          VECTOR backupMV = *currMV;                                  vGMC->y + 16*y*Data->iEdgedWidth + 16*x, Data->iEdgedWidth, 65536);
1188    
1189          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y - 1);                          if (Data->chroma) {
1190          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y - 1);                                  iSAD += sad8(Data->CurU, vGMC->u + 8*y*(Data->iEdgedWidth/2) + 8*x, Data->iEdgedWidth/2);
1191          CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y - 1);                                  iSAD += sad8(Data->CurV, vGMC->v + 8*y*(Data->iEdgedWidth/2) + 8*x, Data->iEdgedWidth/2);
1192          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y);                          }
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y + 1);  
         CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y + 1);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y + 1);  
1193    
1194          return iMinSAD;                          if (iSAD <= sad) {              /* mode decision GMC */
1195                                    mode = MODE_INTER;
1196                                    mcsel = 1;
1197                                    sad = iSAD;
1198  }  }
1199    
1200  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)                  }
1201            } else { /* Rate-Distortion INTER<->INTER4V */
1202                    Data->iQuant = iQuant;
1203                    Data->cbp = c;
1204                    v = Data->qpel ? Data->currentQMV : Data->currentMV;
1205    
1206                    /* final skip decision, a.k.a. "the vector you found, really that good?" */
1207                    if (skip_possible && (pMB->sad16 < (int)iQuant * MAX_SAD00_FOR_SKIP))
1208                            if ( (100*Data->iMinSAD[0])/(pMB->sad16+1) > FINAL_SKIP_THRESH)
1209                                    if (Data->chroma || SkipDecisionP(pCurrent, pRef, x, y, Data->iEdgedWidth/2, iQuant, Data->rrv)) {
1210                                            mode = MODE_NOT_CODED;
1211                                            goto early_out;
1212                                    }
1213    
1214                    for (i = 0; i < 5; i++) {
1215                            sad_backup[i] = Data->iMinSAD[i];
1216                            Data->iMinSAD[i] = 256*4096;
1217                            backup[i] = v[i];
1218                    }
1219    
1220  int32_t                  min_rd = findRDinter(Data, pMBs, x, y, pParam, MotionFlags);
1221  PMVfastSearch16(const uint8_t * const pRef,                  cbp = *Data->cbp;
1222                                  const uint8_t * const pRefH,                  sad = sad_backup[0];
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const IMAGE * const pCur,  
                                 const int x,  
                                 const int y,  
                                 const int start_x,      /* start is searched first, so it should contain the most */  
                                 const int start_y,  /* likely motion vector for this block */  
                                 const int center_x,     /* center is from where length of MVs is measured */  
                                 const int center_y,  
                                 const uint32_t MotionFlags,  
                                 const uint32_t iQuant,  
                                 const uint32_t iFcode,  
                                 const MBParam * const pParam,  
                                 const MACROBLOCK * const pMBs,  
                                 const MACROBLOCK * const prevMBs,  
                                 VECTOR * const currMV,  
                                 VECTOR * const currPMV)  
 {  
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
1223    
1224          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;                  if (coding_type == S_VOP) {
1225                            int gmc_rd;
1226                            int32_t iSAD = sad16(Data->Cur,
1227                                    vGMC->y + 16*y*Data->iEdgedWidth + 16*x, Data->iEdgedWidth, 65536);
1228    
1229          int32_t iDiamondSize;                          if (Data->chroma) {
1230                                    iSAD += sad8(Data->CurU, vGMC->u + 8*y*(Data->iEdgedWidth/2) + 8*x, Data->iEdgedWidth/2);
1231                                    iSAD += sad8(Data->CurV, vGMC->v + 8*y*(Data->iEdgedWidth/2) + 8*x, Data->iEdgedWidth/2);
1232                            }
1233    
1234          int32_t min_dx;                          *Data->iMinSAD = min_rd += BITS_MULT*1; /* mcsel */
1235          int32_t max_dx;                          gmc_rd = findRDgmc(Data, vGMC, x, y);
1236          int32_t min_dy;                          if (gmc_rd < min_rd) {
1237          int32_t max_dy;                                  mcsel = 1;
1238                                    *Data->iMinSAD = min_rd = gmc_rd;
1239                                    mode = MODE_INTER;
1240                                    cbp = *Data->cbp;
1241                                    sad = iSAD;
1242                            }
1243                    }
1244    
1245          int32_t iFound;                  if (inter4v) {
1246                            int v4_rd;
1247                            v4_rd = findRDinter4v(Data, pMB, pMBs, x, y, pParam, MotionFlags, backup);
1248                            if (v4_rd < min_rd) {
1249                                    Data->iMinSAD[0] = min_rd = v4_rd;
1250                                    mode = MODE_INTER4V;
1251                                    cbp = *Data->cbp;
1252                                    sad = sad_backup[1] + sad_backup[2] +
1253                                              sad_backup[3] + sad_backup[4] + IMV16X16 * (int32_t)iQuant;
1254                            }
1255                    }
1256            }
1257    
1258          VECTOR newMV;          left = top = top_right = -1;
1259          VECTOR backupMV;                        /* just for PMVFAST */          thresh = 0;
1260    
1261          VECTOR pmv[4];          if(x > 0 && y > 0 && x < pParam->mb_width) {
1262          int32_t psad[4];                  left = (&pMBs[(x-1) + y * pParam->mb_width])->sad16; // left
1263                    top = (&pMBs[x + (y-1) * pParam->mb_width])->sad16; // top
1264                    top_right = (&pMBs[(x+1) + (y-1) * pParam->mb_width])->sad16; // top right
1265    
1266          MainSearch16FuncPtr MainSearchPtr;                  if(((&pMBs[(x-1) + y * pParam->mb_width])->mode != MODE_INTRA) &&
1267                       ((&pMBs[x + (y-1) * pParam->mb_width])->mode != MODE_INTRA) &&
1268                       ((&pMBs[(x+1) + (y-1) * pParam->mb_width])->mode != MODE_INTRA))
1269                            thresh = MAX(MAX(top, left), top_right);
1270                    else
1271                            thresh = MIN(MIN(top, left), top_right);
1272            }
1273    
1274          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;          /* INTRA <-> INTER decision */
1275            if (sad < thresh) { /* normal, fast, SAD-based mode decision */
1276                    /* intra decision */
1277    
1278          int32_t threshA, threshB;                  if (iQuant > 8) InterBias += 100 * (iQuant - 8); /* to make high quants work */
1279          int32_t bPredEq;                  if (y != 0)
1280          int32_t iMinSAD, iSAD;                          if ((pMB - pParam->mb_width)->mode == MODE_INTRA ) InterBias -= 80;
1281                    if (x != 0)
1282                            if ((pMB - 1)->mode == MODE_INTRA ) InterBias -= 80;
1283    
1284  /* Get maximum range */                  if (Data->chroma) InterBias += 50; /* dev8(chroma) ??? <-- yes, we need dev8 (no big difference though) */
1285          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,                  if (Data->rrv) InterBias *= 4;
                           iFcode);  
1286    
1287  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */                  if (InterBias < sad) {
1288                            int32_t deviation;
1289                            if (!Data->rrv)
1290                                    deviation = dev16(Data->Cur, Data->iEdgedWidth);
1291                            else
1292                                    deviation = dev16(Data->Cur, Data->iEdgedWidth) + /* dev32() */
1293                                                            dev16(Data->Cur+16, Data->iEdgedWidth) +
1294                                                            dev16(Data->Cur + 16*Data->iEdgedWidth, Data->iEdgedWidth) +
1295                                                            dev16(Data->Cur+16+16*Data->iEdgedWidth, Data->iEdgedWidth);
1296    
1297          if (!(MotionFlags & PMV_HALFPEL16)) {                          if (deviation < (sad - InterBias)) mode = MODE_INTRA;
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
1298          }          }
1299    
1300          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */                  pMB->cbp = 63;
1301          //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);          } else { /* Rate-Distortion INTRA<->INTER */
1302          bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);                  if(min_rd < 0) {
1303                            Data->iQuant = iQuant;
1304                            Data->cbp = c;
1305                            v = Data->qpel ? Data->currentQMV : Data->currentMV;
1306    
1307          if ((x == 0) && (y == 0)) {                          for (i = 0; i < 5; i++) {
1308                  threshA = 512;                                  Data->iMinSAD[i] = 256*4096;
1309                  threshB = 1024;                                  backup[i] = v[i];
         } else {  
                 threshA = psad[0];  
                 threshB = threshA + 256;  
                 if (threshA < 512)  
                         threshA = 512;  
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
1310          }          }
1311    
1312          iFound = 0;                          if(mode == MODE_INTER) {
1313                                    min_rd = findRDinter(Data, pMBs, x, y, pParam, MotionFlags);
1314  /* Step 4: Calculate SAD around the Median prediction.                                  cbp = *Data->cbp;
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
1315    
1316          currMV->x = start_x;                                  if (coding_type == S_VOP) {
1317          currMV->y = start_y;                                          int gmc_rd;
1318    
1319          if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */                                          *Data->iMinSAD = min_rd += BITS_MULT*1; /* mcsel */
1320                  currMV->x = EVEN(currMV->x);                                          gmc_rd = findRDgmc(Data, vGMC, x, y);
1321                  currMV->y = EVEN(currMV->y);                                          if (gmc_rd < min_rd) {
1322                                                    mcsel = 1;
1323                                                    *Data->iMinSAD = min_rd = gmc_rd;
1324                                                    mode = MODE_INTER;
1325                                                    cbp = *Data->cbp;
1326                                            }
1327          }          }
   
         if (currMV->x > max_dx) {  
                 currMV->x = max_dx;  
1328          }          }
1329          if (currMV->x < min_dx) {  
1330                  currMV->x = min_dx;                          if(mode == MODE_INTER4V) {
1331                                    int v4_rd;
1332                                    v4_rd = findRDinter4v(Data, pMB, pMBs, x, y, pParam, MotionFlags, backup);
1333                                    if (v4_rd < min_rd) {
1334                                            Data->iMinSAD[0] = min_rd = v4_rd;
1335                                            mode = MODE_INTER4V;
1336                                            cbp = *Data->cbp;
1337          }          }
         if (currMV->y > max_dy) {  
                 currMV->y = max_dy;  
1338          }          }
         if (currMV->y < min_dy) {  
                 currMV->y = min_dy;  
1339          }          }
1340    
1341          iMinSAD =                  intra_rd = findRDintra(Data);
1342                  sad16(cur,                  if (intra_rd < min_rd) {
1343                            get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,                          *Data->iMinSAD = min_rd = intra_rd;
1344                                                   iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);                          mode = MODE_INTRA;
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
                 {  
                         if (!MVzero(*currMV)) {  
                                 iMinSAD += MV16_00_BIAS;  
                                 CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures  
                                 iMinSAD -= MV16_00_BIAS;  
                         }  
1345                  }                  }
1346    
1347                  if (MotionFlags & PMV_QUICKSTOP16)                  pMB->cbp = cbp;
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
1348          }          }
1349    
1350    early_out:
1351            pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
1352    
1353  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion          if (Data->rrv) {
1354     vector of the median.                          Data->currentMV[0].x = RRV_MV_SCALEDOWN(Data->currentMV[0].x);
1355     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2                          Data->currentMV[0].y = RRV_MV_SCALEDOWN(Data->currentMV[0].y);
1356  */          }
1357    
1358          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[0])))          if (mode == MODE_INTER && mcsel == 0) {
1359                  iFound = 2;                  pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
1360    
1361  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.                  if(Data->qpel) {
1362     Otherwise select large Diamond Search.                          pMB->qmvs[0] = pMB->qmvs[1]
1363  */                                  = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1364                            pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1365                            pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;
1366                    } else {
1367                            pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1368                            pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
1369                    }
1370    
1371          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))          } else if (mode == MODE_INTER ) { // but mcsel == 1
                 iDiamondSize = 1;               // halfpel!  
         else  
                 iDiamondSize = 2;               // halfpel!  
1372    
1373          if (!(MotionFlags & PMV_HALFPELDIAMOND16))                  pMB->mcsel = 1;
1374                  iDiamondSize *= 2;                  if (Data->qpel) {
1375                            pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] = pMB->qmvs[3] = pMB->amv;
1376                            pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = pMB->amv.x/2;
1377                            pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = pMB->amv.y/2;
1378                    } else
1379                            pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->amv;
1380    
1381  /*          } else
1382     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.                  if (mode == MODE_INTER4V) ; /* anything here? */
1383     Also calculate (0,0) but do not subtract offset.          else    /* INTRA, NOT_CODED */
1384     Let MinSAD be the smallest SAD up to this point.                  ZeroMacroblockP(pMB, 0);
    If MV is (0,0) subtract offset.  
 */  
1385    
1386  // (0,0) is always possible          pMB->mode = mode;
1387    }
1388    
1389          if (!MVzero(pmv[0]))  static __inline void
1390                  CHECK_MV16_ZERO;  ModeDecision(SearchData * const Data,
1391                            MACROBLOCK * const pMB,
1392                            const MACROBLOCK * const pMBs,
1393                            const int x, const int y,
1394                            const MBParam * const pParam,
1395                            const uint32_t MotionFlags,
1396                            const uint32_t VopFlags,
1397                            const uint32_t VolFlags,
1398                            const IMAGE * const pCurrent,
1399                            const IMAGE * const pRef,
1400                            const IMAGE * const vGMC,
1401                            const int coding_type)
1402    {
1403            int mode = MODE_INTER;
1404            int mcsel = 0;
1405            int inter4v = (VopFlags & XVID_VOP_INTER4V) && (pMB->dquant == 0);
1406            const uint32_t iQuant = pMB->quant;
1407    
1408            const int skip_possible = (coding_type == P_VOP) && (pMB->dquant == 0);
1409    
1410            pMB->mcsel = 0;
1411    
1412            if (!(VopFlags & XVID_VOP_MODEDECISION_RD)) { /* normal, fast, SAD-based mode decision */
1413                    int sad;
1414                    int InterBias = MV16_INTER_BIAS;
1415                    if (inter4v == 0 || Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
1416                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant) {
1417                            mode = MODE_INTER;
1418                            sad = Data->iMinSAD[0];
1419                    } else {
1420                            mode = MODE_INTER4V;
1421                            sad = Data->iMinSAD[1] + Data->iMinSAD[2] +
1422                                                    Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant;
1423                            Data->iMinSAD[0] = sad;
1424                    }
1425    
1426  // previous frame MV is always possible                  /* final skip decision, a.k.a. "the vector you found, really that good?" */
1427                    if (skip_possible && (pMB->sad16 < (int)iQuant * MAX_SAD00_FOR_SKIP))
1428                            if ( (100*sad)/(pMB->sad16+1) > FINAL_SKIP_THRESH)
1429                                    if (Data->chroma || SkipDecisionP(pCurrent, pRef, x, y, Data->iEdgedWidth/2, iQuant, Data->rrv)) {
1430                                            mode = MODE_NOT_CODED;
1431                                            sad = 0;
1432                                    }
1433    
1434          if (!MVzero(prevMB->mvs[0]))                  /* mcsel */
1435                  if (!MVequal(prevMB->mvs[0], pmv[0]))                  if (coding_type == S_VOP) {
                         CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);  
1436    
1437  // left neighbour, if allowed                          int32_t iSAD = sad16(Data->Cur,
1438                                    vGMC->y + 16*y*Data->iEdgedWidth + 16*x, Data->iEdgedWidth, 65536);
1439    
1440          if (!MVzero(pmv[1]))                          if (Data->chroma) {
1441                  if (!MVequal(pmv[1], prevMB->mvs[0]))                                  iSAD += sad8(Data->CurU, vGMC->u + 8*y*(Data->iEdgedWidth/2) + 8*x, Data->iEdgedWidth/2);
1442                          if (!MVequal(pmv[1], pmv[0])) {                                  iSAD += sad8(Data->CurV, vGMC->v + 8*y*(Data->iEdgedWidth/2) + 8*x, Data->iEdgedWidth/2);
                                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                                         pmv[1].x = EVEN(pmv[1].x);  
                                         pmv[1].y = EVEN(pmv[1].y);  
1443                                  }                                  }
1444    
1445                                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);                          if (iSAD <= sad) {              /* mode decision GMC */
1446                                    mode = MODE_INTER;
1447                                    mcsel = 1;
1448                                    sad = iSAD;
1449                          }                          }
 // top neighbour, if allowed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], prevMB->mvs[0]))  
                         if (!MVequal(pmv[2], pmv[0]))  
                                 if (!MVequal(pmv[2], pmv[1])) {  
                                         if (!(MotionFlags & PMV_HALFPEL16)) {  
                                                 pmv[2].x = EVEN(pmv[2].x);  
                                                 pmv[2].y = EVEN(pmv[2].y);  
                                         }  
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
1450    
 // top right neighbour, if allowed  
                                         if (!MVzero(pmv[3]))  
                                                 if (!MVequal(pmv[3], prevMB->mvs[0]))  
                                                         if (!MVequal(pmv[3], pmv[0]))  
                                                                 if (!MVequal(pmv[3], pmv[1]))  
                                                                         if (!MVequal(pmv[3], pmv[2])) {  
                                                                                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                                                                                         pmv[3].x = EVEN(pmv[3].x);  
                                                                                         pmv[3].y = EVEN(pmv[3].y);  
                                                                                 }  
                                                                                 CHECK_MV16_CANDIDATE(pmv[3].x,  
                                                                                                                          pmv[3].y);  
1451                                                                          }                                                                          }
                                 }  
   
         if ((MVzero(*currMV)) &&  
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV16_00_BIAS;  
1452    
1453                    /* intra decision */
1454    
1455  /* Step 6: If MinSAD <= thresa goto Step 10.                  if (iQuant > 8) InterBias += 100 * (iQuant - 8); /* to make high quants work */
1456     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.                  if (y != 0)
1457  */                          if ((pMB - pParam->mb_width)->mode == MODE_INTRA ) InterBias -= 80;
1458                    if (x != 0)
1459          if ((iMinSAD <= threshA) ||                          if ((pMB - 1)->mode == MODE_INTRA ) InterBias -= 80;
                 (MVequal(*currMV, prevMB->mvs[0]) &&  
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
         }  
   
1460    
1461  /************ (Diamond Search)  **************/                  if (Data->chroma) InterBias += 50; /* dev8(chroma) ??? <-- yes, we need dev8 (no big difference though) */
1462  /*                  if (Data->rrv) InterBias *= 4;
    Step 7: Perform Diamond search, with either the small or large diamond.  
    If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
    Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
    If center then goto step 10.  
    Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
    Refine by using small diamond and goto step 10.  
 */  
1463    
1464          if (MotionFlags & PMV_USESQUARES16)                  if (InterBias < sad) {
1465                  MainSearchPtr = Square16_MainSearch;                          int32_t deviation;
1466          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)                          if (!Data->rrv)
1467                  MainSearchPtr = AdvDiamond16_MainSearch;                                  deviation = dev16(Data->Cur, Data->iEdgedWidth);
1468          else          else
1469                  MainSearchPtr = Diamond16_MainSearch;                                  deviation = dev16(Data->Cur, Data->iEdgedWidth) + /* dev32() */
1470                                                            dev16(Data->Cur+16, Data->iEdgedWidth) +
1471                                                            dev16(Data->Cur + 16*Data->iEdgedWidth, Data->iEdgedWidth) +
1472                                                            dev16(Data->Cur+16+16*Data->iEdgedWidth, Data->iEdgedWidth);
1473    
1474                            if (deviation < (sad - InterBias)) mode = MODE_INTRA;
1475                    }
1476    
1477          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                  pMB->cbp = 63;
1478                    pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
1479    
1480            } else { /* Rate-Distortion */
1481    
1482  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                  int min_rd, intra_rd, i, cbp, c[2] = {0, 0};
1483          iSAD =                  VECTOR backup[5], *v;
1484                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                  Data->iQuant = iQuant;
1485                                                    currMV->x, currMV->y, iMinSAD, &newMV, center_x, center_y,                  Data->cbp = c;
                                                   min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
1486    
1487          if (iSAD < iMinSAD) {                  v = Data->qpel ? Data->currentQMV : Data->currentMV;
1488                  *currMV = newMV;                  for (i = 0; i < 5; i++) {
1489                  iMinSAD = iSAD;                          Data->iMinSAD[i] = 256*4096;
1490                            backup[i] = v[i];
1491          }          }
1492    
1493          if (MotionFlags & PMV_EXTSEARCH16) {                  min_rd = findRDinter(Data, pMBs, x, y, pParam, MotionFlags);
1494  /* extended: search (up to) two more times: orignal prediction and (0,0) */                  cbp = *Data->cbp;
   
                 if (!(MVequal(pmv[0], backupMV))) {  
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                                   center_x, center_y, iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
1495    
1496                          if (iSAD < iMinSAD) {                  if (coding_type == S_VOP) {
1497                                  *currMV = newMV;                          int gmc_rd;
1498                                  iMinSAD = iSAD;                          *Data->iMinSAD = min_rd += BITS_MULT*1; /* mcsel */
1499                            gmc_rd = findRDgmc(Data, vGMC, x, y);
1500                            if (gmc_rd < min_rd) {
1501                                    mcsel = 1;
1502                                    *Data->iMinSAD = min_rd = gmc_rd;
1503                                    mode = MODE_INTER;
1504                                    cbp = *Data->cbp;
1505                          }                          }
1506                  }                  }
1507    
1508                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                  if (inter4v) {
1509                          iSAD =                          int v4_rd;
1510                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                          v4_rd = findRDinter4v(Data, pMB, pMBs, x, y, pParam, MotionFlags, backup);
1511                                                                    iMinSAD, &newMV, center_x, center_y,                          if (v4_rd < min_rd) {
1512                                                                    min_dx, max_dx, min_dy, max_dy,                                  Data->iMinSAD[0] = min_rd = v4_rd;
1513                                                                    iEdgedWidth, iDiamondSize, iFcode,                                  mode = MODE_INTER4V;
1514                                                                    iQuant, iFound);                                  cbp = *Data->cbp;
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
1515                  }                  }
1516          }          }
1517    
1518  /*                  intra_rd = findRDintra(Data);
1519     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.                  if (intra_rd < min_rd) {
1520  */                          *Data->iMinSAD = min_rd = intra_rd;
1521                            mode = MODE_INTRA;
   PMVfast16_Terminate_with_Refine:  
         if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step  
                 iMinSAD =  
                         Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
   
   PMVfast16_Terminate_without_Refine:  
         currPMV->x = currMV->x - center_x;  
         currPMV->y = currMV->y - center_y;  
         return iMinSAD;  
1522  }  }
1523    
1524                    pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = 0;
1525                    pMB->cbp = cbp;
1526            }
1527    
1528            if (Data->rrv) {
1529                            Data->currentMV[0].x = RRV_MV_SCALEDOWN(Data->currentMV[0].x);
1530                            Data->currentMV[0].y = RRV_MV_SCALEDOWN(Data->currentMV[0].y);
1531            }
1532    
1533            if (mode == MODE_INTER && mcsel == 0) {
1534                    pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
1535    
1536                    if(Data->qpel) {
1537                            pMB->qmvs[0] = pMB->qmvs[1]
1538  int32_t                                  = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1539  Diamond8_MainSearch(const uint8_t * const pRef,                          pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1540                                          const uint8_t * const pRefH,                          pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x,  
                                         const int y,  
                                         int32_t start_x,  
                                         int32_t start_y,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iDirectionBackup;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
   
         if (iDirection) {  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;     // since iDirection!=0, this is well defined!  
                         iDirectionBackup = iDirection;  
   
                         if (iDirectionBackup != 2)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                   backupMV.y, 1);  
                         if (iDirectionBackup != 1)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                   backupMV.y, 2);  
                         if (iDirectionBackup != 4)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y - iDiamondSize, 3);  
                         if (iDirectionBackup != 3)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y + iDiamondSize, 4);  
                 }  
1541          } else {          } else {
1542                  currMV->x = start_x;                          pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1543                  currMV->y = start_y;                          pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
         }  
         return iMinSAD;  
1544  }  }
1545    
1546            } else if (mode == MODE_INTER ) { // but mcsel == 1
1547    
1548                    pMB->mcsel = 1;
1549                    if (Data->qpel) {
1550                            pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] = pMB->qmvs[3] = pMB->amv;
1551                            pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = pMB->amv.x/2;
1552                            pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = pMB->amv.y/2;
1553                    } else
1554                            pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->amv;
1555    
1556            } else
1557                    if (mode == MODE_INTER4V) ; /* anything here? */
1558            else    /* INTRA, NOT_CODED */
1559                    ZeroMacroblockP(pMB, 0);
1560    
1561            pMB->mode = mode;
1562    }
1563    
1564  int32_t  bool
1565  Square8_MainSearch(const uint8_t * const pRef,  MotionEstimation(MBParam * const pParam,
1566                                          const uint8_t * const pRefH,                                   FRAMEINFO * const current,
1567                                          const uint8_t * const pRefV,                                   FRAMEINFO * const reference,
1568                                          const uint8_t * const pRefHV,                                   const IMAGE * const pRefH,
1569                                          const uint8_t * const cur,                                   const IMAGE * const pRefV,
1570                                          const int x,                                   const IMAGE * const pRefHV,
1571                                          const int y,                                  const IMAGE * const pGMC,
1572                                          int32_t start_x,                                   const uint32_t iLimit)
1573                                          int32_t start_y,  {
1574                                          int32_t iMinSAD,          MACROBLOCK *const pMBs = current->mbs;
1575                                          VECTOR * const currMV,          const IMAGE *const pCurrent = &current->image;
1576                                     const int center_x,          const IMAGE *const pRef = &reference->image;
                                    const int center_y,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a square search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* It's one search with full square pattern, and new parts for all following diamonds */  
   
 /*   new direction are extra, so 1-4 is normal diamond  
       537  
       1*2  
       648  
 */  
1577    
1578          CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);          uint32_t mb_width = pParam->mb_width;
1579          CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);          uint32_t mb_height = pParam->mb_height;
1580          CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);          const uint32_t iEdgedWidth = pParam->edged_width;
1581          CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);          const uint32_t MotionFlags = MakeGoodMotionFlags(current->motion_flags, current->vop_flags, current->vol_flags);
1582            int stat_thresh = 0;
1583          CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
1584                                                           backupMV.y - iDiamondSize, 5);          uint32_t x, y;
1585          CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,          uint32_t iIntra = 0;
1586                                                           backupMV.y + iDiamondSize, 6);          int32_t sad00;
1587          CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,          int skip_thresh = INITIAL_SKIP_THRESH * \
1588                                                           backupMV.y - iDiamondSize, 7);                  (current->vop_flags & XVID_VOP_REDUCED ? 4:1) * \
1589          CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,                  (current->vop_flags & XVID_VOP_MODEDECISION_RD ? 2:1);
1590                                                           backupMV.y + iDiamondSize, 8);  
1591            /* some pre-initialized thingies for SearchP */
1592            int32_t temp[8]; uint32_t dir;
1593          if (iDirection) {          VECTOR currentMV[5];
1594                  while (!iFound) {          VECTOR currentQMV[5];
1595                          iFound = 1;          VECTOR currentMV2[5];
1596                          backupMV = *currMV;          VECTOR currentQMV2[5];
1597            int32_t iMinSAD[5];
1598            int32_t iMinSAD2[5];
1599            DECLARE_ALIGNED_MATRIX(dct_space, 3, 64, int16_t, CACHE_LINE);
1600            SearchData Data;
1601            memset(&Data, 0, sizeof(SearchData));
1602            Data.iEdgedWidth = iEdgedWidth;
1603            Data.currentMV = currentMV;
1604            Data.currentQMV = currentQMV;
1605            Data.currentMV2 = currentMV2;
1606            Data.currentQMV2 = currentQMV2;
1607            Data.iMinSAD = iMinSAD;
1608            Data.iMinSAD2 = iMinSAD2;
1609            Data.temp = temp;
1610            Data.dir = &dir;
1611            Data.iFcode = current->fcode;
1612            Data.rounding = pParam->m_rounding_type;
1613            Data.qpel = (current->vol_flags & XVID_VOL_QUARTERPEL ? 1:0);
1614            Data.chroma = MotionFlags & XVID_ME_CHROMA_PVOP;
1615            Data.rrv = (current->vop_flags & XVID_VOP_REDUCED) ? 1:0;
1616            Data.dctSpace = dct_space;
1617            Data.quant_type = !(pParam->vol_flags & XVID_VOL_MPEGQUANT);
1618    
1619            if ((current->vop_flags & XVID_VOP_REDUCED)) {
1620                    mb_width = (pParam->width + 31) / 32;
1621                    mb_height = (pParam->height + 31) / 32;
1622                    Data.qpel = 0;
1623            }
1624    
1625            Data.RefQ = pRefV->u; /* a good place, also used in MC (for similar purpose) */
1626            if (sadInit) (*sadInit) ();
1627    
1628            for (y = 0; y < mb_height; y++) {
1629                    for (x = 0; x < mb_width; x++)  {
1630                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1631                            MACROBLOCK *prevMB = &reference->mbs[x + y * pParam->mb_width];
1632    
1633                            if (!Data.rrv) pMB->sad16 =
1634                                    sad16v(pCurrent->y + (x + y * iEdgedWidth) * 16,
1635                                                            pRef->y + (x + y * iEdgedWidth) * 16,
1636                                                            pParam->edged_width, pMB->sad8 );
1637    
1638                            else pMB->sad16 =
1639                                    sad32v_c(pCurrent->y + (x + y * iEdgedWidth) * 32,
1640                                                            pRef->y + (x + y * iEdgedWidth) * 32,
1641                                                            pParam->edged_width, pMB->sad8 );
1642    
1643                            if (Data.chroma) {
1644                                    Data.temp[7] = sad8(pCurrent->u + x*8 + y*(iEdgedWidth/2)*8,
1645                                                                            pRef->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2)
1646                                                                    + sad8(pCurrent->v + (x + y*(iEdgedWidth/2))*8,
1647                                                                            pRef->v + (x + y*(iEdgedWidth/2))*8, iEdgedWidth/2);
1648                                    pMB->sad16 += Data.temp[7];
1649                            }
1650    
1651                            sad00 = pMB->sad16;
1652    
1653                            /* initial skip decision */
1654                            /* no early skip for GMC (global vector = skip vector is unknown!)  */
1655                            if (current->coding_type != S_VOP)      { /* no fast SKIP for S(GMC)-VOPs */
1656                                    if (pMB->dquant == 0 && sad00 < pMB->quant * skip_thresh)
1657                                            if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, iEdgedWidth/2, pMB->quant, Data.rrv)) {
1658                                                    ZeroMacroblockP(pMB, sad00);
1659                                                    pMB->mode = MODE_NOT_CODED;
1660                                                    continue;
1661                                            }
1662                            }
1663    
1664                          switch (iDirection) {                          if(MotionFlags & XVID_ME_DETECT_STATIC_MOTION) {
1665                          case 1:                                  if(x > 0 && y > 0 && x < pParam->mb_width)
1666                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                                          if(MVequal((&pMBs[(x-1) + y * pParam->mb_width])->mvs[0], zeroMV) &&
1667                                                                                     backupMV.y, 1);                                             MVequal((&pMBs[x + (y-1) * pParam->mb_width])->mvs[0], zeroMV) &&
1668                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                                         MVequal((&pMBs[(x+1) + (y-1) * pParam->mb_width])->mvs[0], zeroMV) &&
1669                                                                                   backupMV.y - iDiamondSize, 5);                                         MVequal(prevMB->mvs[0], zeroMV)) {
1670                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                                                  stat_thresh = MAX((&pMBs[(x-1) + y * pParam->mb_width])->sad16,
1671                                                                                   backupMV.y - iDiamondSize, 7);                                                                            MAX((&pMBs[x + (y-1) * pParam->mb_width])->sad16,
1672                                  break;                                                                            MAX((&pMBs[(x+1) + (y-1) * pParam->mb_width])->sad16,
1673                          case 2:                                                                            prevMB->sad16)));
1674                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,                                          }
1675                                                                                   2);                                  else
1676                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                                          stat_thresh = MIN((&pMBs[(x-1) + y * pParam->mb_width])->sad16,
1677                                                                                   backupMV.y + iDiamondSize, 6);                                                                            MIN((&pMBs[x + (y-1) * pParam->mb_width])->sad16,
1678                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                                                                            MIN((&pMBs[(x+1) + (y-1) * pParam->mb_width])->sad16,
1679                                                                                   backupMV.y + iDiamondSize, 8);                                                                            prevMB->sad16)));
1680                                  break;                          }
1681    
1682                          case 3:                          if ((current->vop_flags & XVID_VOP_CARTOON) &&
1683                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                                  (sad00 < pMB->quant * 4 * skip_thresh) || (sad00 < stat_thresh)) { /* favorize (0,0) vector for cartoons */
1684                                                                                   4);                                  ZeroMacroblockP(pMB, sad00);
1685                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                                  continue;
1686                                                                                   backupMV.y - iDiamondSize, 7);                          }
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
1687    
1688                          case 4:                          SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1689                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,                                          y, MotionFlags, current->vop_flags, current->vol_flags,
1690                                                                                   3);                                          &Data, pParam, pMBs, reference->mbs, pMB);
1691                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
1692                                                                                   backupMV.y - iDiamondSize, 5);                          if(current->vop_flags & XVID_VOP_FAST_MODEDECISION_RD) {
1693                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                                  ModeDecision_Fast(&Data, pMB, pMBs, x, y, pParam,
1694                                                                                   backupMV.y + iDiamondSize, 6);                                                           MotionFlags, current->vop_flags, current->vol_flags,
1695                                  break;                                                           pCurrent, pRef, pGMC, current->coding_type);
1696                            }
1697                          case 5:                          else {
1698                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,                                  ModeDecision(&Data, pMB, pMBs, x, y, pParam,
1699                                                                                   1);                                                           MotionFlags, current->vop_flags, current->vol_flags,
1700                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,                                                           pCurrent, pRef, pGMC, current->coding_type);
1701                                                                                   3);                          }
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
   
                         case 6:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
   
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
1702    
1703                                  break;                          if (pMB->mode == MODE_INTRA)
1704                                    if (++iIntra > iLimit) return 1;
1705                    }
1706            }
1707    
1708                          case 7:          return 0;
1709                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  }
                                                                                    backupMV.y, 1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
1710    
1711                          case 8:  /* check if given vector is equal to any vector checked before */
1712                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  static __inline int
1713                                                                                   2);  vector_repeats(const VECTOR * const pmv, const int i)
1714                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  {
1715                                                                                   4);          unsigned int j;
1716                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          for (j = 0; j < i; j++)
1717                                                                                   backupMV.y + iDiamondSize, 6);                  if (MVequal(pmv[i], pmv[j])) return 1; /* same vector has been checked already */
1718                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,          return 0;
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         default:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
   
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
1719                          }                          }
1720    
1721    /*      make a binary mask that prevents diamonds/squares
1722            from checking a vector which has been checked as a prediction */
1723    static __inline int
1724    make_mask(const VECTOR * const pmv, const int i, const int current)
1725    {
1726            unsigned int mask = 255, j;
1727            for (j = 0; j < i; j++) {
1728                    if (pmv[current].x == pmv[j].x) {
1729                            if (pmv[current].y == pmv[j].y + iDiamondSize) mask &= ~4;
1730                            else if (pmv[current].y == pmv[j].y - iDiamondSize) mask &= ~8;
1731                    } else
1732                            if (pmv[current].y == pmv[j].y) {
1733                                    if (pmv[current].x == pmv[j].x + iDiamondSize) mask &= ~1;
1734                                    else if (pmv[current].x == pmv[j].x - iDiamondSize) mask &= ~2;
1735                  }                  }
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
1736          }          }
1737          return iMinSAD;          return mask;
1738  }  }
1739    
1740    static __inline void
1741    PreparePredictionsP(VECTOR * const pmv, int x, int y, int iWcount,
1742                            int iHcount, const MACROBLOCK * const prevMB, int rrv)
1743    {
1744            /* this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself */
1745            if (rrv) { iWcount /= 2; iHcount /= 2; }
1746    
1747            if ( (y != 0) && (x < (iWcount-1)) ) {          /* [5] top-right neighbour */
1748                    pmv[5].x = EVEN(pmv[3].x);
1749                    pmv[5].y = EVEN(pmv[3].y);
1750            } else pmv[5].x = pmv[5].y = 0;
1751    
1752            if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }/* pmv[3] is left neighbour */
1753            else pmv[3].x = pmv[3].y = 0;
1754    
1755            if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }/* [4] top neighbour */
1756            else pmv[4].x = pmv[4].y = 0;
1757    
1758  int32_t          /* [1] median prediction */
1759  Halfpel8_Refine_c(const uint8_t * const pRef,          pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
                                 const uint8_t * const pRefH,  
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const uint8_t * const cur,  
                                 const int x,  
                                 const int y,  
                                 VECTOR * const currMV,  
                                 int32_t iMinSAD,  
                            const int center_x,  
                            const int center_y,  
                                 const int32_t min_dx,  
                                 const int32_t max_dx,  
                                 const int32_t min_dy,  
                                 const int32_t max_dy,  
                                 const int32_t iFcode,  
                                 const int32_t iQuant,  
                                 const int32_t iEdgedWidth)  
 {  
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
   
         int32_t iSAD;  
         VECTOR backupMV = *currMV;  
   
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y + 1);  
         CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y + 1);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y + 1);  
1760    
1761          return iMinSAD;          pmv[0].x = pmv[0].y = 0; /* [0] is zero; not used in the loop (checked before) but needed here for make_mask */
1762  }  
1763            pmv[2].x = EVEN(prevMB->mvs[0].x); /* [2] is last frame */
1764            pmv[2].y = EVEN(prevMB->mvs[0].y);
1765    
1766            if ((x < iWcount-1) && (y < iHcount-1)) {
1767                    pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); /* [6] right-down neighbour in last frame */
1768                    pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
1769            } else pmv[6].x = pmv[6].y = 0;
1770    
1771  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)          if (rrv) {
1772                    int i;
1773                    for (i = 0; i < 7; i++) {
1774                            pmv[i].x = RRV_MV_SCALEUP(pmv[i].x);
1775                            pmv[i].y = RRV_MV_SCALEUP(pmv[i].y);
1776                    }
1777            }
1778    }
1779    
1780  int32_t  static void
1781  PMVfastSearch8(const uint8_t * const pRef,  SearchP(const IMAGE * const pRef,
1782                             const uint8_t * const pRefH,                             const uint8_t * const pRefH,
1783                             const uint8_t * const pRefV,                             const uint8_t * const pRefV,
1784                             const uint8_t * const pRefHV,                             const uint8_t * const pRefHV,
1785                             const IMAGE * const pCur,                             const IMAGE * const pCur,
1786                             const int x,                             const int x,
1787                             const int y,                             const int y,
                            const int start_x,  
                            const int start_y,  
                                 const int center_x,  
                                 const int center_y,  
1788                             const uint32_t MotionFlags,                             const uint32_t MotionFlags,
1789                             const uint32_t iQuant,                  const uint32_t VopFlags,
1790                             const uint32_t iFcode,                  const uint32_t VolFlags,
1791                    SearchData * const Data,
1792                             const MBParam * const pParam,                             const MBParam * const pParam,
1793                             const MACROBLOCK * const pMBs,                             const MACROBLOCK * const pMBs,
1794                             const MACROBLOCK * const prevMBs,                             const MACROBLOCK * const prevMBs,
1795                             VECTOR * const currMV,                  MACROBLOCK * const pMB)
                            VECTOR * const currPMV)  
1796  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
1797    
1798          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;          int i, threshA;
1799            VECTOR pmv[7];
1800          int32_t iDiamondSize;          int inter4v = (VopFlags & XVID_VOP_INTER4V) && (pMB->dquant == 0);
1801            CheckFunc * CheckCandidate;
1802          int32_t min_dx;  
1803          int32_t max_dx;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
1804          int32_t min_dy;                                                  pParam->width, pParam->height, Data->iFcode - Data->qpel, 1, Data->rrv);
1805          int32_t max_dy;  
1806            get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);
1807          VECTOR pmv[4];  
1808          int32_t psad[4];          Data->temp[5] = Data->temp[6] = 0; /* chroma-sad cache */
1809          VECTOR newMV;          i = Data->rrv ? 2 : 1;
1810          VECTOR backupMV;          Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16*i;
1811          VECTOR startMV;          Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1812            Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1813    
1814            Data->RefP[0] = pRef->y + (x + Data->iEdgedWidth*y) * 16*i;
1815            Data->RefP[2] = pRefH + (x + Data->iEdgedWidth*y) * 16*i;
1816            Data->RefP[1] = pRefV + (x + Data->iEdgedWidth*y) * 16*i;
1817            Data->RefP[3] = pRefHV + (x + Data->iEdgedWidth*y) * 16*i;
1818            Data->RefP[4] = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1819            Data->RefP[5] = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1820    
1821            Data->lambda16 = lambda_vec16[pMB->quant];
1822            Data->lambda8 = lambda_vec8[pMB->quant];
1823            Data->qpel_precision = 0;
1824            *Data->dir = 0;
1825    
1826            memset(Data->currentMV, 0, 5*sizeof(VECTOR));
1827    
1828            if (Data->qpel) Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1829            else Data->predMV = pmv[0];
1830    
1831            i = d_mv_bits(0, 0, Data->predMV, Data->iFcode, 0, 0);
1832            Data->iMinSAD[0] = pMB->sad16 + ((Data->lambda16 * i * pMB->sad16)>>10);
1833            Data->iMinSAD[1] = pMB->sad8[0] + ((Data->lambda8 * i * (pMB->sad8[0]+NEIGH_8X8_BIAS)) >> 10);
1834            Data->iMinSAD[2] = pMB->sad8[1];
1835            Data->iMinSAD[3] = pMB->sad8[2];
1836            Data->iMinSAD[4] = pMB->sad8[3];
1837    
1838            if ((!(VopFlags & XVID_VOP_MODEDECISION_RD)) && (x | y)) {
1839                    threshA = Data->temp[0]; /* that's where we keep this SAD atm */
1840                    if (threshA < 512) threshA = 512;
1841                    else if (threshA > 1024) threshA = 1024;
1842            } else
1843                    threshA = 512;
1844    
1845  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
1846          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;                                          prevMBs + x + y * pParam->mb_width, Data->rrv);
1847    
1848           int32_t threshA, threshB;          if (!Data->rrv) {
1849          int32_t iFound, bPredEq;                  if (inter4v) CheckCandidate = CheckCandidate16;
1850          int32_t iMinSAD, iSAD;                          else CheckCandidate = CheckCandidate16no4v; /* for extra speed */
1851            } else CheckCandidate = CheckCandidate32;
1852    
1853    /* main loop. checking all predictions (but first, which is 0,0 and has been checked in MotionEstimation())*/
1854    
1855            for (i = 1; i < 7; i++)
1856                    if (!vector_repeats(pmv, i)) {
1857                            CheckCandidate(pmv[i].x, pmv[i].y, Data, i);
1858                            if (Data->iMinSAD[0] <= threshA) { i++; break; }
1859                    }
1860    
1861            if ((Data->iMinSAD[0] <= threshA) ||
1862                            (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
1863                            (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16)))
1864                    inter4v = 0;
1865            else {
1866    
1867          int32_t iSubBlock = (y & 1) + (y & 1) + (x & 1);                  MainSearchFunc * MainSearchPtr;
1868                    int mask = make_mask(pmv, i, *Data->dir); // all vectors pmv[0..i-1] have been checked
1869    
1870          MainSearch8FuncPtr MainSearchPtr;                  if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1871                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1872                            else MainSearchPtr = DiamondSearch;
1873    
1874          /* Init variables */                  MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, mask, CheckCandidate);
         startMV.x = start_x;  
         startMV.y = start_y;  
1875    
1876          /* Get maximum range */  /* extended search, diamond starting in 0,0 and in prediction.
1877          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,          note that this search is/might be done in halfpel positions,
1878                            iFcode);          which makes it more different than the diamond above */
1879    
1880          if (!(MotionFlags & PMV_HALFPELDIAMOND8)) {                  if (MotionFlags & XVID_ME_EXTSEARCH16) {
1881                  min_dx = EVEN(min_dx);                          int32_t bSAD;
1882                  max_dx = EVEN(max_dx);                          VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
1883                  min_dy = EVEN(min_dy);                          if (Data->rrv) {
1884                  max_dy = EVEN(max_dy);                                  startMV.x = RRV_MV_SCALEUP(startMV.x);
1885                                    startMV.y = RRV_MV_SCALEUP(startMV.y);
1886          }          }
1887                            if (!(MVequal(startMV, backupMV))) {
1888                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1889    
1890          /* because we might use IF (dx>max_dx) THEN dx=max_dx; */                                  CheckCandidate(startMV.x, startMV.y, Data, 255);
1891          //bPredEq = get_pmvdata(pMBs, (x >> 1), (y >> 1), iWcount, iSubBlock, pmv, psad);                                  MainSearchPtr(startMV.x, startMV.y, Data, 255, CheckCandidate);
1892          bPredEq = get_pmvdata2(pMBs, iWcount, 0, (x >> 1), (y >> 1), iSubBlock, pmv, psad);                                  if (bSAD < Data->iMinSAD[0]) {
1893                                            Data->currentMV[0] = backupMV;
1894          if ((x == 0) && (y == 0)) {                                          Data->iMinSAD[0] = bSAD; }
1895                  threshA = 512 / 4;                          }
                 threshB = 1024 / 4;  
1896    
1897          } else {                          backupMV = Data->currentMV[0];
1898                  threshA = psad[0] / 4;  /* good estimate? */                          startMV.x = startMV.y = 1;
1899                  threshB = threshA + 256 / 4;                          if (!(MVequal(startMV, backupMV))) {
1900                  if (threshA < 512 / 4)                                  bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
                         threshA = 512 / 4;  
                 if (threshA > 1024 / 4)  
                         threshA = 1024 / 4;  
                 if (threshB > 1792 / 4)  
                         threshB = 1792 / 4;  
         }  
   
         iFound = 0;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
1901    
1902                                    CheckCandidate(startMV.x, startMV.y, Data, 255);
1903                                    MainSearchPtr(startMV.x, startMV.y, Data, 255, CheckCandidate);
1904                                    if (bSAD < Data->iMinSAD[0]) {
1905                                            Data->currentMV[0] = backupMV;
1906                                            Data->iMinSAD[0] = bSAD;
1907                                    }
1908                            }
1909                    }
1910            }
1911    
1912  // Prepare for main loop          if (MotionFlags & XVID_ME_HALFPELREFINE16)
1913                            SubpelRefine(Data, CheckCandidate);
1914    
1915    if (MotionFlags & PMV_USESQUARES8)          for(i = 0; i < 5; i++) {
1916        MainSearchPtr = Square8_MainSearch;                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; /* initialize qpel vectors */
1917    else                  Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
1918            }
1919    
1920          if (MotionFlags & PMV_ADVANCEDDIAMOND8)          if (Data->qpel) {
1921                  MainSearchPtr = AdvDiamond8_MainSearch;                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
1922                                    pParam->width, pParam->height, Data->iFcode, 2, 0);
1923                    Data->qpel_precision = 1;
1924                    if (MotionFlags & XVID_ME_QUARTERPELREFINE16)
1925                            if(MotionFlags & XVID_ME_FASTREFINE16)
1926                                    SubpelRefine_Fast(Data, CheckCandidate);
1927          else          else
1928                  MainSearchPtr = Diamond8_MainSearch;                                  SubpelRefine(Data, CheckCandidate);
1929            }
1930    
1931          *currMV = startMV;          if (Data->iMinSAD[0] < (int32_t)pMB->quant * 30)
1932                    inter4v = 0;
1933    
1934          iMinSAD =          if (inter4v) {
1935                  sad8(cur,                  SearchData Data8;
1936                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,                  memcpy(&Data8, Data, sizeof(SearchData)); /* quick copy of common data */
                                                 iEdgedWidth), iEdgedWidth);  
         iMinSAD +=  
                 calc_delta_8(currMV->x - center_x, currMV->y - center_y,  
                                          (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256 / 4) || ((MVequal(*currMV, prevMB->mvs[iSubBlock]))  
                                                                 && ((int32_t) iMinSAD <  
                                                                         prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  
    vector of the median.  
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
1937    
1938          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[iSubBlock])))                  Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
1939                  iFound = 2;                  Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
1940                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
1941                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
1942    
1943  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.                  if ((Data->chroma) && (!(VopFlags & XVID_VOP_MODEDECISION_RD))) {
1944     Otherwise select large Diamond Search.                          /* chroma is only used for comparsion to INTER. if the comparsion will be done in BITS domain, it will not be used */
1945  */                          int sumx = 0, sumy = 0;
1946    
1947          if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))                          if (Data->qpel)
1948                  iDiamondSize = 1;               // 1 halfpel!                                  for (i = 1; i < 5; i++) {
1949                                            sumx += Data->currentQMV[i].x/2;
1950                                            sumy += Data->currentQMV[i].y/2;
1951                                    }
1952          else          else
1953                  iDiamondSize = 2;               // 2 halfpel = 1 full pixel!                                  for (i = 1; i < 5; i++) {
1954                                            sumx += Data->currentMV[i].x;
1955                                            sumy += Data->currentMV[i].y;
1956                                    }
1957    
1958          if (!(MotionFlags & PMV_HALFPELDIAMOND8))                          Data->iMinSAD[1] += ChromaSAD(  (sumx >> 3) + roundtab_76[sumx & 0xf],
1959                  iDiamondSize *= 2;                                                                                          (sumy >> 3) + roundtab_76[sumy & 0xf], Data);
1960                    }
1961            } else Data->iMinSAD[1] = 4096*256;
1962    }
1963    
1964    static void
1965    Search8(const SearchData * const OldData,
1966                    const int x, const int y,
1967                    const uint32_t MotionFlags,
1968                    const MBParam * const pParam,
1969                    MACROBLOCK * const pMB,
1970                    const MACROBLOCK * const pMBs,
1971                    const int block,
1972                    SearchData * const Data)
1973    {
1974            int i = 0;
1975            CheckFunc * CheckCandidate;
1976            Data->iMinSAD = OldData->iMinSAD + 1 + block;
1977            Data->currentMV = OldData->currentMV + 1 + block;
1978            Data->currentQMV = OldData->currentQMV + 1 + block;
1979    
1980            if(Data->qpel) {
1981                    Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1982                    if (block != 0) i = d_mv_bits(  Data->currentQMV->x, Data->currentQMV->y,
1983                                                                                    Data->predMV, Data->iFcode, 0, 0);
1984            } else {
1985                    Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1986                    if (block != 0) i = d_mv_bits(  Data->currentMV->x, Data->currentMV->y,
1987                                                                                    Data->predMV, Data->iFcode, 0, Data->rrv);
1988            }
1989    
1990  /*          *(Data->iMinSAD) += (Data->lambda8 * i * (*Data->iMinSAD + NEIGH_8X8_BIAS))>>10;
    Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  
    Also calculate (0,0) but do not subtract offset.  
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset.  
 */  
1991    
1992  // the median prediction might be even better than mv16          if (MotionFlags & (XVID_ME_EXTSEARCH8|XVID_ME_HALFPELREFINE8|XVID_ME_QUARTERPELREFINE8)) {
1993    
1994          if (!MVequal(pmv[0], startMV))                  if (Data->rrv) i = 16; else i = 8;
                 CHECK_MV8_CANDIDATE(center_x, center_y);  
1995    
1996  // (0,0) if needed                  Data->RefP[0] = OldData->RefP[0] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1997          if (!MVzero(pmv[0]))                  Data->RefP[1] = OldData->RefP[1] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1998                  if (!MVzero(startMV))                  Data->RefP[2] = OldData->RefP[2] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1999                          CHECK_MV8_ZERO;                  Data->RefP[3] = OldData->RefP[3] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
   
 // previous frame MV if needed  
         if (!MVzero(prevMB->mvs[iSubBlock]))  
                 if (!MVequal(prevMB->mvs[iSubBlock], startMV))  
                         if (!MVequal(prevMB->mvs[iSubBlock], pmv[0]))  
                                 CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x,  
                                                                         prevMB->mvs[iSubBlock].y);  
   
         if ((iMinSAD <= threshA) ||  
                 (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&  
                  ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 // left neighbour, if allowed and needed  
         if (!MVzero(pmv[1]))  
                 if (!MVequal(pmv[1], startMV))  
                         if (!MVequal(pmv[1], prevMB->mvs[iSubBlock]))  
                                 if (!MVequal(pmv[1], pmv[0])) {  
                                         if (!(MotionFlags & PMV_HALFPEL8)) {  
                                                 pmv[1].x = EVEN(pmv[1].x);  
                                                 pmv[1].y = EVEN(pmv[1].y);  
                                         }  
                                         CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);  
                                 }  
 // top neighbour, if allowed and needed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], startMV))  
                         if (!MVequal(pmv[2], prevMB->mvs[iSubBlock]))  
                                 if (!MVequal(pmv[2], pmv[0]))  
                                         if (!MVequal(pmv[2], pmv[1])) {  
                                                 if (!(MotionFlags & PMV_HALFPEL8)) {  
                                                         pmv[2].x = EVEN(pmv[2].x);  
                                                         pmv[2].y = EVEN(pmv[2].y);  
                                                 }  
                                                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed and needed  
                                                 if (!MVzero(pmv[3]))  
                                                         if (!MVequal(pmv[3], startMV))  
                                                                 if (!MVequal(pmv[3], prevMB->mvs[iSubBlock]))  
                                                                         if (!MVequal(pmv[3], pmv[0]))  
                                                                                 if (!MVequal(pmv[3], pmv[1]))  
                                                                                         if (!MVequal(pmv[3], pmv[2])) {  
                                                                                                 if (!  
                                                                                                         (MotionFlags &  
                                                                                                          PMV_HALFPEL8)) {  
                                                                                                         pmv[3].x = EVEN(pmv[3].x);  
                                                                                                         pmv[3].y = EVEN(pmv[3].y);  
                                                                                                 }  
                                                                                                 CHECK_MV8_CANDIDATE(pmv[3].x,  
                                                                                                                                         pmv[3].y);  
                                                                                         }  
                                         }  
   
         if ((MVzero(*currMV)) &&  
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV8_00_BIAS;  
2000    
2001                    Data->Cur = OldData->Cur + i * ((block&1) + Data->iEdgedWidth*(block>>1));
2002                    Data->qpel_precision = 0;
2003    
2004  /* Step 6: If MinSAD <= thresa goto Step 10.                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 3,
2005     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.                                          pParam->width, pParam->height, Data->iFcode - Data->qpel, 1, Data->rrv);
 */  
2006    
2007          if ((iMinSAD <= threshA) ||                  if (!Data->rrv) CheckCandidate = CheckCandidate8;
2008                  (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&                  else CheckCandidate = CheckCandidate16no4v;
                  ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
2009    
2010  /************ (Diamond Search)  **************/                  if (MotionFlags & XVID_ME_EXTSEARCH8 && (!(MotionFlags & XVID_ME_EXTSEARCH_RD))) {
2011  /*                          int32_t temp_sad = *(Data->iMinSAD); /* store current MinSAD */
    Step 7: Perform Diamond search, with either the small or large diamond.  
    If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
    Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
    If center then goto step 10.  
    Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
    Refine by using small diamond and goto step 10.  
 */  
2012    
2013          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                          MainSearchFunc *MainSearchPtr;
2014                            if (MotionFlags & XVID_ME_USESQUARES8) MainSearchPtr = SquareSearch;
2015                                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
2016                                            else MainSearchPtr = DiamondSearch;
2017    
2018  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, 255, CheckCandidate);
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  
                                                   currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
2019    
2020          if (iSAD < iMinSAD) {                          if(*(Data->iMinSAD) < temp_sad) {
2021                  *currMV = newMV;                                          Data->currentQMV->x = 2 * Data->currentMV->x; /* update our qpel vector */
2022                  iMinSAD = iSAD;                                          Data->currentQMV->y = 2 * Data->currentMV->y;
2023                            }
2024          }          }
2025    
2026          if (MotionFlags & PMV_EXTSEARCH8) {                  if (MotionFlags & XVID_ME_HALFPELREFINE8) {
2027  /* extended: search (up to) two more times: orignal prediction and (0,0) */                          int32_t temp_sad = *(Data->iMinSAD); /* store current MinSAD */
2028    
2029                  if (!(MVequal(pmv[0], backupMV))) {                          SubpelRefine(Data, CheckCandidate); /* perform halfpel refine of current best vector */
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
2030    
2031                          if (iSAD < iMinSAD) {                          if(*(Data->iMinSAD) < temp_sad) { /* we have found a better match */
2032                                  *currMV = newMV;                                  Data->currentQMV->x = 2 * Data->currentMV->x; /* update our qpel vector */
2033                                  iMinSAD = iSAD;                                  Data->currentQMV->y = 2 * Data->currentMV->y;
2034                          }                          }
2035                  }                  }
2036    
2037                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                  if (Data->qpel && MotionFlags & XVID_ME_QUARTERPELREFINE8) {
2038                          iSAD =                                  Data->qpel_precision = 1;
2039                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 3,
2040                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,                                          pParam->width, pParam->height, Data->iFcode, 2, 0);
2041                                                                    max_dy, iEdgedWidth, iDiamondSize, iFcode,                                  SubpelRefine(Data, CheckCandidate);
2042                                                                    iQuant, iFound);                  }
2043            }
2044    
2045                          if (iSAD < iMinSAD) {          if (Data->rrv) {
2046                                  *currMV = newMV;                          Data->currentMV->x = RRV_MV_SCALEDOWN(Data->currentMV->x);
2047                                  iMinSAD = iSAD;                          Data->currentMV->y = RRV_MV_SCALEDOWN(Data->currentMV->y);
2048                          }                          }
2049    
2050            if(Data->qpel) {
2051                    pMB->pmvs[block].x = Data->currentQMV->x - Data->predMV.x;
2052                    pMB->pmvs[block].y = Data->currentQMV->y - Data->predMV.y;
2053                    pMB->qmvs[block] = *Data->currentQMV;
2054            } else {
2055                    pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
2056                    pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
2057                  }                  }
2058    
2059            pMB->mvs[block] = *Data->currentMV;
2060            pMB->sad8[block] = 4 * *Data->iMinSAD;
2061          }          }
2062    
2063  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.  /* motion estimation for B-frames */
2064     By performing an optional local half-pixel search, we can refine this result even further.  
2065  */  static __inline VECTOR
2066    ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
2067    {
2068    /* the stupidiest function ever */
2069            return (mode == MODE_FORWARD ? pMB->mvs[0] : pMB->b_mvs[0]);
2070    }
2071    
2072    static void __inline
2073    PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
2074                                                            const uint32_t iWcount,
2075                                                            const MACROBLOCK * const pMB,
2076                                                            const uint32_t mode_curr)
2077    {
2078    
2079    PMVfast8_Terminate_with_Refine:          /* [0] is prediction */
2080          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step          pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
                 iMinSAD =  
                         Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                         iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                         iFcode, iQuant, iEdgedWidth);  
2081    
2082            pmv[1].x = pmv[1].y = 0; /* [1] is zero */
2083    
2084            pmv[2] = ChoosePred(pMB, mode_curr);
2085            pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
2086    
2087            if ((y != 0)&&(x != (int)(iWcount+1))) {                        /* [3] top-right neighbour */
2088                    pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
2089                    pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
2090            } else pmv[3].x = pmv[3].y = 0;
2091    
2092            if (y != 0) {
2093                    pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
2094                    pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
2095            } else pmv[4].x = pmv[4].y = 0;
2096    
2097    PMVfast8_Terminate_without_Refine:          if (x != 0) {
2098          currPMV->x = currMV->x - center_x;                  pmv[5] = ChoosePred(pMB-1, mode_curr);
2099          currPMV->y = currMV->y - center_y;                  pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
2100            } else pmv[5].x = pmv[5].y = 0;
2101    
2102          return iMinSAD;          if (x != 0 && y != 0) {
2103                    pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
2104                    pmv[6].x = EVEN(pmv[6].x); pmv[6].y = EVEN(pmv[6].y);
2105            } else pmv[6].x = pmv[6].y = 0;
2106  }  }
2107    
2108  int32_t  
2109  EPZSSearch16(const uint8_t * const pRef,  /* search backward or forward */
2110    static void
2111    SearchBF(       const IMAGE * const pRef,
2112                           const uint8_t * const pRefH,                           const uint8_t * const pRefH,
2113                           const uint8_t * const pRefV,                           const uint8_t * const pRefV,
2114                           const uint8_t * const pRefHV,                           const uint8_t * const pRefHV,
2115                           const IMAGE * const pCur,                           const IMAGE * const pCur,
2116                           const int x,                          const int x, const int y,
                          const int y,  
                         const int start_x,  
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
2117                           const uint32_t MotionFlags,                           const uint32_t MotionFlags,
                          const uint32_t iQuant,  
2118                           const uint32_t iFcode,                           const uint32_t iFcode,
2119                           const MBParam * const pParam,                           const MBParam * const pParam,
2120                           const MACROBLOCK * const pMBs,                          MACROBLOCK * const pMB,
2121                           const MACROBLOCK * const prevMBs,                          const VECTOR * const predMV,
2122                           VECTOR * const currMV,                          int32_t * const best_sad,
2123                           VECTOR * const currPMV)                          const int32_t mode_current,
2124  {                          SearchData * const Data)
2125          const uint32_t iWcount = pParam->mb_width;  {
2126          const uint32_t iHcount = pParam->mb_height;  
2127            int i;
2128          const int32_t iWidth = pParam->width;          VECTOR pmv[7];
2129          const int32_t iHeight = pParam->height;          MainSearchFunc *MainSearchPtr;
2130          const int32_t iEdgedWidth = pParam->edged_width;          *Data->iMinSAD = MV_MAX_ERROR;
2131            Data->iFcode = iFcode;
2132          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          Data->qpel_precision = 0;
2133            Data->temp[5] = Data->temp[6] = Data->temp[7] = 256*4096; /* reset chroma-sad cache */
2134    
2135            Data->RefP[0] = pRef->y + (x + Data->iEdgedWidth*y) * 16;
2136            Data->RefP[2] = pRefH + (x + Data->iEdgedWidth*y) * 16;
2137            Data->RefP[1] = pRefV + (x + Data->iEdgedWidth*y) * 16;
2138            Data->RefP[3] = pRefHV + (x + Data->iEdgedWidth*y) * 16;
2139            Data->RefP[4] = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8;
2140            Data->RefP[5] = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8;
2141    
2142            Data->predMV = *predMV;
2143    
2144            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
2145                                    pParam->width, pParam->height, iFcode - Data->qpel, 1, 0);
2146    
2147            pmv[0] = Data->predMV;
2148            if (Data->qpel) { pmv[0].x /= 2; pmv[0].y /= 2; }
2149    
2150            PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);
2151    
2152            Data->currentMV->x = Data->currentMV->y = 0;
2153    
2154            /* main loop. checking all predictions */
2155            for (i = 0; i < 7; i++)
2156                    if (!vector_repeats(pmv, i) )
2157                            CheckCandidate16no4v(pmv[i].x, pmv[i].y, Data, i);
2158    
2159            if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
2160            else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
2161                    else MainSearchPtr = DiamondSearch;
2162    
2163            if (*Data->iMinSAD > 512) {
2164                    unsigned int mask = make_mask(pmv, 7, *Data->dir);
2165                    MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, mask, CheckCandidate16no4v);
2166            }
2167    
2168            SubpelRefine(Data, CheckCandidate16no4v);
2169    
2170            if (Data->qpel && *Data->iMinSAD < *best_sad + 300) {
2171                    Data->currentQMV->x = 2*Data->currentMV->x;
2172                    Data->currentQMV->y = 2*Data->currentMV->y;
2173                    Data->qpel_precision = 1;
2174                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
2175                                            pParam->width, pParam->height, iFcode, 2, 0);
2176                    SubpelRefine(Data, CheckCandidate16no4v);
2177            }
2178    
2179            /* three bits are needed to code backward mode. four for forward */
2180    
2181            if (mode_current == MODE_FORWARD) *Data->iMinSAD += 4 * Data->lambda16;
2182            else *Data->iMinSAD += 3 * Data->lambda16;
2183    
2184            if (*Data->iMinSAD < *best_sad) {
2185                    *best_sad = *Data->iMinSAD;
2186                    pMB->mode = mode_current;
2187                    if (Data->qpel) {
2188                            pMB->pmvs[0].x = Data->currentQMV->x - predMV->x;
2189                            pMB->pmvs[0].y = Data->currentQMV->y - predMV->y;
2190                            if (mode_current == MODE_FORWARD)
2191                                    pMB->qmvs[0] = *Data->currentQMV;
2192                            else
2193                                    pMB->b_qmvs[0] = *Data->currentQMV;
2194                    } else {
2195                            pMB->pmvs[0].x = Data->currentMV->x - predMV->x;
2196                            pMB->pmvs[0].y = Data->currentMV->y - predMV->y;
2197                    }
2198                    if (mode_current == MODE_FORWARD) pMB->mvs[0] = *Data->currentMV;
2199                    else pMB->b_mvs[0] = *Data->currentMV;
2200            }
2201    
2202          int32_t min_dx;          if (mode_current == MODE_FORWARD) *(Data->currentMV+2) = *Data->currentMV;
2203          int32_t max_dx;          else *(Data->currentMV+1) = *Data->currentMV; /* we store currmv for interpolate search */
2204          int32_t min_dy;  }
2205          int32_t max_dy;  
2206    static void
2207    SkipDecisionB(const IMAGE * const pCur,
2208                                    const IMAGE * const f_Ref,
2209                                    const IMAGE * const b_Ref,
2210                                    MACROBLOCK * const pMB,
2211                                    const uint32_t x, const uint32_t y,
2212                                    const SearchData * const Data)
2213    {
2214            int dx = 0, dy = 0, b_dx = 0, b_dy = 0;
2215            int32_t sum;
2216            int k;
2217            const uint32_t stride = Data->iEdgedWidth/2;
2218            /* this is not full chroma compensation, only it's fullpel approximation. should work though */
2219    
2220          VECTOR newMV;          for (k = 0; k < 4; k++) {
2221          VECTOR backupMV;                  dy += Data->directmvF[k].y >> Data->qpel;
2222                    dx += Data->directmvF[k].x >> Data->qpel;
2223                    b_dy += Data->directmvB[k].y >> Data->qpel;
2224                    b_dx += Data->directmvB[k].x >> Data->qpel;
2225            }
2226    
2227            dy = (dy >> 3) + roundtab_76[dy & 0xf];
2228            dx = (dx >> 3) + roundtab_76[dx & 0xf];
2229            b_dy = (b_dy >> 3) + roundtab_76[b_dy & 0xf];
2230            b_dx = (b_dx >> 3) + roundtab_76[b_dx & 0xf];
2231    
2232            sum = sad8bi(pCur->u + 8 * x + 8 * y * stride,
2233                                            f_Ref->u + (y*8 + dy/2) * stride + x*8 + dx/2,
2234                                            b_Ref->u + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
2235                                            stride);
2236    
2237            if (sum >= MAX_CHROMA_SAD_FOR_SKIP * Data->iQuant) return; /* no skip */
2238    
2239            sum += sad8bi(pCur->v + 8*x + 8 * y * stride,
2240                                            f_Ref->v + (y*8 + dy/2) * stride + x*8 + dx/2,
2241                                            b_Ref->v + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
2242                                            stride);
2243    
2244          VECTOR pmv[4];          if (sum < MAX_CHROMA_SAD_FOR_SKIP * Data->iQuant) {
2245          int32_t psad[8];                  pMB->mode = MODE_DIRECT_NONE_MV; /* skipped */
2246                    for (k = 0; k < 4; k++) {
2247                            pMB->qmvs[k] = pMB->mvs[k];
2248                            pMB->b_qmvs[k] = pMB->b_mvs[k];
2249                    }
2250            }
2251    }
2252    
2253          static MACROBLOCK *oldMBs = NULL;  static __inline uint32_t
2254    SearchDirect(const IMAGE * const f_Ref,
2255                                    const uint8_t * const f_RefH,
2256                                    const uint8_t * const f_RefV,
2257                                    const uint8_t * const f_RefHV,
2258                                    const IMAGE * const b_Ref,
2259                                    const uint8_t * const b_RefH,
2260                                    const uint8_t * const b_RefV,
2261                                    const uint8_t * const b_RefHV,
2262                                    const IMAGE * const pCur,
2263                                    const int x, const int y,
2264                                    const uint32_t MotionFlags,
2265                                    const int32_t TRB, const int32_t TRD,
2266                                    const MBParam * const pParam,
2267                                    MACROBLOCK * const pMB,
2268                                    const MACROBLOCK * const b_mb,
2269                                    int32_t * const best_sad,
2270                                    SearchData * const Data)
2271    
2272    {
2273            int32_t skip_sad;
2274            int k = (x + Data->iEdgedWidth*y) * 16;
2275            MainSearchFunc *MainSearchPtr;
2276            CheckFunc * CheckCandidate;
2277    
2278            *Data->iMinSAD = 256*4096;
2279            Data->RefP[0] = f_Ref->y + k;
2280            Data->RefP[2] = f_RefH + k;
2281            Data->RefP[1] = f_RefV + k;
2282            Data->RefP[3] = f_RefHV + k;
2283            Data->b_RefP[0] = b_Ref->y + k;
2284            Data->b_RefP[2] = b_RefH + k;
2285            Data->b_RefP[1] = b_RefV + k;
2286            Data->b_RefP[3] = b_RefHV + k;
2287            Data->RefP[4] = f_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
2288            Data->RefP[5] = f_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
2289            Data->b_RefP[4] = b_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
2290            Data->b_RefP[5] = b_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
2291    
2292            k = Data->qpel ? 4 : 2;
2293            Data->max_dx = k * (pParam->width - x * 16);
2294            Data->max_dy = k * (pParam->height - y * 16);
2295            Data->min_dx = -k * (16 + x * 16);
2296            Data->min_dy = -k * (16 + y * 16);
2297    
2298  //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;          Data->referencemv = Data->qpel ? b_mb->qmvs : b_mb->mvs;
2299          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;          Data->qpel_precision = 0;
         MACROBLOCK *oldMB = NULL;  
2300    
2301           int32_t thresh2;          for (k = 0; k < 4; k++) {
2302          int32_t bPredEq;                  pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);
2303          int32_t iMinSAD, iSAD = 9999;                  pMB->b_mvs[k].x = Data->directmvB[k].x = ((TRB - TRD) * Data->referencemv[k].x) / TRD;
2304                    pMB->mvs[k].y = Data->directmvF[k].y = ((TRB * Data->referencemv[k].y) / TRD);
2305                    pMB->b_mvs[k].y = Data->directmvB[k].y = ((TRB - TRD) * Data->referencemv[k].y) / TRD;
2306    
2307          MainSearch16FuncPtr MainSearchPtr;                  if ( (pMB->b_mvs[k].x > Data->max_dx) | (pMB->b_mvs[k].x < Data->min_dx)
2308                            | (pMB->b_mvs[k].y > Data->max_dy) | (pMB->b_mvs[k].y < Data->min_dy) ) {
2309    
2310          if (oldMBs == NULL) {                          *best_sad = 256*4096; /* in that case, we won't use direct mode */
2311                  oldMBs = (MACROBLOCK *) calloc(iWcount * iHcount, sizeof(MACROBLOCK));                          pMB->mode = MODE_DIRECT; /* just to make sure it doesn't say "MODE_DIRECT_NONE_MV" */
2312  //      fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));                          pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;
2313                            return 256*4096;
2314                    }
2315                    if (b_mb->mode != MODE_INTER4V) {
2316                            pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mvs[0];
2317                            pMB->b_mvs[1] = pMB->b_mvs[2] = pMB->b_mvs[3] = pMB->b_mvs[0];
2318                            Data->directmvF[1] = Data->directmvF[2] = Data->directmvF[3] = Data->directmvF[0];
2319                            Data->directmvB[1] = Data->directmvB[2] = Data->directmvB[3] = Data->directmvB[0];
2320                            break;
2321                    }
2322          }          }
         oldMB = oldMBs + x + y * iWcount;  
2323    
2324  /* Get maximum range */          CheckCandidate = b_mb->mode == MODE_INTER4V ? CheckCandidateDirect : CheckCandidateDirectno4v;
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
2325    
2326          if (!(MotionFlags & PMV_HALFPEL16)) {          CheckCandidate(0, 0, Data, 255);
2327                  min_dx = EVEN(min_dx);  
2328                  max_dx = EVEN(max_dx);          /* initial (fast) skip decision */
2329                  min_dy = EVEN(min_dy);          if (*Data->iMinSAD < Data->iQuant * INITIAL_SKIP_THRESH * (Data->chroma?3:2)) {
2330                  max_dy = EVEN(max_dy);                  /* possible skip */
2331                    if (Data->chroma) {
2332                            pMB->mode = MODE_DIRECT_NONE_MV;
2333                            return *Data->iMinSAD; /* skip. */
2334                    } else {
2335                            SkipDecisionB(pCur, f_Ref, b_Ref, pMB, x, y, Data);
2336                            if (pMB->mode == MODE_DIRECT_NONE_MV) return *Data->iMinSAD; /* skip. */
2337          }          }
2338          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */          }
2339          //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  
2340          bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);          *Data->iMinSAD += Data->lambda16;
2341            skip_sad = *Data->iMinSAD;
2342    
2343  /* Step 4: Calculate SAD around the Median prediction.          /*
2344          MinSAD=SAD           * DIRECT MODE DELTA VECTOR SEARCH.
2345          If Motion Vector equal to Previous frame motion vector           * This has to be made more effective, but at the moment I'm happy it's running at all
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
2346  */  */
2347    
2348  // Prepare for main loop          if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
2349                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
2350                            else MainSearchPtr = DiamondSearch;
2351    
2352          currMV->x = start_x;          MainSearchPtr(0, 0, Data, 255, CheckCandidate);
         currMV->y = start_y;  
2353    
2354          if (!(MotionFlags & PMV_HALFPEL16)) {          SubpelRefine(Data, CheckCandidate);
                 currMV->x = EVEN(currMV->x);  
                 currMV->y = EVEN(currMV->y);  
         }  
   
         if (currMV->x > max_dx)  
                 currMV->x = max_dx;  
         if (currMV->x < min_dx)  
                 currMV->x = min_dx;  
         if (currMV->y > max_dy)  
                 currMV->y = max_dy;  
         if (currMV->y < min_dy)  
                 currMV->y = min_dy;  
   
 /***************** This is predictor SET A: only median prediction ******************/  
   
         iMinSAD =  
                 sad16(cur,  
                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
   
 // thresh1 is fixed to 256  
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
         }  
   
 /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/  
2355    
2356  // previous frame MV          *best_sad = *Data->iMinSAD;
         CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);  
2357    
2358  // set threshhold based on Min of Prediction and SAD of collocated block          if (Data->qpel || b_mb->mode == MODE_INTER4V) pMB->mode = MODE_DIRECT;
2359  // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want          else pMB->mode = MODE_DIRECT_NO4V; /* for faster compensation */
2360    
2361          if ((x == 0) && (y == 0)) {          pMB->pmvs[3] = *Data->currentMV;
                 thresh2 = 512;  
         } else {  
 /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */  
2362    
2363                  thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;          for (k = 0; k < 4; k++) {
2364                    pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
2365                    pMB->b_mvs[k].x = (     (Data->currentMV->x == 0)
2366                                                            ? Data->directmvB[k].x
2367                                                            :pMB->mvs[k].x - Data->referencemv[k].x);
2368                    pMB->mvs[k].y = (Data->directmvF[k].y + Data->currentMV->y);
2369                    pMB->b_mvs[k].y = ((Data->currentMV->y == 0)
2370                                                            ? Data->directmvB[k].y
2371                                                            : pMB->mvs[k].y - Data->referencemv[k].y);
2372                    if (Data->qpel) {
2373                            pMB->qmvs[k].x = pMB->mvs[k].x; pMB->mvs[k].x /= 2;
2374                            pMB->b_qmvs[k].x = pMB->b_mvs[k].x; pMB->b_mvs[k].x /= 2;
2375                            pMB->qmvs[k].y = pMB->mvs[k].y; pMB->mvs[k].y /= 2;
2376                            pMB->b_qmvs[k].y = pMB->b_mvs[k].y; pMB->b_mvs[k].y /= 2;
2377                    }
2378    
2379                    if (b_mb->mode != MODE_INTER4V) {
2380                            pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
2381                            pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
2382                            pMB->qmvs[3] = pMB->qmvs[2] = pMB->qmvs[1] = pMB->qmvs[0];
2383                            pMB->b_qmvs[3] = pMB->b_qmvs[2] = pMB->b_qmvs[1] = pMB->b_qmvs[0];
2384                            break;
2385          }          }
2386            }
2387            return skip_sad;
2388    }
2389    
2390    static void
2391    SearchInterpolate(const IMAGE * const f_Ref,
2392                                    const uint8_t * const f_RefH,
2393                                    const uint8_t * const f_RefV,
2394                                    const uint8_t * const f_RefHV,
2395                                    const IMAGE * const b_Ref,
2396                                    const uint8_t * const b_RefH,
2397                                    const uint8_t * const b_RefV,
2398                                    const uint8_t * const b_RefHV,
2399                                    const IMAGE * const pCur,
2400                                    const int x, const int y,
2401                                    const uint32_t fcode,
2402                                    const uint32_t bcode,
2403                                    const uint32_t MotionFlags,
2404                                    const MBParam * const pParam,
2405                                    const VECTOR * const f_predMV,
2406                                    const VECTOR * const b_predMV,
2407                                    MACROBLOCK * const pMB,
2408                                    int32_t * const best_sad,
2409                                    SearchData * const fData)
2410    
2411  // MV=(0,0) is often a good choice  {
2412    
2413          CHECK_MV16_ZERO;          int i, j;
2414            SearchData bData;
2415    
2416            fData->qpel_precision = 0;
2417            memcpy(&bData, fData, sizeof(SearchData)); /* quick copy of common data */
2418            *fData->iMinSAD = 4096*256;
2419            bData.currentMV++; bData.currentQMV++;
2420            fData->iFcode = bData.bFcode = fcode; fData->bFcode = bData.iFcode = bcode;
2421    
2422            i = (x + y * fData->iEdgedWidth) * 16;
2423    
2424            bData.b_RefP[0] = fData->RefP[0] = f_Ref->y + i;
2425            bData.b_RefP[2] = fData->RefP[2] = f_RefH + i;
2426            bData.b_RefP[1] = fData->RefP[1] = f_RefV + i;
2427            bData.b_RefP[3] = fData->RefP[3] = f_RefHV + i;
2428            bData.RefP[0] = fData->b_RefP[0] = b_Ref->y + i;
2429            bData.RefP[2] = fData->b_RefP[2] = b_RefH + i;
2430            bData.RefP[1] = fData->b_RefP[1] = b_RefV + i;
2431            bData.RefP[3] = fData->b_RefP[3] = b_RefHV + i;
2432            bData.b_RefP[4] = fData->RefP[4] = f_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
2433            bData.b_RefP[5] = fData->RefP[5] = f_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
2434            bData.RefP[4] = fData->b_RefP[4] = b_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
2435            bData.RefP[5] = fData->b_RefP[5] = b_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
2436            bData.dir = fData->dir;
2437    
2438            bData.bpredMV = fData->predMV = *f_predMV;
2439            fData->bpredMV = bData.predMV = *b_predMV;
2440            fData->currentMV[0] = fData->currentMV[2];
2441    
2442            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);
2443            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);
2444    
2445            if (fData->currentMV[0].x > fData->max_dx) fData->currentMV[0].x = fData->max_dx;
2446            if (fData->currentMV[0].x < fData->min_dx) fData->currentMV[0].x = fData->min_dx;
2447            if (fData->currentMV[0].y > fData->max_dy) fData->currentMV[0].y = fData->max_dy;
2448            if (fData->currentMV[0].y < fData->min_dy) fData->currentMV[0].y = fData->min_dy;
2449    
2450            if (fData->currentMV[1].x > bData.max_dx) fData->currentMV[1].x = bData.max_dx;
2451            if (fData->currentMV[1].x < bData.min_dx) fData->currentMV[1].x = bData.min_dx;
2452            if (fData->currentMV[1].y > bData.max_dy) fData->currentMV[1].y = bData.max_dy;
2453            if (fData->currentMV[1].y < bData.min_dy) fData->currentMV[1].y = bData.min_dy;
2454    
2455            CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, fData, 255);
2456    
2457  // left neighbour, if allowed          /* diamond */
2458          if (x != 0) {          do {
2459                  if (!(MotionFlags & PMV_HALFPEL16)) {                  *fData->dir = 255;
2460                          pmv[1].x = EVEN(pmv[1].x);                  /* forward MV moves */
2461                          pmv[1].y = EVEN(pmv[1].y);                  i = fData->currentMV[0].x; j = fData->currentMV[0].y;
2462    
2463                    CheckCandidateInt(i + 1, j, fData, 0);
2464                    CheckCandidateInt(i, j + 1, fData, 0);
2465                    CheckCandidateInt(i - 1, j, fData, 0);
2466                    CheckCandidateInt(i, j - 1, fData, 0);
2467    
2468                    /* backward MV moves */
2469                    i = fData->currentMV[1].x; j = fData->currentMV[1].y;
2470                    fData->currentMV[2] = fData->currentMV[0];
2471                    CheckCandidateInt(i + 1, j, &bData, 0);
2472                    CheckCandidateInt(i, j + 1, &bData, 0);
2473                    CheckCandidateInt(i - 1, j, &bData, 0);
2474                    CheckCandidateInt(i, j - 1, &bData, 0);
2475    
2476            } while (!(*fData->dir));
2477    
2478            /* qpel refinement */
2479            if (fData->qpel) {
2480                    if (*fData->iMinSAD > *best_sad + 500) return;
2481                    fData->qpel_precision = bData.qpel_precision = 1;
2482                    get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 4, pParam->width, pParam->height, fcode, 2, 0);
2483                    get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 4, pParam->width, pParam->height, bcode, 2, 0);
2484                    fData->currentQMV[2].x = fData->currentQMV[0].x = 2 * fData->currentMV[0].x;
2485                    fData->currentQMV[2].y = fData->currentQMV[0].y = 2 * fData->currentMV[0].y;
2486                    fData->currentQMV[1].x = 2 * fData->currentMV[1].x;
2487                    fData->currentQMV[1].y = 2 * fData->currentMV[1].y;
2488                    SubpelRefine(fData, CheckCandidateInt);
2489                    if (*fData->iMinSAD > *best_sad + 300) return;
2490                    fData->currentQMV[2] = fData->currentQMV[0];
2491                    SubpelRefine(&bData, CheckCandidateInt);
2492            }
2493    
2494            *fData->iMinSAD += (2+3) * fData->lambda16; /* two bits are needed to code interpolate mode. */
2495    
2496            if (*fData->iMinSAD < *best_sad) {
2497                    *best_sad = *fData->iMinSAD;
2498                    pMB->mvs[0] = fData->currentMV[0];
2499                    pMB->b_mvs[0] = fData->currentMV[1];
2500                    pMB->mode = MODE_INTERPOLATE;
2501                    if (fData->qpel) {
2502                            pMB->qmvs[0] = fData->currentQMV[0];
2503                            pMB->b_qmvs[0] = fData->currentQMV[1];
2504                            pMB->pmvs[1].x = pMB->qmvs[0].x - f_predMV->x;
2505                            pMB->pmvs[1].y = pMB->qmvs[0].y - f_predMV->y;
2506                            pMB->pmvs[0].x = pMB->b_qmvs[0].x - b_predMV->x;
2507                            pMB->pmvs[0].y = pMB->b_qmvs[0].y - b_predMV->y;
2508                    } else {
2509                            pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;
2510                            pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;
2511                            pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;
2512                            pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;
2513                  }                  }
                 CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
2514          }          }
 // top neighbour, if allowed  
         if (y != 0) {  
                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                         pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
2515                  }                  }
                 CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
2516    
2517  // top right neighbour, if allowed  void
2518                  if ((uint32_t) x != (iWcount - 1)) {  MotionEstimationBVOP(MBParam * const pParam,
2519                          if (!(MotionFlags & PMV_HALFPEL16)) {                                           FRAMEINFO * const frame,
2520                                  pmv[3].x = EVEN(pmv[3].x);                                           const int32_t time_bp,
2521                                  pmv[3].y = EVEN(pmv[3].y);                                           const int32_t time_pp,
2522                                             /* forward (past) reference */
2523                                             const MACROBLOCK * const f_mbs,
2524                                             const IMAGE * const f_ref,
2525                                             const IMAGE * const f_refH,
2526                                             const IMAGE * const f_refV,
2527                                             const IMAGE * const f_refHV,
2528                                             /* backward (future) reference */
2529                                             const FRAMEINFO * const b_reference,
2530                                             const IMAGE * const b_ref,
2531                                             const IMAGE * const b_refH,
2532                                             const IMAGE * const b_refV,
2533                                             const IMAGE * const b_refHV)
2534    {
2535            uint32_t i, j;
2536            int32_t best_sad;
2537            uint32_t skip_sad;
2538            int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;
2539            const MACROBLOCK * const b_mbs = b_reference->mbs;
2540    
2541            VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
2542    
2543            const int32_t TRB = time_pp - time_bp;
2544            const int32_t TRD = time_pp;
2545    
2546            /* some pre-inintialized data for the rest of the search */
2547    
2548            SearchData Data;
2549            int32_t iMinSAD;
2550            uint32_t dir;
2551            VECTOR currentMV[3];
2552            VECTOR currentQMV[3];
2553            int32_t temp[8];
2554            memset(&Data, 0, sizeof(SearchData));
2555            Data.iEdgedWidth = pParam->edged_width;
2556            Data.currentMV = currentMV; Data.currentQMV = currentQMV;
2557            Data.iMinSAD = &iMinSAD;
2558            Data.lambda16 = lambda_vec16[MAX(frame->quant-2, 2)];
2559            Data.qpel = pParam->vol_flags & XVID_VOL_QUARTERPEL ? 1 : 0;
2560            Data.rounding = 0;
2561            Data.chroma = frame->motion_flags & XVID_ME_CHROMA_BVOP;
2562            Data.temp = temp;
2563            Data.dir = &dir;
2564            Data.iQuant = frame->quant;
2565    
2566            Data.RefQ = f_refV->u; /* a good place, also used in MC (for similar purpose) */
2567    
2568            /* note: i==horizontal, j==vertical */
2569            for (j = 0; j < pParam->mb_height; j++) {
2570    
2571                    f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
2572    
2573                    for (i = 0; i < pParam->mb_width; i++) {
2574                            MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
2575                            const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
2576    
2577    /* special case, if collocated block is SKIPed in P-VOP: encoding is forward (0,0), cpb=0 without further ado */
2578                            if (b_reference->coding_type != S_VOP)
2579                                    if (b_mb->mode == MODE_NOT_CODED) {
2580                                            pMB->mode = MODE_NOT_CODED;
2581                                            continue;
2582                                    }
2583    
2584                            Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
2585                            Data.CurU = frame->image.u + (j * Data.iEdgedWidth/2 + i) * 8;
2586                            Data.CurV = frame->image.v + (j * Data.iEdgedWidth/2 + i) * 8;
2587    
2588    /* direct search comes first, because it (1) checks for SKIP-mode
2589            and (2) sets very good predictions for forward and backward search */
2590                            skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2591                                                                            b_ref, b_refH->y, b_refV->y, b_refHV->y,
2592                                                                            &frame->image,
2593                                                                            i, j,
2594                                                                            frame->motion_flags,
2595                                                                            TRB, TRD,
2596                                                                            pParam,
2597                                                                            pMB, b_mb,
2598                                                                            &best_sad,
2599                                                                            &Data);
2600    
2601                            if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
2602    
2603                            /* forward search */
2604                            SearchBF(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2605                                                    &frame->image, i, j,
2606                                                    frame->motion_flags,
2607                                                    frame->fcode, pParam,
2608                                                    pMB, &f_predMV, &best_sad,
2609                                                    MODE_FORWARD, &Data);
2610    
2611                            /* backward search */
2612                            SearchBF(b_ref, b_refH->y, b_refV->y, b_refHV->y,
2613                                                    &frame->image, i, j,
2614                                                    frame->motion_flags,
2615                                                    frame->bcode, pParam,
2616                                                    pMB, &b_predMV, &best_sad,
2617                                                    MODE_BACKWARD, &Data);
2618    
2619                            /* interpolate search comes last, because it uses data from forward and backward as prediction */
2620                            SearchInterpolate(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2621                                                    b_ref, b_refH->y, b_refV->y, b_refHV->y,
2622                                                    &frame->image,
2623                                                    i, j,
2624                                                    frame->fcode, frame->bcode,
2625                                                    frame->motion_flags,
2626                                                    pParam,
2627                                                    &f_predMV, &b_predMV,
2628                                                    pMB, &best_sad,
2629                                                    &Data);
2630    
2631                            /* final skip decision */
2632                            if ( (skip_sad < Data.iQuant * MAX_SAD00_FOR_SKIP * 2)
2633                                            && ((100*best_sad)/(skip_sad+1) > FINAL_SKIP_THRESH) )
2634                                    SkipDecisionB(&frame->image, f_ref, b_ref, pMB, i, j, &Data);
2635    
2636                            switch (pMB->mode) {
2637                                    case MODE_FORWARD:
2638                                            f_count++;
2639                                            f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2640                                            break;
2641                                    case MODE_BACKWARD:
2642                                            b_count++;
2643                                            b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2644                                            break;
2645                                    case MODE_INTERPOLATE:
2646                                            i_count++;
2647                                            f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2648                                            b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2649                                            break;
2650                                    case MODE_DIRECT:
2651                                    case MODE_DIRECT_NO4V:
2652                                            d_count++;
2653                                    default:
2654                                            break;
2655                          }                          }
                         CHECK_MV16_CANDIDATE(pmv[3].x, pmv[3].y);  
2656                  }                  }
2657          }          }
   
 /* Terminate if MinSAD <= T_2  
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
   
         if ((iMinSAD <= thresh2)  
                 || (MVequal(*currMV, prevMB->mvs[0]) &&  
                         ((int32_t) iMinSAD <= prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
2658          }          }
2659    
2660  /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/  static __inline void
2661    MEanalyzeMB (   const uint8_t * const pRef,
2662          backupMV = prevMB->mvs[0];      // collocated MV                                  const uint8_t * const pCur,
2663          backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x);     // acceleration X                                  const int x,
2664          backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y);     // acceleration Y                                  const int y,
2665                                    const MBParam * const pParam,
2666                                    MACROBLOCK * const pMBs,
2667                                    SearchData * const Data)
2668    {
2669    
2670          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y);          int i;
2671            VECTOR pmv[3];
2672            MACROBLOCK * const pMB = &pMBs[x + y * pParam->mb_width];
2673    
2674  // left neighbour          unsigned int simplicity = 0;
         if (x != 0)  
                 CHECK_MV16_CANDIDATE((prevMB - 1)->mvs[0].x, (prevMB - 1)->mvs[0].y);  
2675    
2676  // top neighbour          for (i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;
         if (y != 0)  
                 CHECK_MV16_CANDIDATE((prevMB - iWcount)->mvs[0].x,  
                                                          (prevMB - iWcount)->mvs[0].y);  
2677    
2678  // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
2679                            pParam->width, pParam->height, Data->iFcode - Data->qpel - 1, 0, 0);
2680    
2681          if ((uint32_t) x != iWcount - 1)          Data->Cur = pCur + (x + y * pParam->edged_width) * 16;
2682                  CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);          Data->RefP[0] = pRef + (x + y * pParam->edged_width) * 16;
2683    
2684  // bottom neighbour, dito          pmv[0].x = pMB->mvs[0].x;
2685          if ((uint32_t) y != iHcount - 1)          pmv[0].y = pMB->mvs[0].y;
                 CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,  
                                                          (prevMB + iWcount)->mvs[0].y);  
2686    
2687  /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */          CheckCandidate32I(pmv[0].x, pmv[0].y, Data, 0);
         if (iMinSAD <= thresh2) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
         }  
2688    
2689  /************ (if Diamond Search)  **************/          if (*Data->iMinSAD > 200) {
2690    
2691          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                  pmv[1].x = pmv[1].y = 0;
2692    
2693          if (MotionFlags & PMV_USESQUARES16)                  /* median is only used as prediction. it doesn't have to be real */
2694                  MainSearchPtr = Square16_MainSearch;                  if (x == 1 && y == 1) Data->predMV.x = Data->predMV.y = 0;
2695          else          else
2696           if (MotionFlags & PMV_ADVANCEDDIAMOND16)                          if (x == 1) /* left macroblock does not have any vector now */
2697                  MainSearchPtr = AdvDiamond16_MainSearch;                                  Data->predMV = (pMB - pParam->mb_width)->mvs[0]; /* top instead of median */
2698                            else if (y == 1) /* top macroblock doesn't have it's vector */
2699                                    Data->predMV = (pMB - 1)->mvs[0]; /* left instead of median */
2700                            else Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); /* else median */
2701    
2702                    pmv[2].x = Data->predMV.x;
2703                    pmv[2].y = Data->predMV.y;
2704    
2705                    if (!vector_repeats(pmv, 1))
2706                            CheckCandidate32I(pmv[1].x, pmv[1].y, Data, 1);
2707                    if (!vector_repeats(pmv, 2))
2708                            CheckCandidate32I(pmv[2].x, pmv[2].y, Data, 2);
2709    
2710                    if (*Data->iMinSAD > 500) { /* diamond only if needed */
2711                            unsigned int mask = make_mask(pmv, 3, *Data->dir);
2712                            DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, mask, CheckCandidate32I);
2713                    } else simplicity++;
2714    
2715                    if (*Data->iMinSAD > 500) /* refinement from 2-pixel to 1-pixel */
2716                            SubpelRefine(Data, CheckCandidate32I);
2717                    else simplicity++;
2718            } else simplicity++;
2719    
2720            for (i = 0; i < 4; i++) {
2721                    MACROBLOCK * MB = &pMBs[x + (i&1) + (y+(i>>1)) * pParam->mb_width];
2722                    MB->mvs[0] = MB->mvs[1] = MB->mvs[2] = MB->mvs[3] = Data->currentMV[i];
2723                    MB->mode = MODE_INTER;
2724                    /* if we skipped some search steps, we have to assume that SAD would be lower with them */
2725                    MB->sad16 = Data->iMinSAD[i+1] - (simplicity<<7);
2726            }
2727    }
2728    
2729    #define INTRA_THRESH    2200
2730    #define INTER_THRESH    40
2731    #define INTRA_THRESH2   95
2732    
2733    int
2734    MEanalysis(     const IMAGE * const pRef,
2735                            const FRAMEINFO * const Current,
2736                            const MBParam * const pParam,
2737                            const int maxIntra, //maximum number if non-I frames
2738                            const int intraCount, //number of non-I frames after last I frame; 0 if we force P/B frame
2739                            const int bCount, // number of B frames in a row
2740                            const int b_thresh)
2741    {
2742            uint32_t x, y, intra = 0;
2743            int sSAD = 0;
2744            MACROBLOCK * const pMBs = Current->mbs;
2745            const IMAGE * const pCurrent = &Current->image;
2746            int IntraThresh = INTRA_THRESH, InterThresh = INTER_THRESH + b_thresh;
2747            int blocks = 0;
2748            int complexity = 0;
2749    
2750            int32_t iMinSAD[5], temp[5];
2751            uint32_t dir;
2752            VECTOR currentMV[5];
2753            SearchData Data;
2754            Data.iEdgedWidth = pParam->edged_width;
2755            Data.currentMV = currentMV;
2756            Data.iMinSAD = iMinSAD;
2757            Data.iFcode = Current->fcode;
2758            Data.temp = temp;
2759            Data.dir = &dir;
2760            Data.qpel = (pParam->vol_flags & XVID_VOL_QUARTERPEL)? 1: 0;
2761            Data.qpel_precision = 0;
2762    
2763            if (intraCount != 0) {
2764                    if (intraCount < 10) // we're right after an I frame
2765                            IntraThresh += 15* (intraCount - 10) * (intraCount - 10);
2766          else          else
2767                  MainSearchPtr = Diamond16_MainSearch;                          if ( 5*(maxIntra - intraCount) < maxIntra) // we're close to maximum. 2 sec when max is 10 sec
2768                                    IntraThresh -= (IntraThresh * (maxIntra - 8*(maxIntra - intraCount)))/maxIntra;
2769            }
2770    
2771  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          InterThresh -= 20 * bCount;
2772            if (InterThresh < 10 + b_thresh) InterThresh = 10 + b_thresh;
2773    
2774          iSAD =          if (sadInit) (*sadInit) ();
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  
                                                   currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);  
2775    
2776          if (iSAD < iMinSAD) {          for (y = 1; y < pParam->mb_height-1; y += 2) {
2777                  *currMV = newMV;                  for (x = 1; x < pParam->mb_width-1; x += 2) {
2778                  iMinSAD = iSAD;                          int i;
2779          }                          blocks += 10;
2780    
2781                            if (bCount == 0) pMBs[x + y * pParam->mb_width].mvs[0] = zeroMV;
2782                            else { //extrapolation of the vector found for last frame
2783                                    pMBs[x + y * pParam->mb_width].mvs[0].x =
2784                                            (pMBs[x + y * pParam->mb_width].mvs[0].x * (bCount+1) ) / bCount;
2785                                    pMBs[x + y * pParam->mb_width].mvs[0].y =
2786                                            (pMBs[x + y * pParam->mb_width].mvs[0].y * (bCount+1) ) / bCount;
2787                            }
2788    
2789          if (MotionFlags & PMV_EXTSEARCH16) {                          MEanalyzeMB(pRef->y, pCurrent->y, x, y, pParam, pMBs, &Data);
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
2790    
2791                  if (!(MVequal(pmv[0], backupMV))) {                          for (i = 0; i < 4; i++) {
2792                          iSAD =                                  int dev;
2793                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                  MACROBLOCK *pMB = &pMBs[x+(i&1) + (y+(i>>1)) * pParam->mb_width];
2794                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,                                  dev = dev16(pCurrent->y + (x + (i&1) + (y + (i>>1)) * pParam->edged_width) * 16,
2795                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,                                                                  pParam->edged_width);
                                                                   2, iFcode, iQuant, 0);  
                 }  
2796    
2797                  if (iSAD < iMinSAD) {                                  complexity += MAX(dev, 300);
2798                          *currMV = newMV;                                  if (dev + IntraThresh < pMB->sad16) {
2799                          iMinSAD = iSAD;                                          pMB->mode = MODE_INTRA;
2800                                            if (++intra > ((pParam->mb_height-2)*(pParam->mb_width-2))/2) return I_VOP;
2801                  }                  }
2802    
2803                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                                  if (pMB->mvs[0].x == 0 && pMB->mvs[0].y == 0)
2804                          iSAD =                                          if (dev > 1000 && pMB->sad16 < 1000)
2805                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                                                  sSAD += 1000;
                                                                   iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);  
2806    
2807                          if (iSAD < iMinSAD) {                                  sSAD += (dev < 4000) ? pMB->sad16 : pMB->sad16/2; /* blocks with big contrast differences usually have large SAD - while they look very good in b-frames */
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
2808                          }                          }
2809                  }                  }
2810          }          }
2811            complexity >>= 7;
2812    
2813  /***************        Choose best MV found     **************/          sSAD /= complexity + 4*blocks;
2814    
2815    EPZS16_Terminate_with_Refine:          if (intraCount > 80 && sSAD > INTRA_THRESH2 ) return I_VOP;
2816          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step          if (sSAD > InterThresh ) return P_VOP;
2817                  iMinSAD =          emms();
2818                          Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,          return B_VOP;
                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
   
   EPZS16_Terminate_without_Refine:  
   
         *oldMB = *prevMB;  
   
         currPMV->x = currMV->x - center_x;  
         currPMV->y = currMV->y - center_y;  
         return iMinSAD;  
2819  }  }
2820    
2821    
2822  int32_t  /* functions which perform BITS-based search/bitcount */
2823  EPZSSearch8(const uint8_t * const pRef,  
2824                          const uint8_t * const pRefH,  static int
2825                          const uint8_t * const pRefV,  findRDinter(SearchData * const Data,
2826                          const uint8_t * const pRefHV,                          const MACROBLOCK * const pMBs, const int x, const int y,
                         const IMAGE * const pCur,  
                         const int x,  
                         const int y,  
                         const int start_x,  
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
                         const uint32_t MotionFlags,  
                         const uint32_t iQuant,  
                         const uint32_t iFcode,  
2827                          const MBParam * const pParam,                          const MBParam * const pParam,
2828                          const MACROBLOCK * const pMBs,                          const uint32_t MotionFlags)
                         const MACROBLOCK * const prevMBs,  
                         VECTOR * const currMV,  
                         VECTOR * const currPMV)  
2829  {  {
2830  /* Please not that EPZS might not be a good choice for 8x8-block motion search ! */          int i;
2831            int32_t bsad[5];
2832    
2833            if (Data->qpel) {
2834                    for(i = 0; i < 5; i++) {
2835                            Data->currentMV[i].x = Data->currentQMV[i].x/2;
2836                            Data->currentMV[i].y = Data->currentQMV[i].y/2;
2837                    }
2838                    Data->qpel_precision = 1;
2839                    CheckCandidateRD16(Data->currentQMV[0].x, Data->currentQMV[0].y, Data, 255);
2840    
2841          const uint32_t iWcount = pParam->mb_width;                  if (MotionFlags & (XVID_ME_HALFPELREFINE16_RD | XVID_ME_EXTSEARCH_RD)) { /* we have to prepare for halfpixel-precision search */
2842          const int32_t iWidth = pParam->width;                          for(i = 0; i < 5; i++) bsad[i] = Data->iMinSAD[i];
2843          const int32_t iHeight = pParam->height;                          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
2844          const int32_t iEdgedWidth = pParam->edged_width;                                                  pParam->width, pParam->height, Data->iFcode - Data->qpel, 1, Data->rrv);
2845                            Data->qpel_precision = 0;
2846                            if (Data->currentQMV->x & 1 || Data->currentQMV->y & 1)
2847                                    CheckCandidateRD16(Data->currentMV[0].x, Data->currentMV[0].y, Data, 255);
2848                    }
2849    
2850          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;          } else { /* not qpel */
2851    
2852          int32_t iDiamondSize = 1;                  CheckCandidateRD16(Data->currentMV[0].x, Data->currentMV[0].y, Data, 255);
2853            }
2854    
2855          int32_t min_dx;          if (MotionFlags&XVID_ME_EXTSEARCH_RD)
2856          int32_t max_dx;                  SquareSearch(Data->currentMV->x, Data->currentMV->y, Data, 255, CheckCandidateRD16);
         int32_t min_dy;  
         int32_t max_dy;  
2857    
2858          VECTOR newMV;          if (MotionFlags&XVID_ME_HALFPELREFINE16_RD)
2859          VECTOR backupMV;                  SubpelRefine(Data, CheckCandidateRD16);
2860    
2861          VECTOR pmv[4];          if (Data->qpel) {
2862          int32_t psad[8];                  if (MotionFlags&(XVID_ME_EXTSEARCH_RD | XVID_ME_HALFPELREFINE16_RD)) { /* there was halfpel-precision search */
2863                            for(i = 0; i < 5; i++) if (bsad[i] > Data->iMinSAD[i]) {
2864                                    Data->currentQMV[i].x = 2 * Data->currentMV[i].x; /* we have found a better match */
2865                                    Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
2866                            }
2867    
2868          const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);                          /* preparing for qpel-precision search */
2869                            Data->qpel_precision = 1;
2870                            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
2871                                            pParam->width, pParam->height, Data->iFcode, 2, 0);
2872                    }
2873                    if (MotionFlags&XVID_ME_QUARTERPELREFINE16_RD)
2874                            SubpelRefine(Data, CheckCandidateRD16);
2875            }
2876    
2877  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          if (MotionFlags&XVID_ME_CHECKPREDICTION_RD) { /* let's check vector equal to prediction */
2878          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;                  VECTOR * v = Data->qpel ? Data->currentQMV : Data->currentMV;
2879                    if (!(Data->predMV.x == v->x && Data->predMV.y == v->y))
2880                            CheckCandidateRD16(Data->predMV.x, Data->predMV.y, Data, 255);
2881            }
2882            return Data->iMinSAD[0];
2883    }
2884    
2885          int32_t bPredEq;  static int
2886          int32_t iMinSAD, iSAD = 9999;  findRDinter4v(const SearchData * const Data,
2887                                    MACROBLOCK * const pMB, const MACROBLOCK * const pMBs,
2888                                    const int x, const int y,
2889                                    const MBParam * const pParam, const uint32_t MotionFlags,
2890                                    const VECTOR * const backup)
2891    {
2892    
2893          MainSearch8FuncPtr MainSearchPtr;          int cbp = 0, bits = 0, t = 0, i;
2894            SearchData Data2, *Data8 = &Data2;
2895            int sumx = 0, sumy = 0;
2896            int16_t *in = Data->dctSpace, *coeff = Data->dctSpace + 64;
2897            uint8_t * ptr;
2898    
2899            memcpy(Data8, Data, sizeof(SearchData));
2900    
2901            for (i = 0; i < 4; i++) { /* for all luma blocks */
2902    
2903                    Data8->iMinSAD = Data->iMinSAD + i + 1;
2904                    Data8->currentMV = Data->currentMV + i + 1;
2905                    Data8->currentQMV = Data->currentQMV + i + 1;
2906                    Data8->Cur = Data->Cur + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2907                    Data8->RefP[0] = Data->RefP[0] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2908                    Data8->RefP[2] = Data->RefP[2] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2909                    Data8->RefP[1] = Data->RefP[1] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2910                    Data8->RefP[3] = Data->RefP[3] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2911                    *Data8->cbp = (Data->cbp[1] & (1<<(5-i))) ? 1:0; // copy corresponding cbp bit
2912    
2913                    if(Data->qpel) {
2914                            Data8->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, i);
2915                            if (i != 0)     t = d_mv_bits(  Data8->currentQMV->x, Data8->currentQMV->y,
2916                                                                                    Data8->predMV, Data8->iFcode, 0, 0);
2917                    } else {
2918                            Data8->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, i);
2919                            if (i != 0)     t = d_mv_bits(  Data8->currentMV->x, Data8->currentMV->y,
2920                                                                                    Data8->predMV, Data8->iFcode, 0, 0);
2921                    }
2922    
2923  /* Get maximum range */                  get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 3,
2924          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,                                          pParam->width, pParam->height, Data8->iFcode, Data8->qpel+1, 0);
                           iFcode);  
2925    
2926  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */                  *Data8->iMinSAD += BITS_MULT*t;
2927    
2928          if (!(MotionFlags & PMV_HALFPEL8)) {                  Data8->qpel_precision = Data8->qpel;
2929                  min_dx = EVEN(min_dx);                  /* checking the vector which has been found by SAD-based 8x8 search (if it's different than the one found so far) */
2930                  max_dx = EVEN(max_dx);                  {
2931                  min_dy = EVEN(min_dy);                          VECTOR *v = Data8->qpel ? Data8->currentQMV : Data8->currentMV;
2932                  max_dy = EVEN(max_dy);                          if (!MVequal (*v, backup[i+1]) )
2933                                    CheckCandidateRD8(backup[i+1].x, backup[i+1].y, Data8, 255);
2934          }          }
         /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
         //bPredEq = get_pmvdata(pMBs, x >> 1, y >> 1, iWcount, iSubBlock, pmv[0].x, pmv[0].y, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, x >> 1, y >> 1, iSubBlock, pmv, psad);  
2935    
2936                    if (Data8->qpel) {
2937                            if (MotionFlags&XVID_ME_HALFPELREFINE8_RD || (MotionFlags&XVID_ME_EXTSEARCH8 && MotionFlags&XVID_ME_EXTSEARCH_RD)) { /* halfpixel motion search follows */
2938                                    int32_t s = *Data8->iMinSAD;
2939                                    Data8->currentMV->x = Data8->currentQMV->x/2;
2940                                    Data8->currentMV->y = Data8->currentQMV->y/2;
2941                                    Data8->qpel_precision = 0;
2942                                    get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 3,
2943                                                            pParam->width, pParam->height, Data8->iFcode - 1, 1, 0);
2944    
2945  /* Step 4: Calculate SAD around the Median prediction.                                  if (Data8->currentQMV->x & 1 || Data8->currentQMV->y & 1)
2946          MinSAD=SAD                                          CheckCandidateRD8(Data8->currentMV->x, Data8->currentMV->y, Data8, 255);
         If Motion Vector equal to Previous frame motion vector  
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
 */  
2947    
2948  // Prepare for main loop                                  if (MotionFlags & XVID_ME_EXTSEARCH8 && MotionFlags & XVID_ME_EXTSEARCH_RD)
2949                                            SquareSearch(Data8->currentMV->x, Data8->currentMV->x, Data8, 255, CheckCandidateRD8);
2950    
2951                                    if (MotionFlags & XVID_ME_HALFPELREFINE8_RD)
2952                                            SubpelRefine(Data8, CheckCandidateRD8);
2953    
2954          if (!(MotionFlags & PMV_HALFPEL8)) {                                  if(s > *Data8->iMinSAD) { /* we have found a better match */
2955                  currMV->x = EVEN(currMV->x);                                          Data8->currentQMV->x = 2*Data8->currentMV->x;
2956                  currMV->y = EVEN(currMV->y);                                          Data8->currentQMV->y = 2*Data8->currentMV->y;
2957          }          }
2958    
2959          if (currMV->x > max_dx)                                  Data8->qpel_precision = 1;
2960                  currMV->x = max_dx;                                  get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 3,
2961          if (currMV->x < min_dx)                                                          pParam->width, pParam->height, Data8->iFcode, 2, 0);
                 currMV->x = min_dx;  
         if (currMV->y > max_dy)  
                 currMV->y = max_dy;  
         if (currMV->y < min_dy)  
                 currMV->y = min_dy;  
   
 /***************** This is predictor SET A: only median prediction ******************/  
2962    
2963                            }
2964                            if (MotionFlags & XVID_ME_QUARTERPELREFINE8_RD)
2965                                    SubpelRefine(Data8, CheckCandidateRD8);
2966    
2967          iMinSAD =                  } else { /* not qpel */
                 sad8(cur,  
                          get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  
                                                 iEdgedWidth), iEdgedWidth);  
         iMinSAD +=  
                 calc_delta_8(currMV->x - center_x, currMV->y - center_y,  
                                          (uint8_t) iFcode, iQuant);  
2968    
2969                            if (MotionFlags & XVID_ME_EXTSEARCH8 && MotionFlags & XVID_ME_EXTSEARCH_RD) /* extsearch */
2970                                    SquareSearch(Data8->currentMV->x, Data8->currentMV->x, Data8, 255, CheckCandidateRD8);
2971    
2972  // thresh1 is fixed to 256                          if (MotionFlags & XVID_ME_HALFPELREFINE8_RD)
2973          if (iMinSAD < 256 / 4) {                                  SubpelRefine(Data8, CheckCandidateRD8); /* halfpel refinement */
                 if (MotionFlags & PMV_QUICKSTOP8)  
                         goto EPZS8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
2974          }          }
2975    
2976  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/                  /* checking vector equal to predicion */
2977                    if (i != 0 && MotionFlags & XVID_ME_CHECKPREDICTION_RD) {
2978                            const VECTOR * v = Data->qpel ? Data8->currentQMV : Data8->currentMV;
2979                            if (!MVequal(*v, Data8->predMV))
2980                                    CheckCandidateRD8(Data8->predMV.x, Data8->predMV.y, Data8, 255);
2981                    }
2982    
2983                    bits += *Data8->iMinSAD;
2984                    if (bits >= Data->iMinSAD[0]) return bits; /* no chances for INTER4V */
2985    
2986  // MV=(0,0) is often a good choice                  /* MB structures for INTER4V mode; we have to set them here, we don't have predictor anywhere else */
2987          CHECK_MV8_ZERO;                  if(Data->qpel) {
2988                            pMB->pmvs[i].x = Data8->currentQMV->x - Data8->predMV.x;
2989                            pMB->pmvs[i].y = Data8->currentQMV->y - Data8->predMV.y;
2990                            pMB->qmvs[i] = *Data8->currentQMV;
2991                            sumx += Data8->currentQMV->x/2;
2992                            sumy += Data8->currentQMV->y/2;
2993                    } else {
2994                            pMB->pmvs[i].x = Data8->currentMV->x - Data8->predMV.x;
2995                            pMB->pmvs[i].y = Data8->currentMV->y - Data8->predMV.y;
2996                            sumx += Data8->currentMV->x;
2997                            sumy += Data8->currentMV->y;
2998                    }
2999                    pMB->mvs[i] = *Data8->currentMV;
3000                    pMB->sad8[i] = 4 * *Data8->iMinSAD;
3001                    if (Data8->cbp[0]) cbp |= 1 << (5 - i);
3002    
3003  // previous frame MV          } /* end - for all luma blocks */
         CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x, prevMB->mvs[iSubBlock].y);  
3004    
3005  // left neighbour, if allowed          bits += BITS_MULT*xvid_cbpy_tab[15-(cbp>>2)].len;
         if (psad[1] != MV_MAX_ERROR) {  
                 if (!(MotionFlags & PMV_HALFPEL8)) {  
                         pmv[1].x = EVEN(pmv[1].x);  
                         pmv[1].y = EVEN(pmv[1].y);  
                 }  
                 CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);  
         }  
 // top neighbour, if allowed  
         if (psad[2] != MV_MAX_ERROR) {  
                 if (!(MotionFlags & PMV_HALFPEL8)) {  
                         pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
                 }  
                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
3006    
3007  // top right neighbour, if allowed          /* let's check chroma */
3008                  if (psad[3] != MV_MAX_ERROR) {          sumx = (sumx >> 3) + roundtab_76[sumx & 0xf];
3009                          if (!(MotionFlags & PMV_HALFPEL8)) {          sumy = (sumy >> 3) + roundtab_76[sumy & 0xf];
                                 pmv[3].x = EVEN(pmv[3].x);  
                                 pmv[3].y = EVEN(pmv[3].y);  
                         }  
                         CHECK_MV8_CANDIDATE(pmv[3].x, pmv[3].y);  
                 }  
         }  
3010    
3011  /*  // this bias is zero anyway, at the moment!          /* chroma U */
3012            ptr = interpolate8x8_switch2(Data->RefQ + 64, Data->RefP[4], 0, 0, sumx, sumy, Data->iEdgedWidth/2, Data->rounding);
3013            transfer_8to16subro(in, Data->CurU, ptr, Data->iEdgedWidth/2);
3014            bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 4);
3015    
3016          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)          if (bits >= *Data->iMinSAD) return bits;
                 iMinSAD -= MV8_00_BIAS;  
3017    
3018  */          /* chroma V */
3019            ptr = interpolate8x8_switch2(Data->RefQ + 64, Data->RefP[5], 0, 0, sumx, sumy, Data->iEdgedWidth/2, Data->rounding);
3020            transfer_8to16subro(in, Data->CurV, ptr, Data->iEdgedWidth/2);
3021            bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 5);
3022    
3023  /* Terminate if MinSAD <= T_2          bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTER4V & 7) | ((cbp & 3) << 3)].len;
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
3024    
3025          if (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */          *Data->cbp = cbp;
3026                  if (MotionFlags & PMV_QUICKSTOP8)          return bits;
                         goto EPZS8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
3027          }          }
3028    
3029  /************ (Diamond Search)  **************/  static int
3030    findRDintra(const SearchData * const Data)
3031          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  {
3032            int bits = BITS_MULT*1; /* this one is ac/dc prediction flag bit */
3033            int cbp = 0, i, dc = 0;
3034            int16_t *in = Data->dctSpace, * coeff = Data->dctSpace + 64;
3035    
3036          if (!(MotionFlags & PMV_HALFPELDIAMOND8))          for(i = 0; i < 4; i++) {
3037                  iDiamondSize *= 2;                  int s = 8*((i&1) + (i>>1)*Data->iEdgedWidth);
3038                    transfer_8to16copy(in, Data->Cur + s, Data->iEdgedWidth);
3039                    bits += Block_CalcBitsIntra(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, i, &dc);
3040    
3041  /* default: use best prediction as starting point for one call of EPZS_MainSearch */                  if (bits >= Data->iMinSAD[0]) return bits;
3042            }
3043    
3044  // there is no EPZS^2 for inter4v at the moment          bits += BITS_MULT*xvid_cbpy_tab[cbp>>2].len;
3045    
3046    if (MotionFlags & PMV_USESQUARES8)          /*chroma U */
3047        MainSearchPtr = Square8_MainSearch;          transfer_8to16copy(in, Data->CurU, Data->iEdgedWidth/2);
3048    else          bits += Block_CalcBitsIntra(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 4, &dc);
3049    
3050          if (MotionFlags & PMV_ADVANCEDDIAMOND8)          if (bits >= Data->iMinSAD[0]) return bits;
                 MainSearchPtr = AdvDiamond8_MainSearch;  
         else  
                 MainSearchPtr = Diamond8_MainSearch;  
3051    
3052          iSAD =          /* chroma V */
3053                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,          transfer_8to16copy(in, Data->CurV, Data->iEdgedWidth/2);
3054                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,          bits += Block_CalcBitsIntra(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 5, &dc);
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, 0);  
3055    
3056            bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTRA & 7) | ((cbp & 3) << 3)].len;
3057    
3058          if (iSAD < iMinSAD) {          return bits;
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
3059          }          }
3060    
3061          if (MotionFlags & PMV_EXTSEARCH8) {  static int
3062  /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  findRDgmc(const SearchData * const Data, const IMAGE * const vGMC, const int x, const int y)
3063    {
3064                  if (!(MVequal(pmv[0], backupMV))) {          int bits = BITS_MULT*1; /* this one is mcsel */
3065                          iSAD =          int cbp = 0, i;
3066                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,          int16_t *in = Data->dctSpace, * coeff = Data->dctSpace + 64;
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, 0);  
3067    
3068                          if (iSAD < iMinSAD) {          for(i = 0; i < 4; i++) {
3069                                  *currMV = newMV;                  int s = 8*((i&1) + (i>>1)*Data->iEdgedWidth);
3070                                  iMinSAD = iSAD;                  transfer_8to16subro(in, Data->Cur + s, vGMC->y + s + 16*(x+y*Data->iEdgedWidth), Data->iEdgedWidth);
3071                          }                  bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, i);
3072                    if (bits >= Data->iMinSAD[0]) return bits;
3073                  }                  }
3074    
3075                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          bits += BITS_MULT*xvid_cbpy_tab[15-(cbp>>2)].len;
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, 0);  
3076    
3077                          if (iSAD < iMinSAD) {          /*chroma U */
3078                                  *currMV = newMV;          transfer_8to16subro(in, Data->CurU, vGMC->u + 8*(x+y*(Data->iEdgedWidth/2)), Data->iEdgedWidth/2);
3079                                  iMinSAD = iSAD;          bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 4);
3080                          }  
3081                  }          if (bits >= Data->iMinSAD[0]) return bits;
         }  
3082    
3083  /***************        Choose best MV found     **************/          /* chroma V */
3084            transfer_8to16subro(in, Data->CurV , vGMC->v + 8*(x+y*(Data->iEdgedWidth/2)), Data->iEdgedWidth/2);
3085            bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 5);
3086    
3087    EPZS8_Terminate_with_Refine:          bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTER & 7) | ((cbp & 3) << 3)].len;
         if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step  
                 iMinSAD =  
                         Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                         iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                         iFcode, iQuant, iEdgedWidth);  
3088    
3089    EPZS8_Terminate_without_Refine:          *Data->cbp = cbp;
3090    
3091          currPMV->x = currMV->x - center_x;          return bits;
         currPMV->y = currMV->y - center_y;  
         return iMinSAD;  
3092  }  }
3093    
3094    
3095    
3096  int32_t  
3097  PMVfastIntSearch16(const uint8_t * const pRef,  static __inline void
3098    GMEanalyzeMB (  const uint8_t * const pCur,
3099                                    const uint8_t * const pRef,
3100                                  const uint8_t * const pRefH,                                  const uint8_t * const pRefH,
3101                                  const uint8_t * const pRefV,                                  const uint8_t * const pRefV,
3102                                  const uint8_t * const pRefHV,                                  const uint8_t * const pRefHV,
                                 const IMAGE * const pCur,  
3103                                  const int x,                                  const int x,
3104                                  const int y,                                  const int y,
                                 const int start_x,              /* start should be most likely vector */  
                                 const int start_y,  
                                 const int center_x,             /* center is from where length of MVs is measured */  
                                 const int center_y,  
                                 const uint32_t MotionFlags,  
                                 const uint32_t iQuant,  
                                 const uint32_t iFcode,  
3105                                  const MBParam * const pParam,                                  const MBParam * const pParam,
3106                                  const MACROBLOCK * const pMBs,                                  MACROBLOCK * const pMBs,
3107                                  const MACROBLOCK * const prevMBs,                                  SearchData * const Data)
                                 VECTOR * const currMV,  
                                 VECTOR * const currPMV)  
3108  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
3109    
3110          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          int i=0;
3111          const VECTOR zeroMV = { 0, 0 };          MACROBLOCK * const pMB = &pMBs[x + y * pParam->mb_width];
3112    
3113          int32_t iDiamondSize;          Data->iMinSAD[0] = MV_MAX_ERROR;
3114    
3115          int32_t min_dx;          Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
3116    
3117          int32_t iFound;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
3118                                    pParam->width, pParam->height, 16, 1, 0);
3119    
3120          VECTOR newMV;          Data->Cur = pCur + 16*(x + y * pParam->edged_width);
3121          VECTOR backupMV;          Data->RefP[0] = pRef + 16*(x + y * pParam->edged_width);
3122            Data->RefP[1] = pRefV + 16*(x + y * pParam->edged_width);
3123            Data->RefP[2] = pRefH + 16*(x + y * pParam->edged_width);
3124            Data->RefP[3] = pRefHV + 16*(x + y * pParam->edged_width);
3125    
3126          VECTOR pmv[4];          Data->currentMV[0].x = Data->currentMV[0].y = 0;
3127          int32_t psad[4];          CheckCandidate16I(0, 0, Data, 255);
3128    
3129          MainSearch16FuncPtr MainSearchPtr;          if ( (Data->predMV.x !=0) || (Data->predMV.y != 0) )
3130                    CheckCandidate16I(Data->predMV.x, Data->predMV.y, Data, 255);
3131    
3132          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;          DiamondSearch(Data->currentMV[0].x, Data->currentMV[0].y, Data, 255, CheckCandidate16I);
         MACROBLOCK *const pMB = pMBs + x + y * iWcount;  
3133    
3134          int32_t threshA, threshB;          SubpelRefine(Data, CheckCandidate16I);
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD;  
3135    
3136    
3137  /* Get maximum range */          /* for QPel halfpel positions are worse than in halfpel mode :( */
3138          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  /*      if (Data->qpel) {
3139                            iFcode);                  Data->currentQMV->x = 2*Data->currentMV->x;
3140                    Data->currentQMV->y = 2*Data->currentMV->y;
3141                    Data->qpel_precision = 1;
3142                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
3143                                            pParam->width, pParam->height, iFcode, 2, 0);
3144                    SubpelRefine(Data);
3145            }
3146    */
3147    
3148  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
3149            pMB->sad16 = Data->iMinSAD[0];
3150            pMB->mode = MODE_INTER;
3151            pMB->sad16 += 10*d_mv_bits(pMB->mvs[0].x, pMB->mvs[0].y, Data->predMV, Data->iFcode, 0, 0);
3152            return;
3153    }
3154    
3155          if ((x == 0) && (y == 0)) {  void
3156                  threshA = 512;  GMEanalysis(const MBParam * const pParam,
3157                  threshB = 1024;                          const FRAMEINFO * const current,
3158                            const FRAMEINFO * const reference,
3159                            const IMAGE * const pRefH,
3160                            const IMAGE * const pRefV,
3161                            const IMAGE * const pRefHV)
3162    {
3163            uint32_t x, y;
3164            MACROBLOCK * const pMBs = current->mbs;
3165            const IMAGE * const pCurrent = &current->image;
3166            const IMAGE * const pReference = &reference->image;
3167    
3168                  bPredEq = 0;          int32_t iMinSAD[5], temp[5];
3169                  psad[0] = psad[1] = psad[2] = psad[3] = 0;          VECTOR currentMV[5];
3170                  *currMV = pmv[0] = pmv[1] = pmv[2] = pmv[3] = zeroMV;          uint32_t dir;
3171            SearchData Data;
3172            memset(&Data, 0, sizeof(SearchData));
3173    
3174          } else {          Data.iEdgedWidth = pParam->edged_width;
3175                  threshA = psad[0];          Data.rounding = pParam->m_rounding_type;
                 threshB = threshA + 256;  
                 if (threshA < 512)  
                         threshA = 512;  
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
   
                 bPredEq = get_ipmvdata(pMBs, iWcount, 0, x, y, 0, pmv, psad);  
                 *currMV = pmv[0];                       /* current best := prediction */  
         }  
   
         iFound = 0;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
3176    
3177          if (currMV->x > max_dx) {          Data.currentMV = &currentMV[0];
3178                  currMV->x = EVEN(max_dx);          Data.iMinSAD = &iMinSAD[0];
3179          }          Data.iFcode = current->fcode;
3180          if (currMV->x < min_dx) {          Data.temp = temp;
3181                  currMV->x = EVEN(min_dx);          Data.dir = &dir;
         }  
         if (currMV->y > max_dy) {  
                 currMV->y = EVEN(max_dy);  
         }  
         if (currMV->y < min_dy) {  
                 currMV->y = EVEN(min_dy);  
         }  
3182    
3183          iMinSAD =          if (sadInit) (*sadInit) ();
                 sad16(cur,  
                           get_iref_mv(pRef, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
3184    
3185          if ((iMinSAD < 256) ||          for (y = 0; y < pParam->mb_height; y ++) {
3186                  ((MVequal(*currMV, prevMB->i_mvs[0])) &&                  for (x = 0; x < pParam->mb_width; x ++) {
3187                   ((int32_t) iMinSAD < prevMB->i_sad16))) {                          GMEanalyzeMB(pCurrent->y, pReference->y, pRefH->y, pRefV->y, pRefHV->y, x, y, pParam, pMBs, &Data);
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
                 {  
                         if (!MVzero(*currMV)) {  
                                 iMinSAD += MV16_00_BIAS;  
                                 CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures  
                                 iMinSAD -= MV16_00_BIAS;  
3188                          }                          }
3189                  }                  }
3190            return;
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfastInt16_Terminate_with_Refine;  
3191          }          }
3192    
3193    
3194  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  WARPPOINTS
3195     vector of the median.  GlobalMotionEst(MACROBLOCK * const pMBs,
3196     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2                                  const MBParam * const pParam,
3197  */                                  const FRAMEINFO * const current,
3198                                    const FRAMEINFO * const reference,
3199          if ((bPredEq) && (MVequal(pmv[0], prevMB->i_mvs[0])))                                  const IMAGE * const pRefH,
3200                  iFound = 2;                                  const IMAGE * const pRefV,
3201                                    const IMAGE * const pRefHV)
3202    {
3203    
3204  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          const int deltax=8;             // upper bound for difference between a MV and it's neighbour MVs
3205     Otherwise select large Diamond Search.          const int deltay=8;
3206  */          const unsigned int gradx=512;           // lower bound for gradient in MB (ignore "flat" blocks)
3207            const unsigned int grady=512;
3208    
3209          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))          double sol[4] = { 0., 0., 0., 0. };
                 iDiamondSize = 2;               // halfpel units!  
         else  
                 iDiamondSize = 4;               // halfpel units!  
3210    
3211  /*          WARPPOINTS gmc;
    Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  
    Also calculate (0,0) but do not subtract offset.  
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset.  
 */  
3212    
3213  // (0,0) is often a good choice          uint32_t mx, my;
3214    
3215          if (!MVzero(pmv[0]))          int MBh = pParam->mb_height;
3216                  CHECK_MV16_ZERO;          int MBw = pParam->mb_width;
3217            const int minblocks = 9; //MBh*MBw/32+3;                /* just some reasonable number 3% + 3 */
3218            const int maxblocks = MBh*MBw/4;                /* just some reasonable number 3% + 3 */
3219    
3220  // previous frame MV is always possible          int num=0;
3221            int oldnum;
3222    
3223          if (!MVzero(prevMB->i_mvs[0]))          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;
                 if (!MVequal(prevMB->i_mvs[0], pmv[0]))  
                         CHECK_MV16_CANDIDATE(prevMB->i_mvs[0].x, prevMB->i_mvs[0].y);  
   
 // left neighbour, if allowed  
   
         if (!MVzero(pmv[1]))  
                 if (!MVequal(pmv[1], prevMB->i_mvs[0]))  
                         if (!MVequal(pmv[1], pmv[0]))  
                                 CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
   
 // top neighbour, if allowed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], prevMB->i_mvs[0]))  
                         if (!MVequal(pmv[2], pmv[0]))  
                                 if (!MVequal(pmv[2], pmv[1]))  
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed  
                                         if (!MVzero(pmv[3]))  
                                                 if (!MVequal(pmv[3], prevMB->i_mvs[0]))  
                                                         if (!MVequal(pmv[3], pmv[0]))  
                                                                 if (!MVequal(pmv[3], pmv[1]))  
                                                                         if (!MVequal(pmv[3], pmv[2]))  
                                                                                 CHECK_MV16_CANDIDATE(pmv[3].x,  
                                                                                                                          pmv[3].y);  
   
         if ((MVzero(*currMV)) &&  
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV16_00_BIAS;  
3224    
3225            GMEanalysis(pParam,current, reference, pRefH, pRefV, pRefHV);
3226    
3227  /* Step 6: If MinSAD <= thresa goto Step 10.          /* block based ME isn't done, yet, so do a quick presearch */
    If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
 */  
3228    
3229          if ((iMinSAD <= threshA) ||  // filter mask of all blocks
                 (MVequal(*currMV, prevMB->i_mvs[0]) &&  
                  ((int32_t) iMinSAD < prevMB->i_sad16))) {  
3230    
3231                  if (MotionFlags & PMV_EARLYSTOP16)          for (my = 0; my < (uint32_t)MBh; my++)
3232                          goto PMVfastInt16_Terminate_with_Refine;          for (mx = 0; mx < (uint32_t)MBw; mx++)
3233            {
3234                    const int mbnum = mx + my * MBw;
3235                            pMBs[mbnum].mcsel = 0;
3236          }          }
3237    
3238    
3239  /************ (Diamond Search)  **************/          for (my = 1; my < (uint32_t)MBh-1; my++) /* ignore boundary blocks */
3240  /*          for (mx = 1; mx < (uint32_t)MBw-1; mx++) /* theirs MVs are often wrong */
3241     Step 7: Perform Diamond search, with either the small or large diamond.          {
3242     If Found=2 only examine one Diamond pattern, and afterwards goto step 10                  const int mbnum = mx + my * MBw;
3243     Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.                  MACROBLOCK *const pMB = &pMBs[mbnum];
3244     If center then goto step 10.                  const VECTOR mv = pMB->mvs[0];
    Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
    Refine by using small diamond and goto step 10.  
 */  
3245    
3246          if (MotionFlags & PMV_USESQUARES16)                  /* don't use object boundaries */
3247                  MainSearchPtr = Square16_MainSearch;                  if   ( (abs(mv.x -   (pMB-1)->mvs[0].x) < deltax)
3248          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)                          && (abs(mv.y -   (pMB-1)->mvs[0].y) < deltay)
3249                  MainSearchPtr = AdvDiamond16_MainSearch;                          && (abs(mv.x -   (pMB+1)->mvs[0].x) < deltax)
3250          else                          && (abs(mv.y -   (pMB+1)->mvs[0].y) < deltay)
3251                  MainSearchPtr = Diamond16_MainSearch;                          && (abs(mv.x - (pMB-MBw)->mvs[0].x) < deltax)
3252                            && (abs(mv.y - (pMB-MBw)->mvs[0].y) < deltay)
3253                            && (abs(mv.x - (pMB+MBw)->mvs[0].x) < deltax)
3254                            && (abs(mv.y - (pMB+MBw)->mvs[0].y) < deltay) )
3255                    {       const int iEdgedWidth = pParam->edged_width;
3256                            const uint8_t *const pCur = current->image.y + 16*(my*iEdgedWidth + mx);
3257                            if ( (sad16 ( pCur, pCur+1 , iEdgedWidth, 65536) >= gradx )
3258                             &&  (sad16 ( pCur, pCur+iEdgedWidth, iEdgedWidth, 65536) >= grady ) )
3259                             {      pMB->mcsel = 1;
3260                                    num++;
3261                             }
3262    
3263          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                  /* only use "structured" blocks */
3264                    }
3265            }
3266            emms();
3267    
3268            /*      further filtering would be possible, but during iteration, remaining
3269                    outliers usually are removed, too */
3270    
3271  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          if (num>= minblocks)
3272          iSAD =          do {            /* until convergence */
3273                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,                  double DtimesF[4];
3274                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,                  double a,b,c,n,invdenom;
3275                                                    min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,                  double meanx,meany;
                                                   iQuant, iFound);  
3276    
3277          if (iSAD < iMinSAD) {                  a = b = c = n = 0;
3278                  *currMV = newMV;                  DtimesF[0] = DtimesF[1] = DtimesF[2] = DtimesF[3] = 0.;
3279                  iMinSAD = iSAD;                  for (my = 1; my < (uint32_t)MBh-1; my++)
3280          }                  for (mx = 1; mx < (uint32_t)MBw-1; mx++)
3281                    {
3282                            const int mbnum = mx + my * MBw;
3283                            const VECTOR mv = pMBs[mbnum].mvs[0];
3284    
3285          if (MotionFlags & PMV_EXTSEARCH16) {                          if (!pMBs[mbnum].mcsel)
3286  /* extended: search (up to) two more times: orignal prediction and (0,0) */                                  continue;
3287    
3288                  if (!(MVequal(pmv[0], backupMV))) {                          n++;
3289                          iSAD =                          a += 16*mx+8;
3290                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                          b += 16*my+8;
3291                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,                          c += (16*mx+8)*(16*mx+8)+(16*my+8)*(16*my+8);
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
3292    
3293                          if (iSAD < iMinSAD) {                          DtimesF[0] += (double)mv.x;
3294                                  *currMV = newMV;                          DtimesF[1] += (double)mv.x*(16*mx+8) + (double)mv.y*(16*my+8);
3295                                  iMinSAD = iSAD;                          DtimesF[2] += (double)mv.x*(16*my+8) - (double)mv.y*(16*mx+8);
3296                          }                          DtimesF[3] += (double)mv.y;
3297                  }                  }
3298    
3299                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          invdenom = a*a+b*b-c*n;
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
                 }  
         }  
3300    
3301  /*  /* Solve the system:    sol = (D'*E*D)^{-1} D'*E*F   */
3302     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  /* D'*E*F has been calculated in the same loop as matrix */
 */  
3303    
3304  PMVfastInt16_Terminate_with_Refine:          sol[0] = -c*DtimesF[0] + a*DtimesF[1] + b*DtimesF[2];
3305            sol[1] =  a*DtimesF[0] - n*DtimesF[1]                           + b*DtimesF[3];
3306            sol[2] =  b*DtimesF[0]                          - n*DtimesF[2] - a*DtimesF[3];
3307            sol[3] =                                 b*DtimesF[1] - a*DtimesF[2] - c*DtimesF[3];
3308    
3309          pMB->i_mvs[0] = pMB->i_mvs[1] = pMB->i_mvs[2] = pMB->i_mvs[3] = pMB->i_mv16 = *currMV;          sol[0] /= invdenom;
3310          pMB->i_sad8[0] = pMB->i_sad8[1] = pMB->i_sad8[2] = pMB->i_sad8[3] = pMB->i_sad16 = iMinSAD;          sol[1] /= invdenom;
3311            sol[2] /= invdenom;
3312            sol[3] /= invdenom;
3313    
3314          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step          meanx = meany = 0.;
3315                  iMinSAD =          oldnum = 0;
3316                          Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,          for (my = 1; my < (uint32_t)MBh-1; my++)
3317                                                           iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,                  for (mx = 1; mx < (uint32_t)MBw-1; mx++)
3318                                                           iFcode, iQuant, iEdgedWidth);                  {
3319                            const int mbnum = mx + my * MBw;
3320                            const VECTOR mv = pMBs[mbnum].mvs[0];
3321    
3322          pmv[0] = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          // get _REAL_ prediction (halfpel possible)                          if (!pMBs[mbnum].mcsel)
3323                                    continue;
3324    
3325  PMVfastInt16_Terminate_without_Refine:                          oldnum++;
3326          currPMV->x = currMV->x - center_x;                          meanx += fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - (double)mv.x );
3327          currPMV->y = currMV->y - center_y;                          meany += fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - (double)mv.y );
         return iMinSAD;  
3328  }  }
3329    
3330            if (4*meanx > oldnum)   /* better fit than 0.25 (=1/4pel) is useless */
3331                    meanx /= oldnum;
3332            else
3333                    meanx = 0.25;
3334    
3335            if (4*meany > oldnum)
3336                    meany /= oldnum;
3337            else
3338                    meany = 0.25;
3339    
3340  /* ***********************************************************          num = 0;
3341          bvop motion estimation          for (my = 0; my < (uint32_t)MBh; my++)
3342  ***************************************************************/                  for (mx = 0; mx < (uint32_t)MBw; mx++)
   
 void  
 MotionEstimationBVOP(MBParam * const pParam,  
                                          FRAMEINFO * const frame,  
                                          const int32_t time_bp,  
                                          const int32_t time_pp,  
                                          // forward (past) reference  
                                          const MACROBLOCK * const f_mbs,  
                                          const IMAGE * const f_ref,  
                                          const IMAGE * const f_refH,  
                                          const IMAGE * const f_refV,  
                                          const IMAGE * const f_refHV,  
                                          // backward (future) reference  
                                          const MACROBLOCK * const b_mbs,  
                                          const IMAGE * const b_ref,  
                                          const IMAGE * const b_refH,  
                                          const IMAGE * const b_refV,  
                                          const IMAGE * const b_refHV)  
3343  {  {
3344          const int mb_width = pParam->mb_width;                          const int mbnum = mx + my * MBw;
3345          const int mb_height = pParam->mb_height;                          const VECTOR mv = pMBs[mbnum].mvs[0];
         const int edged_width = pParam->edged_width;  
   
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
3346    
3347          int i, j, k;                          if (!pMBs[mbnum].mcsel)
3348                                    continue;
         static const VECTOR zeroMV={0,0};  
3349    
3350          int f_sad16;    /* forward (as usual) search */                          if  ( ( fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - (double)mv.x ) > meanx )
3351          int b_sad16;    /* backward (only in b-frames) search */                                  || ( fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - (double)mv.y ) > meany ) )
3352          int i_sad16;    /* interpolated (both direction, b-frames only) */                                  pMBs[mbnum].mcsel=0;
3353          int d_sad16;    /* direct mode (assume almost linear motion) */                          else
3354                                    num++;
3355                    }
3356    
3357          int best_sad;          } while ( (oldnum != num) && (num>= minblocks) );
3358    
3359          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/          if (num < minblocks)
3360          VECTOR f_interpolMV, b_interpolMV;          {
3361          VECTOR pmv_dontcare;                  const int iEdgedWidth = pParam->edged_width;
3362                    num = 0;
3363    
3364          int min_dx, max_dx, min_dy, max_dy;  /*              fprintf(stderr,"Warning! Unreliable GME (%d/%d blocks), falling back to translation.\n",num,MBh*MBw);
3365          int f_min_dx, f_max_dx, f_min_dy, f_max_dy;  */
3366          int b_min_dx, b_max_dx, b_min_dy, b_max_dy;                  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;
3367    
3368          int f_count=0;                  if (!(current->motion_flags & XVID_ME_GME_REFINE))
3369          int b_count=0;                          return gmc;
         int i_count=0;  
         int d_count=0;  
3370    
3371          const int64_t TRB = (int32_t)time_pp - (int32_t)time_bp;                  for (my = 1; my < (uint32_t)MBh-1; my++) /* ignore boundary blocks */
3372      const int64_t TRD = (int32_t)time_pp;                  for (mx = 1; mx < (uint32_t)MBw-1; mx++) /* theirs MVs are often wrong */
3373                    {
3374                            const int mbnum = mx + my * MBw;
3375                            MACROBLOCK *const pMB = &pMBs[mbnum];
3376                            const uint8_t *const pCur = current->image.y + 16*(my*iEdgedWidth + mx);
3377                            if ( (sad16 ( pCur, pCur+1 , iEdgedWidth, 65536) >= gradx )
3378                             &&  (sad16 ( pCur, pCur+iEdgedWidth, iEdgedWidth, 65536) >= grady ) )
3379                             {      pMB->mcsel = 1;
3380                                    gmc.duv[0].x += pMB->mvs[0].x;
3381                                    gmc.duv[0].y += pMB->mvs[0].y;
3382                                    num++;
3383                             }
3384                    }
3385    
3386          // fprintf(stderr,"TRB = %lld  TRD = %lld  time_bp =%d time_pp =%d\n\n",TRB,TRD,time_bp,time_pp);                  if (gmc.duv[0].x)
3387          // note: i==horizontal, j==vertical                          gmc.duv[0].x /= num;
3388          for (j = 0; j < mb_height; j++) {                  if (gmc.duv[0].y)
3389                            gmc.duv[0].y /= num;
3390            } else {
3391    
3392                  f_predMV = zeroMV;      /* prediction is reset at left boundary */                  gmc.duv[0].x=(int)(sol[0]+0.5);
3393                  b_predMV = zeroMV;                  gmc.duv[0].y=(int)(sol[3]+0.5);
3394    
3395                  for (i = 0; i < mb_width; i++) {                  gmc.duv[1].x=(int)(sol[1]*pParam->width+0.5);
3396                          MACROBLOCK *mb = &frame->mbs[i + j * mb_width];                  gmc.duv[1].y=(int)(-sol[2]*pParam->width+0.5);
                         const MACROBLOCK *f_mb = &f_mbs[i + j * mb_width];  
                         const MACROBLOCK *b_mb = &b_mbs[i + j * mb_width];  
3397    
3398                          mb->deltamv=zeroMV;                  gmc.duv[2].x=-gmc.duv[1].y;             /* two warp points only */
3399                    gmc.duv[2].y=gmc.duv[1].x;
3400            }
3401            if (num>maxblocks)
3402            {       for (my = 1; my < (uint32_t)MBh-1; my++)
3403                    for (mx = 1; mx < (uint32_t)MBw-1; mx++)
3404                    {
3405                            const int mbnum = mx + my * MBw;
3406                            if (pMBs[mbnum-1].mcsel)
3407                                    pMBs[mbnum].mcsel=0;
3408                            else
3409                                    if (pMBs[mbnum-MBw].mcsel)
3410                                            pMBs[mbnum].mcsel=0;
3411                    }
3412            }
3413            return gmc;
3414    }
3415    
3416  /* special case, if collocated block is SKIPed: encoding is forward (0,0), cpb=0 without further ado */  int
3417    GlobalMotionEstRefine(
3418                                    WARPPOINTS *const startwp,
3419                                    MACROBLOCK * const pMBs,
3420                                    const MBParam * const pParam,
3421                                    const FRAMEINFO * const current,
3422                                    const FRAMEINFO * const reference,
3423                                    const IMAGE * const pCurr,
3424                                    const IMAGE * const pRef,
3425                                    const IMAGE * const pRefH,
3426                                    const IMAGE * const pRefV,
3427                                    const IMAGE * const pRefHV)
3428    {
3429            uint8_t* GMCblock = (uint8_t*)malloc(16*pParam->edged_width);
3430            WARPPOINTS bestwp=*startwp;
3431            WARPPOINTS centerwp,currwp;
3432            int gmcminSAD=0;
3433            int gmcSAD=0;
3434            int direction;
3435    //      int mx,my;
3436    
3437                          if (b_mb->mode == MODE_INTER && b_mb->cbp == 0 &&  /* use many blocks... */
3438                                  b_mb->mvs[0].x == 0 && b_mb->mvs[0].y == 0) {  /*              for (my = 0; my < (uint32_t)pParam->mb_height; my++)
3439                                  mb->mode = MODE_NOT_CODED;                  for (mx = 0; mx < (uint32_t)pParam->mb_width; mx++)
3440                                  mb->b_mvs[0] = mb->mvs[0] = zeroMV;                  {
3441                                  continue;                          const int mbnum = mx + my * pParam->mb_width;
3442                            pMBs[mbnum].mcsel=1;
3443                          }                          }
3444    */
3445    
3446                          if (b_mb->mode == MODE_INTER4V)  /* or rather don't use too many blocks... */
3447    /*
3448                    for (my = 1; my < (uint32_t)MBh-1; my++)
3449                    for (mx = 1; mx < (uint32_t)MBw-1; mx++)
3450                          {                          {
3451                                  d_sad16 = 0;                          const int mbnum = mx + my * MBw;
3452                          /* same method of scaling as in decoder.c, so we copy from there */                          if (MBmask[mbnum-1])
3453                      for (k = 0; k < 4; k++) {                                  MBmask[mbnum-1]=0;
3454                            else
3455                                          mb->directmv[k] = b_mb->mvs[k];                                  if (MBmask[mbnum-MBw])
3456                                            MBmask[mbnum-1]=0;
3457    
                                         mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);  
                     mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)  
                                                                                 ? ((TRB - TRD) * mb->directmv[k].x) / TRD  
                                             : mb->mvs[k].x - mb->directmv[k].x);  
   
                     mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);  
                         mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)  
                                                                                 ? ((TRB - TRD) * mb->directmv[k].y) / TRD  
                                             : mb->mvs[k].y - mb->directmv[k].y);  
   
                                         d_sad16 +=  
                                                 sad8bi(frame->image.y + 2*(i+(k&1))*8 + 2*(j+(k>>1))*8*edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 2*(i+(k&1)), 2*(j+(k>>1)), 8, &mb->mvs[k], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 2*(i+(k&1)), 2*(j+(k>>1)), 8, &mb->b_mvs[k], edged_width),  
                                                   edged_width);  
                                 }  
3458                          }                          }
3459                          else  */
3460                          {                  gmcminSAD = globalSAD(&bestwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
                                 mb->directmv[3] = mb->directmv[2] = mb->directmv[1] =  
                                         mb->directmv[0] = b_mb->mvs[0];  
3461    
3462                                  mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);                  if ( (reference->coding_type == S_VOP)
3463                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)                          && ( (reference->warp.duv[1].x != bestwp.duv[1].x)
3464                                                                          ? ((TRB - TRD) * mb->directmv[0].x) / TRD                            || (reference->warp.duv[1].y != bestwp.duv[1].y)
3465                                      : mb->mvs[0].x - mb->directmv[0].x);                            || (reference->warp.duv[0].x != bestwp.duv[0].x)
3466                              || (reference->warp.duv[0].y != bestwp.duv[0].y)
3467                      mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);                            || (reference->warp.duv[2].x != bestwp.duv[2].x)
3468                  mb->b_mvs[0].y = (int32_t) ((mb->directmv[0].y == 0)                            || (reference->warp.duv[2].y != bestwp.duv[2].y) ) )
3469                                                                          ? ((TRB - TRD) * mb->directmv[0].y) / TRD                  {
3470                                      : mb->mvs[0].y - mb->directmv[0].y);                          gmcSAD = globalSAD(&reference->warp, pParam, pMBs,
3471                                                                    current, pRef, pCurr, GMCblock);
                                 d_sad16 = sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 i, j, 16, &mb->mvs[0], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 i, j, 16, &mb->b_mvs[0], edged_width),  
                                                   edged_width);  
3472    
3473                            if (gmcSAD < gmcminSAD)
3474                            {       bestwp = reference->warp;
3475                                    gmcminSAD = gmcSAD;
3476                            }
3477              }              }
                     d_sad16 += calc_delta_16(mb->deltamv.x, mb->deltamv.y, 1, frame->quant);  
3478    
3479                          // forward search          do {
3480                          f_sad16 = SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,                  direction = 0;
3481                                                  &frame->image, i, j,                  centerwp = bestwp;
                                                 mb->mvs[0].x, mb->mvs[0].y,                     /* start point f_directMV */  
                                                 f_predMV.x, f_predMV.y,                         /* center is f-prediction */  
                                                 frame->motion_flags,  
                                                 frame->quant, frame->fcode, pParam,  
                                                 f_mbs, f_mbs,  
                                                 &mb->mvs[0], &pmv_dontcare);  
3482    
3483                    currwp = centerwp;
3484    
3485                          // backward search                  currwp.duv[0].x--;
3486                          b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,                  gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3487                                                  &frame->image, i, j,                  if (gmcSAD < gmcminSAD)
3488                                                  mb->b_mvs[0].x, mb->b_mvs[0].y,         /* start point b_directMV */                  {       bestwp = currwp;
3489                                                  b_predMV.x, b_predMV.y,                         /* center is b-prediction */                          gmcminSAD = gmcSAD;
3490                                                  frame->motion_flags,                          direction = 1;
                                                 frame->quant, frame->bcode, pParam,  
                                                 b_mbs, b_mbs,  
                                                 &mb->b_mvs[0], &pmv_dontcare);  
   
                         i_sad16 =  
                                 sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 i, j, 16, &mb->mvs[0], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 i, j, 16, &mb->b_mvs[0], edged_width),  
                                                   edged_width);  
                     i_sad16 += calc_delta_16(mb->mvs[0].x-f_predMV.x, mb->mvs[0].y-f_predMV.y,  
                                                                 frame->fcode, frame->quant);  
                     i_sad16 += calc_delta_16(mb->b_mvs[0].x-b_predMV.x, mb->b_mvs[0].y-b_predMV.y,  
                                                                 frame->bcode, frame->quant);  
   
                         get_range(&f_min_dx, &f_max_dx, &f_min_dy, &f_max_dy, i, j, 16, iWidth, iHeight,  
                           frame->fcode);  
                         get_range(&b_min_dx, &b_max_dx, &b_min_dy, &b_max_dy, i, j, 16, iWidth, iHeight,  
                           frame->bcode);  
   
 /* 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". */  
   
                         i_sad16 = Diamond16_InterpolMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i * 16 + j * 16 * edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 mb->mvs[0].x, mb->mvs[0].y,  
                                                 mb->b_mvs[0].x, mb->b_mvs[0].y,  
                                                 i_sad16,  
                                                 &f_interpolMV, &b_interpolMV,  
                                                 f_predMV.x, f_predMV.y, b_predMV.x, b_predMV.y,  
                                                 f_min_dx, f_max_dx, f_min_dy, f_max_dy,  
                                                 b_min_dx, b_max_dx, b_min_dy, b_max_dy,  
                                                 edged_width,  2,  
                                                 frame->fcode, frame->bcode,frame->quant,0);  
   
                         i_sad16 = Diamond16_InterpolMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i * 16 + j * 16 * edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 f_interpolMV.x, f_interpolMV.y,  
                                                 b_interpolMV.x, b_interpolMV.y,  
                                                 i_sad16,  
                                                 &f_interpolMV, &b_interpolMV,  
                                                 f_predMV.x, f_predMV.y, b_predMV.x, b_predMV.y,  
                                                 f_min_dx, f_max_dx, f_min_dy, f_max_dy,  
                                                 b_min_dx, b_max_dx, b_min_dy, b_max_dy,  
                                                 edged_width,  1,  
                                                 frame->fcode, frame->bcode,frame->quant,0);             // equiv to halfpel refine  
   
   
 /*  DIRECT MODE DELTA VECTOR SEARCH.  
     This has to be made more effective, but at the moment I'm happy it's running at all */  
   
 /* There are two range restrictions for direct mode: deltaMV is limited to [-32,31] in halfpel units, and  
    absolute vector must not lie outside of image dimensions. Constraint one is dealt with by CHECK_MV16_DIRECT  
    and for constraint two we need distance to boundary. This is done by get_range very large fcode (hack!) */  
   
                         get_range(&min_dx, &max_dx, &min_dy, &max_dy, i, j, 16, iWidth, iHeight, 19);  
   
                         d_sad16 = Diamond16_DirectMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i*16 + j*16*edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 TRB,TRD,  
                                                 0,0,  
                                                 d_sad16,  
                                                 &mb->deltamv,  
                                                 mb->directmv, // this has to be pre-initialized with b_mb->mvs[]  
                                         min_dx, max_dx, min_dy, max_dy,  
                                                 edged_width, 2, frame->quant, 0);  
   
                         d_sad16 = Diamond16_DirectMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i*16 + j*16*edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 TRB,TRD,  
                                                 mb->deltamv.x, mb->deltamv.y,  
                                                 d_sad16,  
                                                 &mb->deltamv,  
                                                 mb->directmv, // this has to be pre-initialized with b_mb->mvs[]  
                                         min_dx, max_dx, min_dy, max_dy,  
                                                 edged_width, 1, frame->quant, 0);               // equiv to halfpel refine  
   
   
 //                      i_sad16 = 65535;                /* remove the comment to disable any of the MODEs */  
 //                      f_sad16 = 65535;  
 //                      b_sad16 = 65535;  
 //                      d_sad16 = 65535;  
   
                         if (f_sad16 < b_sad16) {  
                                 best_sad = f_sad16;  
                                 mb->mode = MODE_FORWARD;  
                         } else {  
                                 best_sad = b_sad16;  
                                 mb->mode = MODE_BACKWARD;  
3491                          }                          }
3492                    else
3493                          if (i_sad16 < best_sad) {                  {
3494                                  best_sad = i_sad16;                  currwp = centerwp; currwp.duv[0].x++;
3495                                  mb->mode = MODE_INTERPOLATE;                  gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3496                    if (gmcSAD < gmcminSAD)
3497                    {       bestwp = currwp;
3498                            gmcminSAD = gmcSAD;
3499                            direction = 2;
3500                    }
3501                    }
3502                    if (direction) continue;
3503    
3504                    currwp = centerwp; currwp.duv[0].y--;
3505                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3506                    if (gmcSAD < gmcminSAD)
3507                    {       bestwp = currwp;
3508                            gmcminSAD = gmcSAD;
3509                            direction = 4;
3510                          }                          }
3511                    else
                         if (d_sad16 < best_sad) {  
   
                                 if (b_mb->mode == MODE_INTER4V)  
3512                                  {                                  {
3513                    currwp = centerwp; currwp.duv[0].y++;
3514                                  /* how to calc vectors is defined in standard. mvs[] and b_mvs[] are only for motion compensation */                  gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3515                                  /* for the bitstream, the value mb->deltamv is read directly */                  if (gmcSAD < gmcminSAD)
3516                    {       bestwp = currwp;
3517                              for (k = 0; k < 4; k++) {                          gmcminSAD = gmcSAD;
3518                            direction = 8;
3519                                                  mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);                  }
3520                              mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)                  }
3521                                                                                          ? ((TRB - TRD) * mb->directmv[k].x) / TRD                  if (direction) continue;
3522                                                      : mb->mvs[k].x - mb->directmv[k].x);  
3523                    currwp = centerwp; currwp.duv[1].x++;
3524                              mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);                  gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3525                          mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)                  if (gmcSAD < gmcminSAD)
3526                                                                                          ? ((TRB - TRD) * mb->directmv[k].y) / TRD                  {       bestwp = currwp;
3527                                              : mb->mvs[k].y - mb->directmv[k].y);                          gmcminSAD = gmcSAD;
3528                            direction = 32;
3529                    }
3530                    currwp.duv[2].y++;
3531                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3532                    if (gmcSAD < gmcminSAD)
3533                    {       bestwp = currwp;
3534                            gmcminSAD = gmcSAD;
3535                            direction = 1024;
3536                    }
3537    
3538                    currwp = centerwp; currwp.duv[1].x--;
3539                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3540                    if (gmcSAD < gmcminSAD)
3541                    {       bestwp = currwp;
3542                            gmcminSAD = gmcSAD;
3543                            direction = 16;
3544                    }
3545                    else
3546                    {
3547                    currwp = centerwp; currwp.duv[1].x++;
3548                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3549                    if (gmcSAD < gmcminSAD)
3550                    {       bestwp = currwp;
3551                            gmcminSAD = gmcSAD;
3552                            direction = 32;
3553                    }
3554                    }
3555                    if (direction) continue;
3556    
3557    
3558                    currwp = centerwp; currwp.duv[1].y--;
3559                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3560                    if (gmcSAD < gmcminSAD)
3561                    {       bestwp = currwp;
3562                            gmcminSAD = gmcSAD;
3563                            direction = 64;
3564                                          }                                          }
3565                    else
3566                    {
3567                    currwp = centerwp; currwp.duv[1].y++;
3568                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3569                    if (gmcSAD < gmcminSAD)
3570                    {       bestwp = currwp;
3571                            gmcminSAD = gmcSAD;
3572                            direction = 128;
3573                    }
3574                    }
3575                    if (direction) continue;
3576    
3577                    currwp = centerwp; currwp.duv[2].x--;
3578                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3579                    if (gmcSAD < gmcminSAD)
3580                    {       bestwp = currwp;
3581                            gmcminSAD = gmcSAD;
3582                            direction = 256;
3583                    }
3584                    else
3585                    {
3586                    currwp = centerwp; currwp.duv[2].x++;
3587                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3588                    if (gmcSAD < gmcminSAD)
3589                    {       bestwp = currwp;
3590                            gmcminSAD = gmcSAD;
3591                            direction = 512;
3592                    }
3593                    }
3594                    if (direction) continue;
3595    
3596                    currwp = centerwp; currwp.duv[2].y--;
3597                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3598                    if (gmcSAD < gmcminSAD)
3599                    {       bestwp = currwp;
3600                            gmcminSAD = gmcSAD;
3601                            direction = 1024;
3602                                  }                                  }
3603                                  else                                  else
3604                                  {                                  {
3605                                          mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);                  currwp = centerwp; currwp.duv[2].y++;
3606                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3607                    if (gmcSAD < gmcminSAD)
3608                    {       bestwp = currwp;
3609                            gmcminSAD = gmcSAD;
3610                            direction = 2048;
3611                    }
3612                    }
3613            } while (direction);
3614            free(GMCblock);
3615    
3616                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)          *startwp = bestwp;
                                                                                 ? ((TRB - TRD) * mb->directmv[0].x) / TRD  
                                         : mb->mvs[0].x - mb->directmv[0].x);  
3617    
3618                              mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);          return gmcminSAD;
3619    }
3620    
3621                          mb->b_mvs[0].y = (int32_t) ((mb->deltamv.y == 0)  int
3622                                                                                  ? ((TRB - TRD) * mb->directmv[0].y) / TRD  globalSAD(const WARPPOINTS *const wp,
3623                                              : mb->mvs[0].y - mb->directmv[0].y);                    const MBParam * const pParam,
3624                      const MACROBLOCK * const pMBs,
3625                      const FRAMEINFO * const current,
3626                      const IMAGE * const pRef,
3627                      const IMAGE * const pCurr,
3628                      uint8_t *const GMCblock)
3629    {
3630            NEW_GMC_DATA gmc_data;
3631            int iSAD, gmcSAD=0;
3632            int num=0;
3633            unsigned int mx, my;
3634    
3635                                          mb->mvs[3] = mb->mvs[2] = mb->mvs[1] = mb->mvs[0];          generate_GMCparameters( 3, 3, wp, pParam->width, pParam->height, &gmc_data);
                                         mb->b_mvs[3] = mb->b_mvs[2] = mb->b_mvs[1] = mb->b_mvs[0];  
                 }  
3636    
3637                                  best_sad = d_sad16;          for (my = 0; my < (uint32_t)pParam->mb_height; my++)
3638                                  mb->mode = MODE_DIRECT;                  for (mx = 0; mx < (uint32_t)pParam->mb_width; mx++) {
                         }  
3639    
3640                          switch (mb->mode)                  const int mbnum = mx + my * pParam->mb_width;
3641                          {                  const int iEdgedWidth = pParam->edged_width;
                                 case MODE_FORWARD:  
                                         f_count++;  
                                         f_predMV = mb->mvs[0];  
                                         break;  
                                 case MODE_BACKWARD:  
                                         b_count++;  
                                         b_predMV = mb->b_mvs[0];  
3642    
3643                                          break;                  if (!pMBs[mbnum].mcsel)
3644                                  case MODE_INTERPOLATE:                          continue;
                                         i_count++;  
                                         mb->mvs[0] = f_interpolMV;  
                                         mb->b_mvs[0] = b_interpolMV;  
                                         f_predMV = mb->mvs[0];  
                                         b_predMV = mb->b_mvs[0];  
                                         break;  
                                 case MODE_DIRECT:  
                                         d_count++;  
                                         break;  
                                 default:  
                                         break;  
                         }  
3645    
3646                    gmc_data.predict_16x16(&gmc_data, GMCblock,
3647                                                    pRef->y,
3648                                                    iEdgedWidth,
3649                                                    iEdgedWidth,
3650                                                    mx, my,
3651                                                    pParam->m_rounding_type);
3652    
3653                    iSAD = sad16 ( pCurr->y + 16*(my*iEdgedWidth + mx),
3654                                                    GMCblock , iEdgedWidth, 65536);
3655                    iSAD -= pMBs[mbnum].sad16;
3656    
3657                    if (iSAD<0)
3658                            gmcSAD += iSAD;
3659                    num++;
3660                  }                  }
3661            return gmcSAD;
3662          }          }
3663    
 #ifdef _DEBUG_BFRAME_STAT  
         fprintf(stderr,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d\n",  
                                 f_count,b_count,i_count,d_count);  
 #endif  
   
 }  

Legend:
Removed from v.348  
changed lines
  Added in v.1137

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