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

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