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

Legend:
Removed from v.341  
changed lines
  Added in v.1133

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