[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 346, Sun Jul 28 02:55:41 2002 UTC branches/dev-api-4/xvidcore/src/motion/motion_est.c revision 1135, Fri Aug 29 13:47:21 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.32 2003-08-29 13:47:21 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            sad += (data->lambda8 * t * (sad+NEIGH_8X8_BIAS))>>10;
371    
372  #define CHECK_MV16_ZERO {\          if (sad < *(data->iMinSAD)) {
373    if ( (0 <= max_dx) && (0 >= min_dx) \                  *(data->iMinSAD) = sad;
374      && (0 <= max_dy) && (0 >= min_dy) ) \                  current->x = x; current->y = y;
375    { \                  *data->dir = Direction;
376      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \          }
     iSAD += calc_delta_16(-center_x, -center_y, (uint8_t)iFcode, iQuant);\  
     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;  
   
         return iSAD;  
397    
398            if (sad < data->iMinSAD[0]) {
399                    data->iMinSAD[0] = sad;
400                    data->currentMV[0].x = x; data->currentMV[0].y = y;
401                    *data->dir = Direction;
402  }  }
 */  
403    
404  int32_t          if (data->temp[0] < data->iMinSAD[1]) {
405  Diamond16_MainSearch(const uint8_t * const pRef,                  data->iMinSAD[1] = data->temp[0]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
406                                           const uint8_t * const pRefH,          if (data->temp[1] < data->iMinSAD[2]) {
407                                           const uint8_t * const pRefV,                  data->iMinSAD[2] = data->temp[1]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
408                                           const uint8_t * const pRefHV,          if (data->temp[2] < data->iMinSAD[3]) {
409                                           const uint8_t * const cur,                  data->iMinSAD[3] = data->temp[2]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
410                                           const int x,          if (data->temp[3] < data->iMinSAD[4]) {
411                                           const int y,                  data->iMinSAD[4] = data->temp[3]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
                                    const int start_x,  
                                    const int start_y,  
                                    int iMinSAD,  
                                    VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                          const int32_t min_dx,  
                                          const int32_t max_dx,  
                                          const int32_t min_dy,  
                                          const int32_t max_dy,  
                                          const int32_t iEdgedWidth,  
                                          const int32_t iDiamondSize,  
                                          const int32_t iFcode,  
                                          const int32_t iQuant,  
                                          int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iDirectionBackup;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
   
         if (iDirection) {  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;  
                         iDirectionBackup = iDirection;  
   
                         if (iDirectionBackup != 2)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                    backupMV.y, 1);  
                         if (iDirectionBackup != 1)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                    backupMV.y, 2);  
                         if (iDirectionBackup != 4)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,  
                                                                                    backupMV.y - iDiamondSize, 3);  
                         if (iDirectionBackup != 3)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,  
                                                                                    backupMV.y + iDiamondSize, 4);  
412                  }                  }
413    
414    static void
415    CheckCandidate16no4v(const int x, const int y, const SearchData * const data, const int Direction)
416    {
417            int32_t sad, xc, yc;
418            const uint8_t * Reference;
419            uint32_t t;
420            VECTOR * current;
421    
422            if ( (x > data->max_dx) || ( x < data->min_dx)
423                    || (y > data->max_dy) || (y < data->min_dy) ) return;
424    
425            if (data->rrv && (!(x&1) && x !=0) | (!(y&1) && y !=0) ) return; /* non-zero even value */
426    
427            if (data->qpel_precision) { /* x and y are in 1/4 precision */
428                    Reference = Interpolate16x16qpel(x, y, 0, data);
429                    current = data->currentQMV;
430                    xc = x/2; yc = y/2;
431          } else {          } else {
432                  currMV->x = start_x;                  Reference = GetReference(x, y, data);
433                  currMV->y = start_y;                  current = data->currentMV;
434          }                  xc = x; yc = y;
         return iMinSAD;  
435  }  }
436            t = d_mv_bits(x, y, data->predMV, data->iFcode,
437                                            data->qpel^data->qpel_precision, data->rrv);
438    
439  int32_t          sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
440  Square16_MainSearch(const uint8_t * const pRef,          sad += (data->lambda16 * t * sad)>>10;
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x,  
                                         const int y,  
                                    const int start_x,  
                                    const int start_y,  
                                    int iMinSAD,  
                                    VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a square search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* It's one search with full square pattern, and new parts for all following diamonds */  
   
 /*   new direction are extra, so 1-4 is normal diamond  
       537  
       1*2  
       648  
 */  
441    
442          CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);          if (data->chroma && sad < *data->iMinSAD)
443          CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);                  sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
444          CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);                                                          (yc >> 1) + roundtab_79[yc & 0x3], data);
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
   
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 5);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 6);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 7);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 8);  
   
   
         if (iDirection) {  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;  
445    
446                          switch (iDirection) {          if (sad < *(data->iMinSAD)) {
447                          case 1:                  *(data->iMinSAD) = sad;
448                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  current->x = x; current->y = y;
449                                                                                     backupMV.y, 1);                  *data->dir = Direction;
450                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          }
451                                                                                   backupMV.y - iDiamondSize, 5);  }
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
                         case 2:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
452    
453                          case 3:  static void
454                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  CheckCandidate16I(const int x, const int y, const SearchData * const data, const int Direction)
455                                                                                   4);  {
456                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,          int sad;
457                                                                                   backupMV.y - iDiamondSize, 7);  //      int xc, yc;
458                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,          const uint8_t * Reference;
459                                                                                   backupMV.y + iDiamondSize, 8);  //      VECTOR * current;
                                 break;  
460    
461                          case 4:          if ( (x > data->max_dx) || ( x < data->min_dx)
462                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,                  || (y > data->max_dy) || (y < data->min_dy) ) return;
                                                                                  3);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 break;  
   
                         case 5:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
   
                         case 6:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
   
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
463    
464                                  break;          Reference = GetReference(x, y, data);
465    //      xc = x; yc = y;
466    
467                          case 7:          sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
468                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  //      sad += d_mv_bits(x, y, data->predMV, data->iFcode, 0, 0);
                                                                                    backupMV.y, 1);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
469    
470                          case 8:  /*      if (data->chroma) sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
471                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,                                                                                  (yc >> 1) + roundtab_79[yc & 0x3], data);
472                                                                                   2);  */
473                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
474                                                                                   4);          if (sad < data->iMinSAD[0]) {
475                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  data->iMinSAD[0] = sad;
476                                                                                   backupMV.y + iDiamondSize, 6);                  data->currentMV[0].x = x; data->currentMV[0].y = y;
477                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                  *data->dir = Direction;
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         default:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
   
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         }  
                 }  
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
478          }          }
         return iMinSAD;  
479  }  }
480    
481    static void
482    CheckCandidate32I(const int x, const int y, const SearchData * const data, const int Direction)
483    {
484            /* maximum speed - for P/B/I decision */
485            int32_t sad;
486    
487  int32_t          if ( (x > data->max_dx) || (x < data->min_dx)
488  Full16_MainSearch(const uint8_t * const pRef,                  || (y > data->max_dy) || (y < data->min_dy) ) return;
                                   const uint8_t * const pRefH,  
                                   const uint8_t * const pRefV,  
                                   const uint8_t * const pRefHV,  
                                   const uint8_t * const cur,  
                                   const int x,  
                                   const int y,  
                                    const int start_x,  
                                    const int start_y,  
                                    int iMinSAD,  
                                    VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                   const int32_t min_dx,  
                                   const int32_t max_dx,  
                                   const int32_t min_dy,  
                                   const int32_t max_dy,  
                                   const int32_t iEdgedWidth,  
                                   const int32_t iDiamondSize,  
                                   const int32_t iFcode,  
                                   const int32_t iQuant,  
                                   int iFound)  
 {  
         int32_t iSAD;  
         int32_t dx, dy;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV16_CANDIDATE(dx, dy);  
489    
490          return iMinSAD;          sad = sad32v_c(data->Cur, data->RefP[0] + x + y*((int)data->iEdgedWidth),
491                                            data->iEdgedWidth, data->temp);
492    
493            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  int32_t  }
 AdvDiamond16_MainSearch(const uint8_t * const pRef,  
                                                 const uint8_t * const pRefH,  
                                                 const uint8_t * const pRefV,  
                                                 const uint8_t * const pRefHV,  
                                                 const uint8_t * const cur,  
                                                 const int x,  
                                                 const int y,  
                                            int start_x,  
                                            int start_y,  
                                            int iMinSAD,  
                                            VECTOR * const currMV,  
                                            const int center_x,  
                                            const int center_y,  
                                                 const int32_t min_dx,  
                                                 const int32_t max_dx,  
                                                 const int32_t min_dy,  
                                                 const int32_t max_dy,  
                                                 const int32_t iEdgedWidth,  
                                                 const int32_t iDiamondSize,  
                                                 const int32_t iFcode,  
                                                 const int32_t iQuant,  
                                                 int iDirection)  
 {  
508    
509          int32_t iSAD;  static void
510    CheckCandidateInt(const int xf, const int yf, const SearchData * const data, const int Direction)
511    {
512            int32_t sad, xb, yb, xcf, ycf, xcb, ycb;
513            uint32_t t;
514            const uint8_t *ReferenceF, *ReferenceB;
515            VECTOR *current;
516    
517  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */          if ((xf > data->max_dx) || (xf < data->min_dx) ||
518                    (yf > data->max_dy) || (yf < data->min_dy))
519                    return;
520    
521          if (iDirection) {          if (!data->qpel_precision) {
522                  CHECK_MV16_CANDIDATE(start_x - iDiamondSize, start_y);                  ReferenceF = GetReference(xf, yf, data);
523                  CHECK_MV16_CANDIDATE(start_x + iDiamondSize, start_y);                  xb = data->currentMV[1].x; yb = data->currentMV[1].y;
524                  CHECK_MV16_CANDIDATE(start_x, start_y - iDiamondSize);                  ReferenceB = GetReferenceB(xb, yb, 1, data);
525                  CHECK_MV16_CANDIDATE(start_x, start_y + iDiamondSize);                  current = data->currentMV;
526                    xcf = xf; ycf = yf;
527                    xcb = xb; ycb = yb;
528          } else {          } else {
529                  int bDirection = 1 + 2 + 4 + 8;                  ReferenceF = Interpolate16x16qpel(xf, yf, 0, data);
530                    xb = data->currentQMV[1].x; yb = data->currentQMV[1].y;
531                  do {                  current = data->currentQMV;
532                          iDirection = 0;                  ReferenceB = Interpolate16x16qpel(xb, yb, 1, data);
533                          if (bDirection & 1)     //we only want to check left if we came from the right (our last motion was to the left, up-left or down-left)                  xcf = xf/2; ycf = yf/2;
534                                  CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);                  xcb = xb/2; ycb = yb/2;
535            }
536    
537                          if (bDirection & 2)          t = d_mv_bits(xf, yf, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0)
538                                  CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);                   + d_mv_bits(xb, yb, data->bpredMV, data->iFcode, data->qpel^data->qpel_precision, 0);
539    
540                          if (bDirection & 4)          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
541                                  CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);          sad += (data->lambda16 * t * sad)>>10;
542    
543                          if (bDirection & 8)          if (data->chroma && sad < *data->iMinSAD)
544                                  CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);                  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                          /* now we're doing diagonal checks near our candidate */          if (sad < *(data->iMinSAD)) {
550                    *(data->iMinSAD) = sad;
551                    current->x = xf; current->y = yf;
552                    *data->dir = Direction;
553            }
554    }
555    
556                          if (iDirection)         //checking if anything found  static void
557    CheckCandidateDirect(const int x, const int y, const SearchData * const data, const int Direction)
558                          {                          {
559                                  bDirection = iDirection;          int32_t sad = 0, xcf = 0, ycf = 0, xcb = 0, ycb = 0;
560                                  iDirection = 0;          uint32_t k;
561                                  start_x = currMV->x;          const uint8_t *ReferenceF;
562                                  start_y = currMV->y;          const uint8_t *ReferenceB;
563                                  if (bDirection & 3)     //our candidate is left or right          VECTOR mvs, b_mvs;
564                                  {  
565                                          CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
                                         CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);  
                                 } else                  // what remains here is up or down  
                                 {  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
                                 }  
566    
567                                  if (iDirection) {          for (k = 0; k < 4; k++) {
568                                          bDirection += iDirection;                  mvs.x = data->directmvF[k].x + x;
569                                          start_x = currMV->x;                  b_mvs.x = ((x == 0) ?
570                                          start_y = currMV->y;                          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 {
588                            xcf += mvs.x; ycf += mvs.y;
589                            xcb += b_mvs.x; ycb += b_mvs.y;
590                            mvs.x *= 2; mvs.y *= 2; /* we move to qpel precision anyway */
591                            b_mvs.x *= 2; b_mvs.y *= 2;
592                                  }                                  }
                         } else                          //about to quit, eh? not so fast....  
                         {  
                                 switch (bDirection) {  
                                 case 2:  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1:  
593    
594                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                  ReferenceF = Interpolate8x8qpel(mvs.x, mvs.y, k, 0, data);
595                                                                                           start_y - iDiamondSize, 1 + 4);                  ReferenceB = Interpolate8x8qpel(b_mvs.x, b_mvs.y, k, 1, data);
596                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
597                                                                                           start_y + iDiamondSize, 1 + 8);                  sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
598                                          break;                                                  ReferenceF, ReferenceB, data->iEdgedWidth);
599                                  case 2 + 4:                  if (sad > *(data->iMinSAD)) return;
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 4:  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         break;  
                                 case 8:  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 1 + 4:  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         break;  
                                 case 2 + 8:  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1 + 8:  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         break;  
                                 default:                //1+2+4+8 == we didn't find anything at all  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         break;  
600                                  }                                  }
                                 if (!iDirection)  
                                         break;          //ok, the end. really  
                                 else {  
                                         bDirection = iDirection;  
                                         start_x = currMV->x;  
                                         start_y = currMV->y;  
                                 }  
                         }  
                 }  
                 while (1);                              //forever  
         }  
         return iMinSAD;  
 }  
   
 #define CHECK_MV16_F_INTERPOL(X,Y) { \  
   if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \  
     && ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, b_currMV->x, b_currMV->y, iEdgedWidth),   \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16((X) - f_center_x, (Y) - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16(b_currMV->x - b_center_x, b_currMV->y - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; f_currMV->x=(X); f_currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_F_INTERPOL_FOUND(X,Y) { \  
   if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \  
     && ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, b_currMV->x, b_currMV->y, iEdgedWidth),   \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16((X) - f_center_x, (Y) - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16(b_currMV->x - b_center_x, b_currMV->y - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; f_currMV->x=(X); f_currMV->y=(Y); iFound=0;} } \  
 }  
   
 #define CHECK_MV16_B_INTERPOL(X,Y) { \  
   if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \  
     && ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth),   \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16((X) - b_center_x, (Y) - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; b_currMV->x=(X); b_currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_B_INTERPOL_FOUND(X,Y) { \  
   if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \  
     && ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth),   \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16((X) - b_center_x, (Y) - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; b_currMV->x=(X); b_currMV->y=(Y); iFound=0;} } \  
 }  
   
 int32_t  
 Diamond16_InterpolMainSearch(  
                                         const uint8_t * const f_pRef,  
                                          const uint8_t * const f_pRefH,  
                                          const uint8_t * const f_pRefV,  
                                          const uint8_t * const f_pRefHV,  
   
                                          const uint8_t * const cur,  
   
                                         const uint8_t * const b_pRef,  
                                          const uint8_t * const b_pRefH,  
                                          const uint8_t * const b_pRefV,  
                                          const uint8_t * const b_pRefHV,  
601    
602                                           const int x,          sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;
                                          const int y,  
603    
604                                     const int f_start_x,          if (data->chroma && sad < *data->iMinSAD)
605                                     const int f_start_y,                  sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],
606                                     const int b_start_x,                                                          (ycf >> 3) + roundtab_76[ycf & 0xf],
607                                     const int b_start_y,                                                          (xcb >> 3) + roundtab_76[xcb & 0xf],
608                                                            (ycb >> 3) + roundtab_76[ycb & 0xf], data);
                                    int iMinSAD,  
                                    VECTOR * const f_currMV,  
                                    VECTOR * const b_currMV,  
   
                                    const int f_center_x,  
                                    const int f_center_y,  
                                    const int b_center_x,  
                                    const int b_center_y,  
   
                                     const int32_t f_min_dx,  
                                         const int32_t f_max_dx,  
                                         const int32_t f_min_dy,  
                                         const int32_t f_max_dy,  
   
                                     const int32_t b_min_dx,  
                                         const int32_t b_max_dx,  
                                         const int32_t b_min_dy,  
                                         const int32_t b_max_dy,  
   
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
   
                                         const int32_t f_iFcode,  
                                         const int32_t b_iFcode,  
   
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iSAD;  
   
         VECTOR f_backupMV;  
         VECTOR b_backupMV;  
   
         f_currMV->x = f_start_x;  
         f_currMV->y = f_start_y;  
         b_currMV->x = b_start_x;  
         b_currMV->y = b_start_y;  
   
         do  
         {  
                 iFound = 1;  
   
                 f_backupMV = *f_currMV;  
   
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x - iDiamondSize, f_backupMV.y);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x + iDiamondSize, f_backupMV.y);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y - iDiamondSize);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y + iDiamondSize);  
   
                 b_backupMV = *b_currMV;  
   
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x - iDiamondSize, b_backupMV.y);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x + iDiamondSize, b_backupMV.y);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y - iDiamondSize);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y + iDiamondSize);  
   
         } while (!iFound);  
   
         return iMinSAD;  
 }  
   
 /* Sorry, these MACROS really got too large... I'll turn them into function soon! */  
   
 #define CHECK_MV16_DIRECT_FOUND(X,Y) \  
         if ( (X)>=(-32) && (X)<=(31) && ((Y)>=-32) && ((Y)<=31) ) \  
         { int k;\  
         VECTOR mvs,b_mvs;       \  
         iSAD = 0;\  
         for (k = 0; k < 4; k++) {       \  
                                         mvs.x = (int32_t) ((TRB * directmv[k].x) / TRD + (X));          \  
                     b_mvs.x = (int32_t) (((X) == 0)                                                     \  
                                                                                 ? ((TRB - TRD) * directmv[k].x) / TRD   \  
                                             : mvs.x - directmv[k].x);                           \  
                                                                                                                                                                 \  
                     mvs.y = (int32_t) ((TRB * directmv[k].y) / TRD + (Y));              \  
                         b_mvs.y = (int32_t) (((Y) == 0)                                                         \  
                                                                                 ? ((TRB - TRD) * directmv[k].y) / TRD   \  
                                             : mvs.y - directmv[k].y);                           \  
                                                                                                                                                                 \  
   if ( (mvs.x <= max_dx) && (mvs.x >= min_dx) \  
     && (mvs.y <= max_dy) && (mvs.y >= min_dy)  \  
         && (b_mvs.x <= max_dx) && (b_mvs.x >= min_dx)  \  
     && (b_mvs.y <= max_dy) && (b_mvs.y >= min_dy) ) { \  
             iSAD += sad8bi( cur + 8*(k&1) + 8*(k>>1)*iEdgedWidth,                                                                                                       \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \  
                                         mvs.x, mvs.y, iEdgedWidth),                                                             \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \  
                                         b_mvs.x, b_mvs.y, iEdgedWidth),                                                         \  
                         iEdgedWidth); \  
                 }       \  
         else    \  
                 iSAD = 65535;   \  
         } \  
         iSAD += calc_delta_16((X),(Y), 1, iQuant);\  
         if (iSAD < iMinSAD) \  
             {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iFound=0; } \  
 }  
   
   
   
 int32_t  
 Diamond16_DirectMainSearch(  
                                         const uint8_t * const f_pRef,  
                                         const uint8_t * const f_pRefH,  
                                         const uint8_t * const f_pRefV,  
                                         const uint8_t * const f_pRefHV,  
   
                                         const uint8_t * const cur,  
   
                                         const uint8_t * const b_pRef,  
                                         const uint8_t * const b_pRefH,  
                                         const uint8_t * const b_pRefV,  
                                         const uint8_t * const b_pRefHV,  
609    
610                                          const int x,          if (sad < *(data->iMinSAD)) {
611                                          const int y,                  *(data->iMinSAD) = sad;
612                    data->currentMV->x = x; data->currentMV->y = y;
613                    *data->dir = Direction;
614            }
615    }
616    
617                                          const int TRB,  static void
618                                          const int TRD,  CheckCandidateDirectno4v(const int x, const int y, const SearchData * const data, const int Direction)
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                                      const int start_x,          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
                                     const int start_y,  
626    
627                                      int iMinSAD,          mvs.x = data->directmvF[0].x + x;
628                                      VECTOR * const currMV,          b_mvs.x = ((x == 0) ?
629                                          const VECTOR * const directmv,                  data->directmvB[0].x
630                    : mvs.x - data->referencemv[0].x);
631    
632                                      const int32_t min_dx,          mvs.y = data->directmvF[0].y + y;
633                                          const int32_t max_dx,          b_mvs.y = ((y == 0) ?
634                                          const int32_t min_dy,                  data->directmvB[0].y
635                                          const int32_t max_dy,                  : mvs.y - data->referencemv[0].y);
636    
637                                          const int32_t iEdgedWidth,          if ( (mvs.x > data->max_dx) || (mvs.x < data->min_dx)
638                                          const int32_t iDiamondSize,                  || (mvs.y > data->max_dy) || (mvs.y < data->min_dy)
639                    || (b_mvs.x > data->max_dx) || (b_mvs.x < data->min_dx)
640                    || (b_mvs.y > data->max_dy) || (b_mvs.y < data->min_dy) ) return;
641    
642                                          const int32_t iQuant,          if (data->qpel) {
643                                          int iFound)                  xcf = 4*(mvs.x/2); ycf = 4*(mvs.y/2);
644  {                  xcb = 4*(b_mvs.x/2); ycb = 4*(b_mvs.y/2);
645  /* Do a diamond search around given starting point, return SAD of best */                  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          int32_t iSAD;          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
655            sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;
656    
657          VECTOR backupMV;          if (data->chroma && sad < *data->iMinSAD)
658                    sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],
659                                                            (ycf >> 3) + roundtab_76[ycf & 0xf],
660                                                            (xcb >> 3) + roundtab_76[xcb & 0xf],
661                                                            (ycb >> 3) + roundtab_76[ycb & 0xf], data);
662    
663          currMV->x = start_x;          if (sad < *(data->iMinSAD)) {
664          currMV->y = start_y;                  *(data->iMinSAD) = sad;
665                    data->currentMV->x = x; data->currentMV->y = y;
666                    *data->dir = Direction;
667            }
668    }
669    
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
670    
671          do  static void
672    CheckCandidateRD16(const int x, const int y, const SearchData * const data, const int Direction)
673          {          {
                 iFound = 1;  
674    
675                  backupMV = *currMV;          int16_t *in = data->dctSpace, *coeff = data->dctSpace + 64;
676            int32_t rd = 0;
677            VECTOR * current;
678            const uint8_t * ptr;
679            int i, cbp = 0, t, xc, yc;
680    
681                  CHECK_MV16_DIRECT_FOUND(backupMV.x - iDiamondSize, backupMV.y);          if ( (x > data->max_dx) || (x < data->min_dx)
682                  CHECK_MV16_DIRECT_FOUND(backupMV.x + iDiamondSize, backupMV.y);                  || (y > data->max_dy) || (y < data->min_dy) ) return;
                 CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y - iDiamondSize);  
                 CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y + iDiamondSize);  
683    
684          } while (!iFound);          if (!data->qpel_precision) {
685                    ptr = GetReference(x, y, data);
686          return iMinSAD;                  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  int32_t          rd += t = BITS_MULT*d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
 AdvDiamond8_MainSearch(const uint8_t * const pRef,  
                                            const uint8_t * const pRefH,  
                                            const uint8_t * const pRefV,  
                                            const uint8_t * const pRefHV,  
                                            const uint8_t * const cur,  
                                            const int x,  
                                            const int y,  
                                            int start_x,  
                                            int start_y,  
                                            int iMinSAD,  
                                            VECTOR * const currMV,  
                                            const int center_x,  
                                            const int center_y,  
                                            const int32_t min_dx,  
                                            const int32_t max_dx,  
                                            const int32_t min_dy,  
                                            const int32_t max_dy,  
                                            const int32_t iEdgedWidth,  
                                            const int32_t iDiamondSize,  
                                            const int32_t iFcode,  
                                            const int32_t iQuant,  
                                            int iDirection)  
 {  
701    
702          int32_t iSAD;          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  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */          rd += BITS_MULT*xvid_cbpy_tab[15-(cbp>>2)].len;
712    
713          if (iDirection) {          if (rd >= data->iMinSAD[0]) return;
                 CHECK_MV8_CANDIDATE(start_x - iDiamondSize, start_y);  
                 CHECK_MV8_CANDIDATE(start_x + iDiamondSize, start_y);  
                 CHECK_MV8_CANDIDATE(start_x, start_y - iDiamondSize);  
                 CHECK_MV8_CANDIDATE(start_x, start_y + iDiamondSize);  
         } else {  
                 int bDirection = 1 + 2 + 4 + 8;  
714    
715                  do {          /* chroma */
716                          iDirection = 0;          xc = (xc >> 1) + roundtab_79[xc & 0x3];
717                          if (bDirection & 1)     //we only want to check left if we came from the right (our last motion was to the left, up-left or down-left)          yc = (yc >> 1) + roundtab_79[yc & 0x3];
                                 CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
718    
719                          if (bDirection & 2)          /* chroma U */
720                                  CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);          ptr = interpolate8x8_switch2(data->RefQ, data->RefP[4], 0, 0, xc, yc, data->iEdgedWidth/2, data->rounding);
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                          if (bDirection & 4)          /* chroma V */
726                                  CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);          ptr = interpolate8x8_switch2(data->RefQ, data->RefP[5], 0, 0, xc, yc, data->iEdgedWidth/2, data->rounding);
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                          if (bDirection & 8)          rd += BITS_MULT*mcbpc_inter_tab[(MODE_INTER & 7) | ((cbp & 3) << 3)].len;
                                 CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
731    
732                          /* now we're doing diagonal checks near our candidate */          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                          if (iDirection)         //checking if anything found  static void
741    CheckCandidateRD8(const int x, const int y, const SearchData * const data, const int Direction)
742                          {                          {
743                                  bDirection = iDirection;  
744                                  iDirection = 0;          int16_t *in = data->dctSpace, *coeff = data->dctSpace + 64;
745                                  start_x = currMV->x;          int32_t rd;
746                                  start_y = currMV->y;          VECTOR * current;
747                                  if (bDirection & 3)     //our candidate is left or right          const uint8_t * ptr;
748                                  {          int cbp = 0;
749                                          CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
750                                          CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);          if ( (x > data->max_dx) || (x < data->min_dx)
751                                  } else                  // what remains here is up or down                  || (y > data->max_dy) || (y < data->min_dy) ) return;
752                                  {  
753                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);          if (!data->qpel_precision) {
754                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);                  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_MV8_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_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
815                                          break;                                          break;
816                                  case 1:                                  case 1:
817                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
818                                                                                          start_y - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
819                                          break;                                          break;
820                                  case 2 + 4:                                  case 2 + 4:
821                                          CHECK_MV8_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_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
824                                          break;                                          break;
825                                  case 4:                                  case 4:
826                                          CHECK_MV8_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_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
828                                          break;                                          break;
829                                  case 8:                                  case 8:
830                                          CHECK_MV8_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_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
832                                          break;                                          break;
833                                  case 1 + 4:                                  case 1 + 4:
834                                          CHECK_MV8_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_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
837                                          break;                                          break;
838                                  case 2 + 8:                                  case 2 + 8:
839                                          CHECK_MV8_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_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
842                                          break;                                          break;
843                                  case 1 + 8:                                  case 1 + 8:
844                                          CHECK_MV8_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_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
847                                                                                          start_y + iDiamondSize, 2 + 8);                                  break;
848                                          CHECK_MV8_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_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
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;
                                         bDirection = iDirection;  
                                         start_x = currMV->x;  
                                         start_y = currMV->y;  
                                 }  
                         }  
858                  }                  }
                 while (1);                              //forever  
859          }          }
         return iMinSAD;  
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  int32_t          do {
868  Full8_MainSearch(const uint8_t * const pRef,                  *iDirection = 0;
869                                   const uint8_t * const pRefH,                  if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);
870                                   const uint8_t * const pRefV,                  if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);
871                                   const uint8_t * const pRefHV,                  if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);
872                                   const uint8_t * const cur,                  if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128);
873                                   const int x,                  if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64);
874                                   const int y,                  if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128);
875                             const int start_x,                  if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128);
876                             const int start_y,                  if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128);
877                             int iMinSAD,  
878                             VECTOR * const currMV,                  bDirection = *iDirection;
879                             const int center_x,                  x = data->currentMV->x; y = data->currentMV->y;
880                             const int center_y,          } while (*iDirection);
                                  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;  
881  }  }
882    
883  Halfpel8_RefineFuncPtr Halfpel8_Refine;  static void
884    DiamondSearch(int x, int y, const SearchData * const data, int bDirection, CheckFunc * const CheckCandidate)
 int32_t  
 Halfpel16_Refine(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,  
                                  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)  
885  {  {
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
886    
887          int32_t iSAD;  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
         VECTOR backupMV = *currMV;  
888    
889          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y - 1);          unsigned int * const iDirection = data->dir;
         CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y - 1);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y - 1);  
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y + 1);  
         CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y + 1);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y + 1);  
890    
891          return iMinSAD;          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  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)                  /* 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                    }
914            }
915            while (*iDirection);
916    }
917    
918    /* MAINSEARCH FUNCTIONS END */
919    
920  int32_t  static void
921  PMVfastSearch16(const uint8_t * const pRef,  SubpelRefine(const SearchData * const data, CheckFunc * const CheckCandidate)
                                 const uint8_t * const pRefH,  
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const IMAGE * const pCur,  
                                 const int x,  
                                 const int y,  
                                 const int start_x,      /* start is searched first, so it should contain the most */  
                                 const int start_y,  /* likely motion vector for this block */  
                                 const int center_x,     /* center is from where length of MVs is measured */  
                                 const int center_y,  
                                 const uint32_t MotionFlags,  
                                 const uint32_t iQuant,  
                                 const uint32_t iFcode,  
                                 const MBParam * const pParam,  
                                 const MACROBLOCK * const pMBs,  
                                 const MACROBLOCK * const prevMBs,  
                                 VECTOR * const currMV,  
                                 VECTOR * const currPMV)  
922  {  {
923          const uint32_t iWcount = pParam->mb_width;  /* Do a half-pel or q-pel refinement */
924          const int32_t iWidth = pParam->width;          const VECTOR centerMV = data->qpel_precision ? *data->currentQMV : *data->currentMV;
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
925    
926          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          CHECK_CANDIDATE(centerMV.x, centerMV.y - 1, 0);
927            CHECK_CANDIDATE(centerMV.x + 1, centerMV.y - 1, 0);
928            CHECK_CANDIDATE(centerMV.x + 1, centerMV.y, 0);
929            CHECK_CANDIDATE(centerMV.x + 1, centerMV.y + 1, 0);
930            CHECK_CANDIDATE(centerMV.x, centerMV.y + 1, 0);
931            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y + 1, 0);
932            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y, 0);
933            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y - 1, 0);
934    }
935    
936          int32_t iDiamondSize;  static __inline int
937    SkipDecisionP(const IMAGE * current, const IMAGE * reference,
938          int32_t min_dx;                                                          const int x, const int y,
939          int32_t max_dx;                                                          const uint32_t stride, const uint32_t iQuant, int rrv)
         int32_t min_dy;  
         int32_t max_dy;  
   
         int32_t iFound;  
   
         VECTOR newMV;  
         VECTOR backupMV;                        /* just for PMVFAST */  
   
         VECTOR pmv[4];  
         int32_t psad[4];  
   
         MainSearch16FuncPtr MainSearchPtr;  
   
         const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;  
   
         int32_t threshA, threshB;  
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD;  
   
 /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
940    
941  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  {
942            int offset = (x + y*stride)*8;
943            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          if (!(MotionFlags & PMV_HALFPEL16)) {          } else {
953                  min_dx = EVEN(min_dx);                  uint32_t sadC = sad16(current->u + 2*offset,
954                  max_dx = EVEN(max_dx);                                                  reference->u + 2*offset, stride, 256*4096);
955                  min_dy = EVEN(min_dy);                  if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
956                  max_dy = EVEN(max_dy);                  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          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  static __inline void
964          //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  ZeroMacroblockP(MACROBLOCK *pMB, const int32_t sad)
965          bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);  {
966            pMB->mode = MODE_INTER;
967            pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = zeroMV;
968            pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] = pMB->qmvs[3] = zeroMV;
969            pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
970    }
971    
972          if ((x == 0) && (y == 0)) {  static __inline void
973                  threshA = 512;  ModeDecision(SearchData * const Data,
974                  threshB = 1024;                          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 {          } else {
1003                  threshA = psad[0];                          mode = MODE_INTER4V;
1004                  threshB = threshA + 256;                          sad = Data->iMinSAD[1] + Data->iMinSAD[2] +
1005                  if (threshA < 512)                                                  Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant;
1006                          threshA = 512;                          Data->iMinSAD[0] = sad;
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
1007          }          }
1008    
1009          iFound = 0;                  /* final skip decision, a.k.a. "the vector you found, really that good?" */
1010                    if (skip_possible && (pMB->sad16 < (int)iQuant * MAX_SAD00_FOR_SKIP))
1011  /* Step 4: Calculate SAD around the Median prediction.                          if ( (100*sad)/(pMB->sad16+1) > FINAL_SKIP_THRESH)
1012     MinSAD=SAD                                  if (Data->chroma || SkipDecisionP(pCurrent, pRef, x, y, Data->iEdgedWidth/2, iQuant, Data->rrv)) {
1013     If Motion Vector equal to Previous frame motion vector                                          mode = MODE_NOT_CODED;
1014     and MinSAD<PrevFrmSAD goto Step 10.                                          sad = 0;
    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);  
1015          }          }
1016    
1017          if (currMV->x > max_dx) {                  /* mcsel */
1018                  currMV->x = max_dx;                  if (coding_type == S_VOP) {
         }  
         if (currMV->x < min_dx) {  
                 currMV->x = min_dx;  
         }  
         if (currMV->y > max_dy) {  
                 currMV->y = max_dy;  
         }  
         if (currMV->y < min_dy) {  
                 currMV->y = min_dy;  
         }  
1019    
1020          iMinSAD =                          int32_t iSAD = sad16(Data->Cur,
1021                  sad16(cur,                                  vGMC->y + 16*y*Data->iEdgedWidth + 16*x, Data->iEdgedWidth, 65536);
                           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);  
1022    
1023          if ((iMinSAD < 256) ||                          if (Data->chroma) {
1024                  ((MVequal(*currMV, prevMB->mvs[0])) &&                                  iSAD += sad8(Data->CurU, vGMC->u + 8*y*(Data->iEdgedWidth/2) + 8*x, Data->iEdgedWidth/2);
1025                   ((int32_t) iMinSAD < prevMB->sad16))) {                                  iSAD += sad8(Data->CurV, vGMC->v + 8*y*(Data->iEdgedWidth/2) + 8*x, Data->iEdgedWidth/2);
                 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;  
                         }  
1026                  }                  }
1027    
1028                  if (MotionFlags & PMV_QUICKSTOP16)                          if (iSAD <= sad) {              /* mode decision GMC */
1029                          goto PMVfast16_Terminate_without_Refine;                                  mode = MODE_INTER;
1030                  if (MotionFlags & PMV_EARLYSTOP16)                                  mcsel = 1;
1031                          goto PMVfast16_Terminate_with_Refine;                                  sad = iSAD;
1032          }          }
1033    
1034                    }
1035    
1036  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion                  /* intra decision */
    vector of the median.  
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
1037    
1038          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[0])))                  if (iQuant > 8) InterBias += 100 * (iQuant - 8); /* to make high quants work */
1039                  iFound = 2;                  if (y != 0)
1040                            if ((pMB - pParam->mb_width)->mode == MODE_INTRA ) InterBias -= 80;
1041                    if (x != 0)
1042                            if ((pMB - 1)->mode == MODE_INTRA ) InterBias -= 80;
1043    
1044  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.                  if (Data->chroma) InterBias += 50; /* dev8(chroma) ??? <-- yes, we need dev8 (no big difference though) */
1045     Otherwise select large Diamond Search.                  if (Data->rrv) InterBias *= 4;
 */  
1046    
1047          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))                  if (InterBias < sad) {
1048                  iDiamondSize = 1;               // halfpel!                          int32_t deviation;
1049                            if (!Data->rrv)
1050                                    deviation = dev16(Data->Cur, Data->iEdgedWidth);
1051          else          else
1052                  iDiamondSize = 2;               // halfpel!                                  deviation = dev16(Data->Cur, Data->iEdgedWidth) + /* dev32() */
1053                                                            dev16(Data->Cur+16, Data->iEdgedWidth) +
1054                                                            dev16(Data->Cur + 16*Data->iEdgedWidth, Data->iEdgedWidth) +
1055                                                            dev16(Data->Cur+16+16*Data->iEdgedWidth, Data->iEdgedWidth);
1056    
1057          if (!(MotionFlags & PMV_HALFPELDIAMOND16))                          if (deviation < (sad - InterBias)) mode = MODE_INTRA;
1058                  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;  
1059    
1060  // previous frame MV is always possible                  pMB->cbp = 63;
1061                    pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
1062    
1063          if (!MVzero(prevMB->mvs[0]))          } else { /* Rate-Distortion */
                 if (!MVequal(prevMB->mvs[0], pmv[0]))  
                         CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);  
1064    
1065  // left neighbour, if allowed                  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          if (!MVzero(pmv[1]))                  v = Data->qpel ? Data->currentQMV : Data->currentMV;
1071                  if (!MVequal(pmv[1], prevMB->mvs[0]))                  for (i = 0; i < 5; i++) {
1072                          if (!MVequal(pmv[1], pmv[0])) {                          Data->iMinSAD[i] = 256*4096;
1073                                  if (!(MotionFlags & PMV_HALFPEL16)) {                          backup[i] = v[i];
                                         pmv[1].x = EVEN(pmv[1].x);  
                                         pmv[1].y = EVEN(pmv[1].y);  
1074                                  }                                  }
1075    
1076                                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);                  min_rd = findRDinter(Data, pMBs, x, y, pParam, MotionFlags);
1077                    cbp = *Data->cbp;
1078    
1079                    if (coding_type == S_VOP) {
1080                            int gmc_rd;
1081                            *Data->iMinSAD = min_rd += BITS_MULT*1; /* mcsel */
1082                            gmc_rd = findRDgmc(Data, vGMC, x, y);
1083                            if (gmc_rd < min_rd) {
1084                                    mcsel = 1;
1085                                    *Data->iMinSAD = min_rd = gmc_rd;
1086                                    mode = MODE_INTER;
1087                                    cbp = *Data->cbp;
1088                          }                          }
 // top neighbour, if allowed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], prevMB->mvs[0]))  
                         if (!MVequal(pmv[2], pmv[0]))  
                                 if (!MVequal(pmv[2], pmv[1])) {  
                                         if (!(MotionFlags & PMV_HALFPEL16)) {  
                                                 pmv[2].x = EVEN(pmv[2].x);  
                                                 pmv[2].y = EVEN(pmv[2].y);  
1089                                          }                                          }
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
1090    
1091  // top right neighbour, if allowed                  if (inter4v) {
1092                                          if (!MVzero(pmv[3]))                          int v4_rd;
1093                                                  if (!MVequal(pmv[3], prevMB->mvs[0]))                          v4_rd = findRDinter4v(Data, pMB, pMBs, x, y, pParam, MotionFlags, backup);
1094                                                          if (!MVequal(pmv[3], pmv[0]))                          if (v4_rd < min_rd) {
1095                                                                  if (!MVequal(pmv[3], pmv[1]))                                  Data->iMinSAD[0] = min_rd = v4_rd;
1096                                                                          if (!MVequal(pmv[3], pmv[2])) {                                  mode = MODE_INTER4V;
1097                                                                                  if (!(MotionFlags & PMV_HALFPEL16)) {                                  cbp = *Data->cbp;
                                                                                         pmv[3].x = EVEN(pmv[3].x);  
                                                                                         pmv[3].y = EVEN(pmv[3].y);  
                                                                                 }  
                                                                                 CHECK_MV16_CANDIDATE(pmv[3].x,  
                                                                                                                          pmv[3].y);  
1098                                                                          }                                                                          }
1099                                  }                                  }
1100    
1101          if ((MVzero(*currMV)) &&                  intra_rd = findRDintra(Data);
1102                  (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )                  if (intra_rd < min_rd) {
1103                  iMinSAD -= MV16_00_BIAS;                          *Data->iMinSAD = min_rd = intra_rd;
1104                            mode = MODE_INTRA;
1105                    }
1106    
1107  /* Step 6: If MinSAD <= thresa goto Step 10.                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = 0;
1108     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.                  pMB->cbp = cbp;
1109  */          }
1110    
1111          if ((iMinSAD <= threshA) ||          if (Data->rrv) {
1112                  (MVequal(*currMV, prevMB->mvs[0]) &&                          Data->currentMV[0].x = RRV_MV_SCALEDOWN(Data->currentMV[0].x);
1113                   ((int32_t) iMinSAD < prevMB->sad16))) {                          Data->currentMV[0].y = RRV_MV_SCALEDOWN(Data->currentMV[0].y);
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
1114          }          }
1115    
1116            if (mode == MODE_INTER && mcsel == 0) {
1117                    pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
1118    
1119  /************ (Diamond Search)  **************/                  if(Data->qpel) {
1120  /*                          pMB->qmvs[0] = pMB->qmvs[1]
1121     Step 7: Perform Diamond search, with either the small or large diamond.                                  = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1122     If Found=2 only examine one Diamond pattern, and afterwards goto step 10                          pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1123     Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.                          pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;
1124     If center then goto step 10.                  } else {
1125     Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.                          pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1126     Refine by using small diamond and goto step 10.                          pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
1127  */                  }
1128    
1129          if (MotionFlags & PMV_USESQUARES16)          } else if (mode == MODE_INTER ) { // but mcsel == 1
                 MainSearchPtr = Square16_MainSearch;  
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
1130    
1131          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                  pMB->mcsel = 1;
1132                    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    
1147  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  bool
1148          iSAD =  MotionEstimation(MBParam * const pParam,
1149                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                   FRAMEINFO * const current,
1150                                                    currMV->x, currMV->y, iMinSAD, &newMV, center_x, center_y,                                   FRAMEINFO * const reference,
1151                                                    min_dx, max_dx,                                   const IMAGE * const pRefH,
1152                                                    min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,                                   const IMAGE * const pRefV,
1153                                                    iQuant, iFound);                                   const IMAGE * const pRefHV,
1154                                    const IMAGE * const pGMC,
1155                                     const uint32_t iLimit)
1156    {
1157            MACROBLOCK *const pMBs = current->mbs;
1158            const IMAGE *const pCurrent = &current->image;
1159            const IMAGE *const pRef = &reference->image;
1160    
1161          if (iSAD < iMinSAD) {          uint32_t mb_width = pParam->mb_width;
1162                  *currMV = newMV;          uint32_t mb_height = pParam->mb_height;
1163                  iMinSAD = iSAD;          const uint32_t iEdgedWidth = pParam->edged_width;
1164            const uint32_t MotionFlags = MakeGoodMotionFlags(current->motion_flags, current->vop_flags, current->vol_flags);
1165    
1166            uint32_t x, y;
1167            uint32_t iIntra = 0;
1168            int32_t sad00;
1169            int skip_thresh = INITIAL_SKIP_THRESH * \
1170                    (current->vop_flags & XVID_VOP_REDUCED ? 4:1) * \
1171                    (current->vop_flags & XVID_VOP_MODEDECISION_RD ? 2:1);
1172    
1173            /* some pre-initialized thingies for SearchP */
1174            int32_t temp[8]; uint32_t dir;
1175            VECTOR currentMV[5];
1176            VECTOR currentQMV[5];
1177            int32_t iMinSAD[5];
1178            DECLARE_ALIGNED_MATRIX(dct_space, 3, 64, int16_t, CACHE_LINE);
1179            SearchData Data;
1180            memset(&Data, 0, sizeof(SearchData));
1181            Data.iEdgedWidth = iEdgedWidth;
1182            Data.currentMV = currentMV;
1183            Data.currentQMV = currentQMV;
1184            Data.iMinSAD = iMinSAD;
1185            Data.temp = temp;
1186            Data.dir = &dir;
1187            Data.iFcode = current->fcode;
1188            Data.rounding = pParam->m_rounding_type;
1189            Data.qpel = (current->vol_flags & XVID_VOL_QUARTERPEL ? 1:0);
1190            Data.chroma = MotionFlags & XVID_ME_CHROMA_PVOP;
1191            Data.rrv = (current->vop_flags & XVID_VOP_REDUCED) ? 1:0;
1192            Data.dctSpace = dct_space;
1193            Data.quant_type = !(pParam->vol_flags & XVID_VOL_MPEGQUANT);
1194    
1195            if ((current->vop_flags & XVID_VOP_REDUCED)) {
1196                    mb_width = (pParam->width + 31) / 32;
1197                    mb_height = (pParam->height + 31) / 32;
1198                    Data.qpel = 0;
1199            }
1200    
1201            Data.RefQ = pRefV->u; /* a good place, also used in MC (for similar purpose) */
1202            if (sadInit) (*sadInit) ();
1203    
1204            for (y = 0; y < mb_height; y++) {
1205                    for (x = 0; x < mb_width; x++)  {
1206                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1207    
1208                            if (!Data.rrv) pMB->sad16 =
1209                                    sad16v(pCurrent->y + (x + y * iEdgedWidth) * 16,
1210                                                            pRef->y + (x + y * iEdgedWidth) * 16,
1211                                                            pParam->edged_width, pMB->sad8 );
1212    
1213                            else pMB->sad16 =
1214                                    sad32v_c(pCurrent->y + (x + y * iEdgedWidth) * 32,
1215                                                            pRef->y + (x + y * iEdgedWidth) * 32,
1216                                                            pParam->edged_width, pMB->sad8 );
1217    
1218                            if (Data.chroma) {
1219                                    Data.temp[7] = sad8(pCurrent->u + x*8 + y*(iEdgedWidth/2)*8,
1220                                                                            pRef->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2)
1221                                                                    + sad8(pCurrent->v + (x + y*(iEdgedWidth/2))*8,
1222                                                                            pRef->v + (x + y*(iEdgedWidth/2))*8, iEdgedWidth/2);
1223                                    pMB->sad16 += Data.temp[7];
1224                            }
1225    
1226                            sad00 = pMB->sad16;
1227    
1228                            /* initial skip decision */
1229                            /* no early skip for GMC (global vector = skip vector is unknown!)  */
1230                            if (current->coding_type != S_VOP)      { /* no fast SKIP for S(GMC)-VOPs */
1231                                    if (pMB->dquant == 0 && sad00 < pMB->quant * skip_thresh)
1232                                            if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, iEdgedWidth/2, pMB->quant, Data.rrv)) {
1233                                                    ZeroMacroblockP(pMB, sad00);
1234                                                    pMB->mode = MODE_NOT_CODED;
1235                                                    continue;
1236                                            }
1237          }          }
1238    
1239          if (MotionFlags & PMV_EXTSEARCH16) {                          if ((current->vop_flags & XVID_VOP_CARTOON) &&
1240  /* extended: search (up to) two more times: orignal prediction and (0,0) */                                  (sad00 < pMB->quant * 4 * skip_thresh)) { /* favorize (0,0) vector for cartoons */
1241                                    ZeroMacroblockP(pMB, sad00);
1242                                    continue;
1243                            }
1244    
1245                  if (!(MVequal(pmv[0], backupMV))) {                          SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1246                          iSAD =                                          y, MotionFlags, current->vop_flags, current->vol_flags,
1247                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                          &Data, pParam, pMBs, reference->mbs, pMB);
1248                                                                    center_x, center_y, iMinSAD, &newMV, center_x, center_y,  
1249                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,                          ModeDecision(&Data, pMB, pMBs, x, y, pParam,
1250                                                                    iDiamondSize, iFcode, iQuant, iFound);                                                   MotionFlags, current->vop_flags, current->vol_flags,
1251                                                     pCurrent, pRef, pGMC, current->coding_type);
1252    
1253                          if (iSAD < iMinSAD) {                          if (pMB->mode == MODE_INTRA)
1254                                  *currMV = newMV;                                  if (++iIntra > iLimit) return 1;
                                 iMinSAD = iSAD;  
1255                          }                          }
1256                  }                  }
1257    
1258                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          return 0;
1259                          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);  
1260    
1261                          if (iSAD < iMinSAD) {  /* check if given vector is equal to any vector checked before */
1262                                  *currMV = newMV;  static __inline int
1263                                  iMinSAD = iSAD;  vector_repeats(const VECTOR * const pmv, const int i)
1264    {
1265            unsigned int j;
1266            for (j = 0; j < i; j++)
1267                    if (MVequal(pmv[i], pmv[j])) return 1; /* same vector has been checked already */
1268            return 0;
1269    }
1270    
1271    /*      make a binary mask that prevents diamonds/squares
1272            from checking a vector which has been checked as a prediction */
1273    static __inline int
1274    make_mask(const VECTOR * const pmv, const int i, const int current)
1275    {
1276            unsigned int mask = 255, j;
1277            for (j = 0; j < i; j++) {
1278                    if (pmv[current].x == pmv[j].x) {
1279                            if (pmv[current].y == pmv[j].y + iDiamondSize) mask &= ~4;
1280                            else if (pmv[current].y == pmv[j].y - iDiamondSize) mask &= ~8;
1281                    } else
1282                            if (pmv[current].y == pmv[j].y) {
1283                                    if (pmv[current].x == pmv[j].x + iDiamondSize) mask &= ~1;
1284                                    else if (pmv[current].x == pmv[j].x - iDiamondSize) mask &= ~2;
1285                          }                          }
1286                  }                  }
1287            return mask;
1288          }          }
1289    
1290  /*  static __inline void
1291     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  PreparePredictionsP(VECTOR * const pmv, int x, int y, int iWcount,
1292  */                          int iHcount, const MACROBLOCK * const prevMB, int rrv)
1293    {
1294            /* this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself */
1295            if (rrv) { iWcount /= 2; iHcount /= 2; }
1296    
1297    PMVfast16_Terminate_with_Refine:          if ( (y != 0) && (x < (iWcount-1)) ) {          /* [5] top-right neighbour */
1298          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step                  pmv[5].x = EVEN(pmv[3].x);
1299                  iMinSAD =                  pmv[5].y = EVEN(pmv[3].y);
1300                          Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,          } else pmv[5].x = pmv[5].y = 0;
                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
1301    
1302    PMVfast16_Terminate_without_Refine:          if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }/* pmv[3] is left neighbour */
1303          currPMV->x = currMV->x - center_x;          else pmv[3].x = pmv[3].y = 0;
         currPMV->y = currMV->y - center_y;  
         return iMinSAD;  
 }  
1304    
1305            if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }/* [4] top neighbour */
1306            else pmv[4].x = pmv[4].y = 0;
1307    
1308            /* [1] median prediction */
1309            pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
1310    
1311            pmv[0].x = pmv[0].y = 0; /* [0] is zero; not used in the loop (checked before) but needed here for make_mask */
1312    
1313            pmv[2].x = EVEN(prevMB->mvs[0].x); /* [2] is last frame */
1314            pmv[2].y = EVEN(prevMB->mvs[0].y);
1315    
1316            if ((x < iWcount-1) && (y < iHcount-1)) {
1317                    pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); /* [6] right-down neighbour in last frame */
1318                    pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
1319            } else pmv[6].x = pmv[6].y = 0;
1320    
1321  int32_t          if (rrv) {
1322  Diamond8_MainSearch(const uint8_t * const pRef,                  int i;
1323                                          const uint8_t * const pRefH,                  for (i = 0; i < 7; i++) {
1324                                          const uint8_t * const pRefV,                          pmv[i].x = RRV_MV_SCALEUP(pmv[i].x);
1325                                          const uint8_t * const pRefHV,                          pmv[i].y = RRV_MV_SCALEUP(pmv[i].y);
                                         const uint8_t * const cur,  
                                         const int x,  
                                         const int y,  
                                         int32_t start_x,  
                                         int32_t start_y,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iDirectionBackup;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
   
         if (iDirection) {  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;     // since iDirection!=0, this is well defined!  
                         iDirectionBackup = iDirection;  
   
                         if (iDirectionBackup != 2)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                   backupMV.y, 1);  
                         if (iDirectionBackup != 1)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                   backupMV.y, 2);  
                         if (iDirectionBackup != 4)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y - iDiamondSize, 3);  
                         if (iDirectionBackup != 3)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y + iDiamondSize, 4);  
1326                  }                  }
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
1327          }          }
         return iMinSAD;  
1328  }  }
1329    
1330    static void
1331    SearchP(const IMAGE * const pRef,
   
 int32_t  
 Square8_MainSearch(const uint8_t * 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 uint8_t * const cur,                  const IMAGE * const pCur,
1336                                          const int x,                                          const int x,
1337                                          const int y,                                          const int y,
1338                                          int32_t start_x,                  const uint32_t MotionFlags,
1339                                          int32_t start_y,                  const uint32_t VopFlags,
1340                                          int32_t iMinSAD,                  const uint32_t VolFlags,
1341                                          VECTOR * const currMV,                  SearchData * const Data,
1342                                     const int center_x,                  const MBParam * const pParam,
1343                                     const int center_y,                  const MACROBLOCK * const pMBs,
1344                                          const int32_t min_dx,                  const MACROBLOCK * const prevMBs,
1345                                          const int32_t max_dx,                  MACROBLOCK * const pMB)
1346                                          const int32_t min_dy,  {
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a square search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* It's one search with full square pattern, and new parts for all following diamonds */  
   
 /*   new direction are extra, so 1-4 is normal diamond  
       537  
       1*2  
       648  
 */  
1347    
1348          CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);          int i, threshA;
1349          CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);          VECTOR pmv[7];
1350          CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);          int inter4v = (VopFlags & XVID_VOP_INTER4V) && (pMB->dquant == 0);
1351          CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);          CheckFunc * CheckCandidate;
1352    
1353          CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
1354                                                           backupMV.y - iDiamondSize, 5);                                                  pParam->width, pParam->height, Data->iFcode - Data->qpel, 1, Data->rrv);
1355          CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
1356                                                           backupMV.y + iDiamondSize, 6);          get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);
1357          CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
1358                                                           backupMV.y - iDiamondSize, 7);          Data->temp[5] = Data->temp[6] = 0; /* chroma-sad cache */
1359          CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,          i = Data->rrv ? 2 : 1;
1360                                                           backupMV.y + iDiamondSize, 8);          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          if (iDirection) {  
1364                  while (!iFound) {          Data->RefP[0] = pRef->y + (x + Data->iEdgedWidth*y) * 16*i;
1365                          iFound = 1;          Data->RefP[2] = pRefH + (x + Data->iEdgedWidth*y) * 16*i;
1366                          backupMV = *currMV;          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                          switch (iDirection) {          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
1396                          case 1:                                          prevMBs + x + y * pParam->mb_width, Data->rrv);
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                    backupMV.y, 1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
                         case 2:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
1397    
1398                          case 3:          if (!Data->rrv) {
1399                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                  if (inter4v) CheckCandidate = CheckCandidate16;
1400                                                                                   4);                          else CheckCandidate = CheckCandidate16no4v; /* for extra speed */
1401                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,          } else CheckCandidate = CheckCandidate32;
1402                                                                                   backupMV.y - iDiamondSize, 7);  
1403                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  /* main loop. checking all predictions (but first, which is 0,0 and has been checked in MotionEstimation())*/
1404                                                                                   backupMV.y + iDiamondSize, 8);  
1405                                  break;          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                          case 4:                  MainSearchFunc * MainSearchPtr;
1418                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,                  int mask = make_mask(pmv, i, *Data->dir); // all vectors pmv[0..i-1] have been checked
                                                                                  3);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 break;  
   
                         case 5:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
   
                         case 6:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
   
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
1419    
1420                                  break;                  if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1421                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1422                            else MainSearchPtr = DiamondSearch;
1423    
1424                          case 7:                  MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, mask, CheckCandidate);
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                    backupMV.y, 1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
1425    
1426                          case 8:  /* extended search, diamond starting in 0,0 and in prediction.
1427                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,          note that this search is/might be done in halfpel positions,
1428                                                                                   2);          which makes it more different than the diamond above */
1429                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
1430                                                                                   4);                  if (MotionFlags & XVID_ME_EXTSEARCH16) {
1431                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          int32_t bSAD;
1432                                                                                   backupMV.y + iDiamondSize, 6);                          VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
1433                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                          if (Data->rrv) {
1434                                                                                   backupMV.y - iDiamondSize, 7);                                  startMV.x = RRV_MV_SCALEUP(startMV.x);
1435                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                                  startMV.y = RRV_MV_SCALEUP(startMV.y);
1436                                                                                   backupMV.y + iDiamondSize, 8);                          }
1437                                  break;                          if (!(MVequal(startMV, backupMV))) {
1438                          default:                                  bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1439                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
1440                                                                                   1);                                  CheckCandidate(startMV.x, startMV.y, Data, 255);
1441                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,                                  MainSearchPtr(startMV.x, startMV.y, Data, 255, CheckCandidate);
1442                                                                                   2);                                  if (bSAD < Data->iMinSAD[0]) {
1443                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,                                          Data->currentMV[0] = backupMV;
1444                                                                                   3);                                          Data->iMinSAD[0] = bSAD; }
1445                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                          }
1446                                                                                   4);  
1447                            backupMV = Data->currentMV[0];
1448                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          startMV.x = startMV.y = 1;
1449                                                                                   backupMV.y - iDiamondSize, 5);                          if (!(MVequal(startMV, backupMV))) {
1450                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                                  bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1451                                                                                   backupMV.y + iDiamondSize, 6);  
1452                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                                  CheckCandidate(startMV.x, startMV.y, Data, 255);
1453                                                                                   backupMV.y - iDiamondSize, 7);                                  MainSearchPtr(startMV.x, startMV.y, Data, 255, CheckCandidate);
1454                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                                  if (bSAD < Data->iMinSAD[0]) {
1455                                                                                   backupMV.y + iDiamondSize, 8);                                          Data->currentMV[0] = backupMV;
1456                                  break;                                          Data->iMinSAD[0] = bSAD;
1457                          }                          }
1458                  }                  }
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
1459          }          }
         return iMinSAD;  
1460  }  }
1461    
1462            if (MotionFlags & XVID_ME_HALFPELREFINE16)
1463                            SubpelRefine(Data, CheckCandidate);
1464    
1465            for(i = 0; i < 5; i++) {
1466                    Data->currentQMV[i].x = 2 * Data->currentMV[i].x; /* initialize qpel vectors */
1467                    Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
1468            }
1469    
1470            if (Data->qpel) {
1471                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
1472                                    pParam->width, pParam->height, Data->iFcode, 2, 0);
1473                    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  int32_t          if (inter4v) {
1482  Halfpel8_Refine_c(const uint8_t * const pRef,                  SearchData Data8;
1483                                  const uint8_t * const pRefH,                  memcpy(&Data8, Data, sizeof(SearchData)); /* quick copy of common data */
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const uint8_t * const cur,  
                                 const int x,  
                                 const int y,  
                                 VECTOR * const currMV,  
                                 int32_t iMinSAD,  
                            const int center_x,  
                            const int center_y,  
                                 const int32_t min_dx,  
                                 const int32_t max_dx,  
                                 const int32_t min_dy,  
                                 const int32_t max_dy,  
                                 const int32_t iFcode,  
                                 const int32_t iQuant,  
                                 const int32_t iEdgedWidth)  
 {  
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
   
         int32_t iSAD;  
         VECTOR backupMV = *currMV;  
   
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y + 1);  
         CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y + 1);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y + 1);  
1484    
1485          return iMinSAD;                  Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
1486  }                  Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
1487                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
1488                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
1489    
1490                    if ((Data->chroma) && (!(VopFlags & XVID_VOP_MODEDECISION_RD))) {
1491                            /* chroma is only used for comparsion to INTER. if the comparsion will be done in BITS domain, it will not be used */
1492                            int sumx = 0, sumy = 0;
1493    
1494  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)                          if (Data->qpel)
1495                                    for (i = 1; i < 5; i++) {
1496                                            sumx += Data->currentQMV[i].x/2;
1497                                            sumy += Data->currentQMV[i].y/2;
1498                                    }
1499                            else
1500                                    for (i = 1; i < 5; i++) {
1501                                            sumx += Data->currentMV[i].x;
1502                                            sumy += Data->currentMV[i].y;
1503                                    }
1504    
1505  int32_t                          Data->iMinSAD[1] += ChromaSAD(  (sumx >> 3) + roundtab_76[sumx & 0xf],
1506  PMVfastSearch8(const uint8_t * const pRef,                                                                                          (sumy >> 3) + roundtab_76[sumy & 0xf], Data);
1507                             const uint8_t * const pRefH,                  }
1508                             const uint8_t * const pRefV,          } else Data->iMinSAD[1] = 4096*256;
1509                             const uint8_t * const pRefHV,  }
1510                             const IMAGE * const pCur,  
1511                             const int x,  static void
1512                             const int y,  Search8(const SearchData * const OldData,
1513                             const int start_x,                  const int x, const int y,
                            const int start_y,  
                                 const int center_x,  
                                 const int center_y,  
1514                             const uint32_t MotionFlags,                             const uint32_t MotionFlags,
                            const uint32_t iQuant,  
                            const uint32_t iFcode,  
1515                             const MBParam * const pParam,                             const MBParam * const pParam,
1516                    MACROBLOCK * const pMB,
1517                             const MACROBLOCK * const pMBs,                             const MACROBLOCK * const pMBs,
1518                             const MACROBLOCK * const prevMBs,                  const int block,
1519                             VECTOR * const currMV,                  SearchData * const Data)
                            VECTOR * const currPMV)  
1520  {  {
1521          const uint32_t iWcount = pParam->mb_width;          int i = 0;
1522          const int32_t iWidth = pParam->width;          CheckFunc * CheckCandidate;
1523          const int32_t iHeight = pParam->height;          Data->iMinSAD = OldData->iMinSAD + 1 + block;
1524          const int32_t iEdgedWidth = pParam->edged_width;          Data->currentMV = OldData->currentMV + 1 + block;
1525            Data->currentQMV = OldData->currentQMV + 1 + block;
1526    
1527            if(Data->qpel) {
1528                    Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1529                    if (block != 0) i = d_mv_bits(  Data->currentQMV->x, Data->currentQMV->y,
1530                                                                                    Data->predMV, Data->iFcode, 0, 0);
1531            } else {
1532                    Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1533                    if (block != 0) i = d_mv_bits(  Data->currentMV->x, Data->currentMV->y,
1534                                                                                    Data->predMV, Data->iFcode, 0, Data->rrv);
1535            }
1536    
1537            *(Data->iMinSAD) += (Data->lambda8 * i * (*Data->iMinSAD + NEIGH_8X8_BIAS))>>10;
1538    
1539          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;          if (MotionFlags & (XVID_ME_EXTSEARCH8|XVID_ME_HALFPELREFINE8|XVID_ME_QUARTERPELREFINE8)) {
1540    
1541          int32_t iDiamondSize;                  if (Data->rrv) i = 16; else i = 8;
1542    
1543          int32_t min_dx;                  Data->RefP[0] = OldData->RefP[0] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1544          int32_t max_dx;                  Data->RefP[1] = OldData->RefP[1] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1545          int32_t min_dy;                  Data->RefP[2] = OldData->RefP[2] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1546          int32_t max_dy;                  Data->RefP[3] = OldData->RefP[3] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1547    
1548          VECTOR pmv[4];                  Data->Cur = OldData->Cur + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1549          int32_t psad[4];                  Data->qpel_precision = 0;
         VECTOR newMV;  
         VECTOR backupMV;  
         VECTOR startMV;  
1550    
1551  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 3,
1552          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;                                          pParam->width, pParam->height, Data->iFcode - Data->qpel, 1, Data->rrv);
1553    
1554           int32_t threshA, threshB;                  if (!Data->rrv) CheckCandidate = CheckCandidate8;
1555          int32_t iFound, bPredEq;                  else CheckCandidate = CheckCandidate16no4v;
         int32_t iMinSAD, iSAD;  
1556    
1557          int32_t iSubBlock = (y & 1) + (y & 1) + (x & 1);                  if (MotionFlags & XVID_ME_EXTSEARCH8 && (!(MotionFlags & XVID_ME_EXTSEARCH_RD))) {
1558                            int32_t temp_sad = *(Data->iMinSAD); /* store current MinSAD */
1559    
1560          MainSearch8FuncPtr MainSearchPtr;                          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          /* Init variables */                          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, 255, CheckCandidate);
         startMV.x = start_x;  
         startMV.y = start_y;  
1566    
1567          /* Get maximum range */                          if(*(Data->iMinSAD) < temp_sad) {
1568          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,                                          Data->currentQMV->x = 2 * Data->currentMV->x; /* update our qpel vector */
1569                            iFcode);                                          Data->currentQMV->y = 2 * Data->currentMV->y;
1570                            }
1571                    }
1572    
1573                    if (MotionFlags & XVID_ME_HALFPELREFINE8) {
1574                            int32_t temp_sad = *(Data->iMinSAD); /* store current MinSAD */
1575    
1576          if (!(MotionFlags & PMV_HALFPELDIAMOND8)) {                          SubpelRefine(Data, CheckCandidate); /* perform halfpel refine of current best vector */
1577                  min_dx = EVEN(min_dx);  
1578                  max_dx = EVEN(max_dx);                          if(*(Data->iMinSAD) < temp_sad) { /* we have found a better match */
1579                  min_dy = EVEN(min_dy);                                  Data->currentQMV->x = 2 * Data->currentMV->x; /* update our qpel vector */
1580                  max_dy = EVEN(max_dy);                                  Data->currentQMV->y = 2 * Data->currentMV->y;
1581                            }
1582          }          }
1583    
1584          /* because we might use IF (dx>max_dx) THEN dx=max_dx; */                  if (Data->qpel && MotionFlags & XVID_ME_QUARTERPELREFINE8) {
1585          //bPredEq = get_pmvdata(pMBs, (x >> 1), (y >> 1), iWcount, iSubBlock, pmv, psad);                                  Data->qpel_precision = 1;
1586          bPredEq = get_pmvdata2(pMBs, iWcount, 0, (x >> 1), (y >> 1), iSubBlock, pmv, psad);                                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 3,
1587                                            pParam->width, pParam->height, Data->iFcode, 2, 0);
1588                                    SubpelRefine(Data, CheckCandidate);
1589                    }
1590            }
1591    
1592          if ((x == 0) && (y == 0)) {          if (Data->rrv) {
1593                  threshA = 512 / 4;                          Data->currentMV->x = RRV_MV_SCALEDOWN(Data->currentMV->x);
1594                  threshB = 1024 / 4;                          Data->currentMV->y = RRV_MV_SCALEDOWN(Data->currentMV->y);
1595            }
1596    
1597            if(Data->qpel) {
1598                    pMB->pmvs[block].x = Data->currentQMV->x - Data->predMV.x;
1599                    pMB->pmvs[block].y = Data->currentQMV->y - Data->predMV.y;
1600                    pMB->qmvs[block] = *Data->currentQMV;
1601          } else {          } else {
1602                  threshA = psad[0] / 4;  /* good estimate? */                  pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1603                  threshB = threshA + 256 / 4;                  pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
1604                  if (threshA < 512 / 4)          }
                         threshA = 512 / 4;  
                 if (threshA > 1024 / 4)  
                         threshA = 1024 / 4;  
                 if (threshB > 1792 / 4)  
                         threshB = 1792 / 4;  
         }  
   
         iFound = 0;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
1605    
1606            pMB->mvs[block] = *Data->currentMV;
1607            pMB->sad8[block] = 4 * *Data->iMinSAD;
1608    }
1609    
1610  // Prepare for main loop  /* motion estimation for B-frames */
1611    
1612    if (MotionFlags & PMV_USESQUARES8)  static __inline VECTOR
1613        MainSearchPtr = Square8_MainSearch;  ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1614    else  {
1615    /* the stupidiest function ever */
1616            return (mode == MODE_FORWARD ? pMB->mvs[0] : pMB->b_mvs[0]);
1617    }
1618    
1619          if (MotionFlags & PMV_ADVANCEDDIAMOND8)  static void __inline
1620                  MainSearchPtr = AdvDiamond8_MainSearch;  PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
1621          else                                                          const uint32_t iWcount,
1622                  MainSearchPtr = Diamond8_MainSearch;                                                          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          *currMV = startMV;          pmv[1].x = pmv[1].y = 0; /* [1] is zero */
1630    
1631          iMinSAD =          pmv[2] = ChoosePred(pMB, mode_curr);
1632                  sad8(cur,          pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
                          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  
 */  
1633    
1634          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[iSubBlock])))          if ((y != 0)&&(x != (int)(iWcount+1))) {                        /* [3] top-right neighbour */
1635                  iFound = 2;                  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            if (y != 0) {
1640                    pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
1641                    pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
1642            } else pmv[4].x = pmv[4].y = 0;
1643    
1644            if (x != 0) {
1645                    pmv[5] = ChoosePred(pMB-1, mode_curr);
1646                    pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1647            } else pmv[5].x = pmv[5].y = 0;
1648    
1649            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    
 /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.  
    Otherwise select large Diamond Search.  
 */  
1655    
1656          if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))  /* search backward or forward */
1657                  iDiamondSize = 1;               // 1 halfpel!  static void
1658    SearchBF(       const IMAGE * const pRef,
1659                            const uint8_t * const pRefH,
1660                            const uint8_t * const pRefV,
1661                            const uint8_t * const pRefHV,
1662                            const IMAGE * const pCur,
1663                            const int x, const int y,
1664                            const uint32_t MotionFlags,
1665                            const uint32_t iFcode,
1666                            const MBParam * const pParam,
1667                            MACROBLOCK * const pMB,
1668                            const VECTOR * const predMV,
1669                            int32_t * const best_sad,
1670                            const int32_t mode_current,
1671                            SearchData * const Data)
1672    {
1673    
1674            int i;
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            Data->predMV = *predMV;
1690    
1691            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
1692                                    pParam->width, pParam->height, iFcode - Data->qpel, 1, 0);
1693    
1694            pmv[0] = Data->predMV;
1695            if (Data->qpel) { pmv[0].x /= 2; pmv[0].y /= 2; }
1696    
1697            PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);
1698    
1699            Data->currentMV->x = Data->currentMV->y = 0;
1700    
1701            /* 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            if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1707            else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1708                    else MainSearchPtr = DiamondSearch;
1709    
1710            if (*Data->iMinSAD > 512) {
1711                    unsigned int mask = make_mask(pmv, 7, *Data->dir);
1712                    MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, mask, CheckCandidate16no4v);
1713            }
1714    
1715            SubpelRefine(Data, CheckCandidate16no4v);
1716    
1717            if (Data->qpel && *Data->iMinSAD < *best_sad + 300) {
1718                    Data->currentQMV->x = 2*Data->currentMV->x;
1719                    Data->currentQMV->y = 2*Data->currentMV->y;
1720                    Data->qpel_precision = 1;
1721                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
1722                                            pParam->width, pParam->height, iFcode, 2, 0);
1723                    SubpelRefine(Data, CheckCandidate16no4v);
1724            }
1725    
1726            /* three bits are needed to code backward mode. four for forward */
1727    
1728            if (mode_current == MODE_FORWARD) *Data->iMinSAD += 4 * Data->lambda16;
1729            else *Data->iMinSAD += 3 * Data->lambda16;
1730    
1731            if (*Data->iMinSAD < *best_sad) {
1732                    *best_sad = *Data->iMinSAD;
1733                    pMB->mode = mode_current;
1734                    if (Data->qpel) {
1735                            pMB->pmvs[0].x = Data->currentQMV->x - predMV->x;
1736                            pMB->pmvs[0].y = Data->currentQMV->y - predMV->y;
1737                            if (mode_current == MODE_FORWARD)
1738                                    pMB->qmvs[0] = *Data->currentQMV;
1739          else          else
1740                  iDiamondSize = 2;               // 2 halfpel = 1 full pixel!                                  pMB->b_qmvs[0] = *Data->currentQMV;
1741                    } else {
1742                            pMB->pmvs[0].x = Data->currentMV->x - predMV->x;
1743                            pMB->pmvs[0].y = Data->currentMV->y - predMV->y;
1744                    }
1745                    if (mode_current == MODE_FORWARD) pMB->mvs[0] = *Data->currentMV;
1746                    else pMB->b_mvs[0] = *Data->currentMV;
1747            }
1748    
1749          if (!(MotionFlags & PMV_HALFPELDIAMOND8))          if (mode_current == MODE_FORWARD) *(Data->currentMV+2) = *Data->currentMV;
1750                  iDiamondSize *= 2;          else *(Data->currentMV+1) = *Data->currentMV; /* we store currmv for interpolate search */
1751    }
1752    
1753    static void
1754    SkipDecisionB(const IMAGE * const pCur,
1755                                    const IMAGE * const f_Ref,
1756                                    const IMAGE * const b_Ref,
1757                                    MACROBLOCK * const pMB,
1758                                    const uint32_t x, const uint32_t y,
1759                                    const SearchData * const Data)
1760    {
1761            int dx = 0, dy = 0, b_dx = 0, b_dy = 0;
1762            int32_t sum;
1763            int k;
1764            const uint32_t stride = Data->iEdgedWidth/2;
1765            /* this is not full chroma compensation, only it's fullpel approximation. should work though */
1766    
1767            for (k = 0; k < 4; k++) {
1768                    dy += Data->directmvF[k].y >> Data->qpel;
1769                    dx += Data->directmvF[k].x >> Data->qpel;
1770                    b_dy += Data->directmvB[k].y >> Data->qpel;
1771                    b_dx += Data->directmvB[k].x >> Data->qpel;
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 * Data->iQuant) return; /* no skip */
1785    
1786            sum += sad8bi(pCur->v + 8*x + 8 * y * stride,
1787                                            f_Ref->v + (y*8 + dy/2) * stride + x*8 + dx/2,
1788                                            b_Ref->v + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1789                                            stride);
1790    
1791  /*          if (sum < MAX_CHROMA_SAD_FOR_SKIP * Data->iQuant) {
1792     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.                  pMB->mode = MODE_DIRECT_NONE_MV; /* skipped */
1793     Also calculate (0,0) but do not subtract offset.                  for (k = 0; k < 4; k++) {
1794     Let MinSAD be the smallest SAD up to this point.                          pMB->qmvs[k] = pMB->mvs[k];
1795     If MV is (0,0) subtract offset.                          pMB->b_qmvs[k] = pMB->b_mvs[k];
1796  */                  }
1797            }
1798    }
1799    
1800    static __inline uint32_t
1801    SearchDirect(const IMAGE * const f_Ref,
1802                                    const uint8_t * const f_RefH,
1803                                    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  // the median prediction might be even better than mv16          Data->referencemv = Data->qpel ? b_mb->qmvs : b_mb->mvs;
1846            Data->qpel_precision = 0;
1847    
1848          if (!MVequal(pmv[0], startMV))          for (k = 0; k < 4; k++) {
1849                  CHECK_MV8_CANDIDATE(center_x, center_y);                  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  // (0,0) if needed                  if ( (pMB->b_mvs[k].x > Data->max_dx) | (pMB->b_mvs[k].x < Data->min_dx)
1855          if (!MVzero(pmv[0]))                          | (pMB->b_mvs[k].y > Data->max_dy) | (pMB->b_mvs[k].y < Data->min_dy) ) {
                 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;  
1856    
1857                            *best_sad = 256*4096; /* in that case, we won't use direct mode */
1858                            pMB->mode = MODE_DIRECT; /* just to make sure it doesn't say "MODE_DIRECT_NONE_MV" */
1859                            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 6: If MinSAD <= thresa goto Step 10.          CheckCandidate = b_mb->mode == MODE_INTER4V ? CheckCandidateDirect : CheckCandidateDirectno4v;
    If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
 */  
1872    
1873          if ((iMinSAD <= threshA) ||          CheckCandidate(0, 0, Data, 255);
1874                  (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&  
1875                   ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {          /* initial (fast) skip decision */
1876                  if (MotionFlags & PMV_QUICKSTOP16)          if (*Data->iMinSAD < Data->iQuant * INITIAL_SKIP_THRESH * (Data->chroma?3:2)) {
1877                          goto PMVfast8_Terminate_without_Refine;                  /* possible skip */
1878                  if (MotionFlags & PMV_EARLYSTOP16)                  if (Data->chroma) {
1879                          goto PMVfast8_Terminate_with_Refine;                          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    
 /************ (Diamond Search)  **************/  
1890  /*  /*
1891     Step 7: Perform Diamond search, with either the small or large diamond.           * DIRECT MODE DELTA VECTOR SEARCH.
1892     If Found=2 only examine one Diamond pattern, and afterwards goto step 10           * This has to be made more effective, but at the moment I'm happy it's running at all
    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.  
1893  */  */
1894    
1895          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1896                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1897                            else MainSearchPtr = DiamondSearch;
1898    
1899  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          MainSearchPtr(0, 0, 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);  
1900    
1901          if (iSAD < iMinSAD) {          SubpelRefine(Data, CheckCandidate);
1902                  *currMV = newMV;  
1903                  iMinSAD = iSAD;          *best_sad = *Data->iMinSAD;
         }  
1904    
1905          if (MotionFlags & PMV_EXTSEARCH8) {          if (Data->qpel || b_mb->mode == MODE_INTER4V) pMB->mode = MODE_DIRECT;
1906  /* extended: search (up to) two more times: orignal prediction and (0,0) */          else pMB->mode = MODE_DIRECT_NO4V; /* for faster compensation */
1907    
1908                  if (!(MVequal(pmv[0], backupMV))) {          pMB->pmvs[3] = *Data->currentMV;
                         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);  
1909    
1910                          if (iSAD < iMinSAD) {          for (k = 0; k < 4; k++) {
1911                                  *currMV = newMV;                  pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
1912                                  iMinSAD = iSAD;                  pMB->b_mvs[k].x = (     (Data->currentMV->x == 0)
1913                                                            ? Data->directmvB[k].x
1914                                                            :pMB->mvs[k].x - Data->referencemv[k].x);
1915                    pMB->mvs[k].y = (Data->directmvF[k].y + Data->currentMV->y);
1916                    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    {
1959    
1960            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                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, fData, 255);
                         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);  
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  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.  void
2065     By performing an optional local half-pixel search, we can refine this result even further.  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    PMVfast8_Terminate_with_Refine:          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
         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);  
2089    
2090            const int32_t TRB = time_pp - time_bp;
2091            const int32_t TRD = time_pp;
2092    
2093    PMVfast8_Terminate_without_Refine:          /* some pre-inintialized data for the rest of the search */
         currPMV->x = currMV->x - center_x;  
         currPMV->y = currMV->y - center_y;  
2094    
2095          return iMinSAD;          SearchData Data;
2096            int32_t iMinSAD;
2097            uint32_t dir;
2098            VECTOR currentMV[3];
2099            VECTOR currentQMV[3];
2100            int32_t temp[8];
2101            memset(&Data, 0, sizeof(SearchData));
2102            Data.iEdgedWidth = pParam->edged_width;
2103            Data.currentMV = currentMV; Data.currentQMV = currentQMV;
2104            Data.iMinSAD = &iMinSAD;
2105            Data.lambda16 = lambda_vec16[MAX(frame->quant-2, 2)];
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            Data.iQuant = frame->quant;
2112    
2113            Data.RefQ = f_refV->u; /* a good place, also used in MC (for similar purpose) */
2114    
2115            /* note: i==horizontal, j==vertical */
2116            for (j = 0; j < pParam->mb_height; j++) {
2117    
2118                    f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
2119    
2120                    for (i = 0; i < pParam->mb_width; i++) {
2121                            MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
2122                            const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
2123    
2124    /* special case, if collocated block is SKIPed in P-VOP: encoding is forward (0,0), cpb=0 without further ado */
2125                            if (b_reference->coding_type != S_VOP)
2126                                    if (b_mb->mode == MODE_NOT_CODED) {
2127                                            pMB->mode = MODE_NOT_CODED;
2128                                            continue;
2129  }  }
2130    
2131  int32_t                          Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
2132  EPZSSearch16(const uint8_t * const pRef,                          Data.CurU = frame->image.u + (j * Data.iEdgedWidth/2 + i) * 8;
2133                           const uint8_t * const pRefH,                          Data.CurV = frame->image.v + (j * Data.iEdgedWidth/2 + i) * 8;
2134                           const uint8_t * const pRefV,  
2135                           const uint8_t * const pRefHV,  /* direct search comes first, because it (1) checks for SKIP-mode
2136                           const IMAGE * const pCur,          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                            if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
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                            /* backward search */
2159                            SearchBF(b_ref, b_refH->y, b_refV->y, b_refHV->y,
2160                                                    &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 < Data.iQuant * MAX_SAD00_FOR_SKIP * 2)
2180                                            && ((100*best_sad)/(skip_sad+1) > FINAL_SKIP_THRESH) )
2181                                    SkipDecisionB(&frame->image, f_ref, b_ref, pMB, i, j, &Data);
2182    
2183                            switch (pMB->mode) {
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    static __inline void
2208    MEanalyzeMB (   const uint8_t * const pRef,
2209                                    const uint8_t * 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;          unsigned int simplicity = 0;
2222    
2223          int32_t min_dx;          for (i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
2224    
2225          VECTOR newMV;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
2226          VECTOR backupMV;                          pParam->width, pParam->height, Data->iFcode - Data->qpel - 1, 0, 0);
2227    
2228          VECTOR pmv[4];          Data->Cur = pCur + (x + y * pParam->edged_width) * 16;
2229          int32_t psad[8];          Data->RefP[0] = pRef + (x + y * pParam->edged_width) * 16;
2230    
2231          static MACROBLOCK *oldMBs = NULL;          pmv[0].x = pMB->mvs[0].x;
2232            pmv[0].y = pMB->mvs[0].y;
2233    
2234  //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;          CheckCandidate32I(pmv[0].x, pmv[0].y, Data, 0);
         const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;  
         MACROBLOCK *oldMB = NULL;  
2235    
2236           int32_t thresh2;          if (*Data->iMinSAD > 200) {
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD = 9999;  
2237    
2238          MainSearch16FuncPtr MainSearchPtr;                  pmv[1].x = pmv[1].y = 0;
2239    
2240          if (oldMBs == NULL) {                  /* median is only used as prediction. it doesn't have to be real */
2241                  oldMBs = (MACROBLOCK *) calloc(iWcount * iHcount, sizeof(MACROBLOCK));                  if (x == 1 && y == 1) Data->predMV.x = Data->predMV.y = 0;
2242  //      fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));                  else
2243                            if (x == 1) /* left macroblock does not have any vector now */
2244                                    Data->predMV = (pMB - pParam->mb_width)->mvs[0]; /* top instead of median */
2245                            else if (y == 1) /* top macroblock doesn't have it's vector */
2246                                    Data->predMV = (pMB - 1)->mvs[0]; /* left instead of median */
2247                            else Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); /* else median */
2248    
2249                    pmv[2].x = Data->predMV.x;
2250                    pmv[2].y = Data->predMV.y;
2251    
2252                    if (!vector_repeats(pmv, 1))
2253                            CheckCandidate32I(pmv[1].x, pmv[1].y, Data, 1);
2254                    if (!vector_repeats(pmv, 2))
2255                            CheckCandidate32I(pmv[2].x, pmv[2].y, Data, 2);
2256    
2257                    if (*Data->iMinSAD > 500) { /* diamond only if needed */
2258                            unsigned int mask = make_mask(pmv, 3, *Data->dir);
2259                            DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, mask, CheckCandidate32I);
2260                    } else simplicity++;
2261    
2262                    if (*Data->iMinSAD > 500) /* refinement from 2-pixel to 1-pixel */
2263                            SubpelRefine(Data, CheckCandidate32I);
2264                    else simplicity++;
2265            } else simplicity++;
2266    
2267            for (i = 0; i < 4; i++) {
2268                    MACROBLOCK * MB = &pMBs[x + (i&1) + (y+(i>>1)) * pParam->mb_width];
2269                    MB->mvs[0] = MB->mvs[1] = MB->mvs[2] = MB->mvs[3] = Data->currentMV[i];
2270                    MB->mode = MODE_INTER;
2271                    /* if we skipped some search steps, we have to assume that SAD would be lower with them */
2272                    MB->sad16 = Data->iMinSAD[i+1] - (simplicity<<7);
2273          }          }
         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);  
2274          }          }
         /* 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.  
 */  
   
 // Prepare for main loop  
2275    
2276          currMV->x = start_x;  #define INTRA_THRESH    2200
2277          currMV->y = start_y;  #define INTER_THRESH    40
2278    #define INTRA_THRESH2   95
2279          if (!(MotionFlags & PMV_HALFPEL16)) {  
2280                  currMV->x = EVEN(currMV->x);  int
2281                  currMV->y = EVEN(currMV->y);  MEanalysis(     const IMAGE * const pRef,
2282          }                          const FRAMEINFO * const Current,
2283                            const MBParam * const pParam,
2284          if (currMV->x > max_dx)                          const int maxIntra, //maximum number if non-I frames
2285                  currMV->x = max_dx;                          const int intraCount, //number of non-I frames after last I frame; 0 if we force P/B frame
2286          if (currMV->x < min_dx)                          const int bCount, // number of B frames in a row
2287                  currMV->x = min_dx;                          const int b_thresh)
2288          if (currMV->y > max_dy)  {
2289                  currMV->y = max_dy;          uint32_t x, y, intra = 0;
2290          if (currMV->y < min_dy)          int sSAD = 0;
2291                  currMV->y = min_dy;          MACROBLOCK * const pMBs = Current->mbs;
2292            const IMAGE * const pCurrent = &Current->image;
2293  /***************** This is predictor SET A: only median prediction ******************/          int IntraThresh = INTRA_THRESH, InterThresh = INTER_THRESH + b_thresh;
2294            int blocks = 0;
2295          iMinSAD =          int complexity = 0;
2296                  sad16(cur,  
2297                            get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,          int32_t iMinSAD[5], temp[5];
2298                                                   iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);          uint32_t dir;
2299          iMinSAD +=          VECTOR currentMV[5];
2300                  calc_delta_16(currMV->x - center_x, currMV->y - center_y,          SearchData Data;
2301                                            (uint8_t) iFcode, iQuant);          Data.iEdgedWidth = pParam->edged_width;
2302            Data.currentMV = currentMV;
2303  // thresh1 is fixed to 256          Data.iMinSAD = iMinSAD;
2304          if ((iMinSAD < 256) ||          Data.iFcode = Current->fcode;
2305                  ((MVequal(*currMV, prevMB->mvs[0])) &&          Data.temp = temp;
2306                   ((int32_t) iMinSAD < prevMB->sad16))) {          Data.dir = &dir;
2307                  if (MotionFlags & PMV_QUICKSTOP16)          Data.qpel = (pParam->vol_flags & XVID_VOL_QUARTERPEL)? 1: 0;
2308                          goto EPZS16_Terminate_without_Refine;          Data.qpel_precision = 0;
2309                  if (MotionFlags & PMV_EARLYSTOP16)  
2310                          goto EPZS16_Terminate_with_Refine;          if (intraCount != 0) {
2311          }                  if (intraCount < 10) // we're right after an I frame
2312                            IntraThresh += 15* (intraCount - 10) * (intraCount - 10);
2313  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/                  else
2314                            if ( 5*(maxIntra - intraCount) < maxIntra) // we're close to maximum. 2 sec when max is 10 sec
2315                                    IntraThresh -= (IntraThresh * (maxIntra - 8*(maxIntra - intraCount)))/maxIntra;
2316            }
2317    
2318  // previous frame MV          InterThresh -= 20 * bCount;
2319          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);          if (InterThresh < 10 + b_thresh) InterThresh = 10 + b_thresh;
2320    
2321  // 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  
2322    
2323          if ((x == 0) && (y == 0)) {          for (y = 1; y < pParam->mb_height-1; y += 2) {
2324                  thresh2 = 512;                  for (x = 1; x < pParam->mb_width-1; x += 2) {
2325          } else {                          int i;
2326  /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */                          blocks += 10;
2327    
2328                  thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;                          if (bCount == 0) pMBs[x + y * pParam->mb_width].mvs[0] = zeroMV;
2329                            else { //extrapolation of the vector found for last frame
2330                                    pMBs[x + y * pParam->mb_width].mvs[0].x =
2331                                            (pMBs[x + y * pParam->mb_width].mvs[0].x * (bCount+1) ) / bCount;
2332                                    pMBs[x + y * pParam->mb_width].mvs[0].y =
2333                                            (pMBs[x + y * pParam->mb_width].mvs[0].y * (bCount+1) ) / bCount;
2334          }          }
2335    
2336  // MV=(0,0) is often a good choice                          MEanalyzeMB(pRef->y, pCurrent->y, x, y, pParam, pMBs, &Data);
   
         CHECK_MV16_ZERO;  
2337    
2338                            for (i = 0; i < 4; i++) {
2339                                    int dev;
2340                                    MACROBLOCK *pMB = &pMBs[x+(i&1) + (y+(i>>1)) * pParam->mb_width];
2341                                    dev = dev16(pCurrent->y + (x + (i&1) + (y + (i>>1)) * pParam->edged_width) * 16,
2342                                                                    pParam->edged_width);
2343    
2344  // left neighbour, if allowed                                  complexity += MAX(dev, 300);
2345          if (x != 0) {                                  if (dev + IntraThresh < pMB->sad16) {
2346                  if (!(MotionFlags & PMV_HALFPEL16)) {                                          pMB->mode = MODE_INTRA;
2347                          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);  
2348                  }                  }
                 CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
2349    
2350  // top right neighbour, if allowed                                  if (pMB->mvs[0].x == 0 && pMB->mvs[0].y == 0)
2351                  if ((uint32_t) x != (iWcount - 1)) {                                          if (dev > 1000 && pMB->sad16 < 1000)
2352                          if (!(MotionFlags & PMV_HALFPEL16)) {                                                  sSAD += 1000;
2353                                  pmv[3].x = EVEN(pmv[3].x);  
2354                                  pmv[3].y = EVEN(pmv[3].y);                                  sSAD += (dev < 4000) ? pMB->sad16 : pMB->sad16/2; /* blocks with big contrast differences usually have large SAD - while they look very good in b-frames */
2355                          }                          }
                         CHECK_MV16_CANDIDATE(pmv[3].x, pmv[3].y);  
2356                  }                  }
2357          }          }
2358            complexity >>= 7;
2359    
2360  /* Terminate if MinSAD <= T_2          sSAD /= complexity + 4*blocks;
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
2361    
2362          if ((iMinSAD <= thresh2)          if (intraCount > 80 && sSAD > INTRA_THRESH2 ) return I_VOP;
2363                  || (MVequal(*currMV, prevMB->mvs[0]) &&          if (sSAD > InterThresh ) return P_VOP;
2364                          ((int32_t) iMinSAD <= prevMB->sad16))) {          emms();
2365                  if (MotionFlags & PMV_QUICKSTOP16)          return B_VOP;
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
2366          }          }
2367    
 /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/  
   
         backupMV = prevMB->mvs[0];      // collocated MV  
         backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x);     // acceleration X  
         backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y);     // acceleration Y  
   
         CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y);  
   
 // left neighbour  
         if (x != 0)  
                 CHECK_MV16_CANDIDATE((prevMB - 1)->mvs[0].x, (prevMB - 1)->mvs[0].y);  
   
 // top neighbour  
         if (y != 0)  
                 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  
2368    
2369          if ((uint32_t) x != iWcount - 1)  /* functions which perform BITS-based search/bitcount */
                 CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);  
2370    
2371  // bottom neighbour, dito  static int
2372          if ((uint32_t) y != iHcount - 1)  findRDinter(SearchData * const Data,
2373                  CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,                          const MACROBLOCK * const pMBs, const int x, const int y,
2374                                                           (prevMB + iWcount)->mvs[0].y);                          const MBParam * const pParam,
2375                            const uint32_t MotionFlags)
2376    {
2377            int i;
2378            int32_t bsad[5];
2379    
2380  /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */          if (Data->qpel) {
2381          if (iMinSAD <= thresh2) {                  for(i = 0; i < 5; i++) {
2382                  if (MotionFlags & PMV_QUICKSTOP16)                          Data->currentMV[i].x = Data->currentQMV[i].x/2;
2383                          goto EPZS16_Terminate_without_Refine;                          Data->currentMV[i].y = Data->currentQMV[i].y/2;
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
2384          }          }
2385                    Data->qpel_precision = 1;
2386                    CheckCandidateRD16(Data->currentQMV[0].x, Data->currentQMV[0].y, Data, 255);
2387    
2388  /************ (if Diamond Search)  **************/                  if (MotionFlags & (XVID_ME_HALFPELREFINE16_RD | XVID_ME_EXTSEARCH_RD)) { /* we have to prepare for halfpixel-precision search */
2389                            for(i = 0; i < 5; i++) bsad[i] = Data->iMinSAD[i];
2390          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,
2391                                                    pParam->width, pParam->height, Data->iFcode - Data->qpel, 1, Data->rrv);
2392          if (MotionFlags & PMV_USESQUARES16)                          Data->qpel_precision = 0;
2393                  MainSearchPtr = Square16_MainSearch;                          if (Data->currentQMV->x & 1 || Data->currentQMV->y & 1)
2394          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;  
2395          }          }
2396    
2397            } else { /* not qpel */
2398    
2399          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);  
2400                  }                  }
2401    
2402                  if (iSAD < iMinSAD) {          if (MotionFlags&XVID_ME_EXTSEARCH_RD)
2403                          *currMV = newMV;                  SquareSearch(Data->currentMV->x, Data->currentMV->y, Data, 255, CheckCandidateRD16);
                         iMinSAD = iSAD;  
                 }  
2404    
2405                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          if (MotionFlags&XVID_ME_HALFPELREFINE16_RD)
2406                          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);  
2407    
2408                          if (iSAD < iMinSAD) {          if (Data->qpel) {
2409                                  *currMV = newMV;                  if (MotionFlags&(XVID_ME_EXTSEARCH_RD | XVID_ME_HALFPELREFINE16_RD)) { /* there was halfpel-precision search */
2410                                  iMinSAD = iSAD;                          for(i = 0; i < 5; i++) if (bsad[i] > Data->iMinSAD[i]) {
2411                                    Data->currentQMV[i].x = 2 * Data->currentMV[i].x; /* we have found a better match */
2412                                    Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
2413                          }                          }
2414    
2415                            /* preparing for qpel-precision search */
2416                            Data->qpel_precision = 1;
2417                            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
2418                                            pParam->width, pParam->height, Data->iFcode, 2, 0);
2419                  }                  }
2420                    if (MotionFlags&XVID_ME_QUARTERPELREFINE16_RD)
2421                            SubpelRefine(Data, CheckCandidateRD16);
2422          }          }
2423    
2424  /***************        Choose best MV found     **************/          if (MotionFlags&XVID_ME_CHECKPREDICTION_RD) { /* let's check vector equal to prediction */
2425                    VECTOR * v = Data->qpel ? Data->currentQMV : Data->currentMV;
2426    EPZS16_Terminate_with_Refine:                  if (!(Data->predMV.x == v->x && Data->predMV.y == v->y))
2427          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step                          CheckCandidateRD16(Data->predMV.x, Data->predMV.y, Data, 255);
2428                  iMinSAD =          }
2429                          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;  
2430  }  }
2431    
2432    static int
2433  int32_t  findRDinter4v(const SearchData * const Data,
2434  EPZSSearch8(const uint8_t * const pRef,                                  MACROBLOCK * const pMB, const MACROBLOCK * const pMBs,
2435                          const uint8_t * const pRefH,                                  const int x, const int y,
2436                          const uint8_t * const pRefV,                                  const MBParam * const pParam, const uint32_t MotionFlags,
2437                          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)  
2438  {  {
 /* 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;  
   
         int32_t min_dx;  
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
   
         VECTOR newMV;  
         VECTOR backupMV;  
   
         VECTOR pmv[4];  
         int32_t psad[8];  
   
         const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);  
2439    
2440  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          int cbp = 0, bits = 0, t = 0, i;
2441          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;          SearchData Data2, *Data8 = &Data2;
2442            int sumx = 0, sumy = 0;
2443          int32_t bPredEq;          int16_t *in = Data->dctSpace, *coeff = Data->dctSpace + 64;
2444          int32_t iMinSAD, iSAD = 9999;          uint8_t * ptr;
2445    
2446          MainSearch8FuncPtr MainSearchPtr;          memcpy(Data8, Data, sizeof(SearchData));
2447    
2448            for (i = 0; i < 4; i++) { /* for all luma blocks */
2449    
2450                    Data8->iMinSAD = Data->iMinSAD + i + 1;
2451                    Data8->currentMV = Data->currentMV + i + 1;
2452                    Data8->currentQMV = Data->currentQMV + i + 1;
2453                    Data8->Cur = Data->Cur + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2454                    Data8->RefP[0] = Data->RefP[0] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2455                    Data8->RefP[2] = Data->RefP[2] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2456                    Data8->RefP[1] = Data->RefP[1] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2457                    Data8->RefP[3] = Data->RefP[3] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2458                    *Data8->cbp = (Data->cbp[1] & (1<<(5-i))) ? 1:0; // copy corresponding cbp bit
2459    
2460                    if(Data->qpel) {
2461                            Data8->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, i);
2462                            if (i != 0)     t = d_mv_bits(  Data8->currentQMV->x, Data8->currentQMV->y,
2463                                                                                    Data8->predMV, Data8->iFcode, 0, 0);
2464                    } else {
2465                            Data8->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, i);
2466                            if (i != 0)     t = d_mv_bits(  Data8->currentMV->x, Data8->currentMV->y,
2467                                                                                    Data8->predMV, Data8->iFcode, 0, 0);
2468                    }
2469    
2470  /* 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,
2471          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);  
2472    
2473  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */                  *Data8->iMinSAD += BITS_MULT*t;
2474    
2475          if (!(MotionFlags & PMV_HALFPEL8)) {                  Data8->qpel_precision = Data8->qpel;
2476                  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) */
2477                  max_dx = EVEN(max_dx);                  {
2478                  min_dy = EVEN(min_dy);                          VECTOR *v = Data8->qpel ? Data8->currentQMV : Data8->currentMV;
2479                  max_dy = EVEN(max_dy);                          if (!MVequal (*v, backup[i+1]) )
2480                                    CheckCandidateRD8(backup[i+1].x, backup[i+1].y, Data8, 255);
2481          }          }
         /* 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);  
2482    
2483                    if (Data8->qpel) {
2484                            if (MotionFlags&XVID_ME_HALFPELREFINE8_RD || (MotionFlags&XVID_ME_EXTSEARCH8 && MotionFlags&XVID_ME_EXTSEARCH_RD)) { /* halfpixel motion search follows */
2485                                    int32_t s = *Data8->iMinSAD;
2486                                    Data8->currentMV->x = Data8->currentQMV->x/2;
2487                                    Data8->currentMV->y = Data8->currentQMV->y/2;
2488                                    Data8->qpel_precision = 0;
2489                                    get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 3,
2490                                                            pParam->width, pParam->height, Data8->iFcode - 1, 1, 0);
2491    
2492  /* Step 4: Calculate SAD around the Median prediction.                                  if (Data8->currentQMV->x & 1 || Data8->currentQMV->y & 1)
2493          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.  
 */  
2494    
2495  // Prepare for main loop                                  if (MotionFlags & XVID_ME_EXTSEARCH8 && MotionFlags & XVID_ME_EXTSEARCH_RD)
2496                                            SquareSearch(Data8->currentMV->x, Data8->currentMV->x, Data8, 255, CheckCandidateRD8);
2497    
2498                                    if (MotionFlags & XVID_ME_HALFPELREFINE8_RD)
2499                                            SubpelRefine(Data8, CheckCandidateRD8);
2500    
2501          if (!(MotionFlags & PMV_HALFPEL8)) {                                  if(s > *Data8->iMinSAD) { /* we have found a better match */
2502                  currMV->x = EVEN(currMV->x);                                          Data8->currentQMV->x = 2*Data8->currentMV->x;
2503                  currMV->y = EVEN(currMV->y);                                          Data8->currentQMV->y = 2*Data8->currentMV->y;
2504          }          }
2505    
2506          if (currMV->x > max_dx)                                  Data8->qpel_precision = 1;
2507                  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,
2508          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 ******************/  
2509    
2510                            }
2511                            if (MotionFlags & XVID_ME_QUARTERPELREFINE8_RD)
2512                                    SubpelRefine(Data8, CheckCandidateRD8);
2513    
2514          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);  
2515    
2516                            if (MotionFlags & XVID_ME_EXTSEARCH8 && MotionFlags & XVID_ME_EXTSEARCH_RD) /* extsearch */
2517                                    SquareSearch(Data8->currentMV->x, Data8->currentMV->x, Data8, 255, CheckCandidateRD8);
2518    
2519  // thresh1 is fixed to 256                          if (MotionFlags & XVID_ME_HALFPELREFINE8_RD)
2520          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;  
2521          }          }
2522    
2523  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/                  /* checking vector equal to predicion */
2524                    if (i != 0 && MotionFlags & XVID_ME_CHECKPREDICTION_RD) {
2525                            const VECTOR * v = Data->qpel ? Data8->currentQMV : Data8->currentMV;
2526                            if (!MVequal(*v, Data8->predMV))
2527                                    CheckCandidateRD8(Data8->predMV.x, Data8->predMV.y, Data8, 255);
2528                    }
2529    
2530                    bits += *Data8->iMinSAD;
2531                    if (bits >= Data->iMinSAD[0]) return bits; /* no chances for INTER4V */
2532    
2533  // 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 */
2534          CHECK_MV8_ZERO;                  if(Data->qpel) {
2535                            pMB->pmvs[i].x = Data8->currentQMV->x - Data8->predMV.x;
2536                            pMB->pmvs[i].y = Data8->currentQMV->y - Data8->predMV.y;
2537                            pMB->qmvs[i] = *Data8->currentQMV;
2538                            sumx += Data8->currentQMV->x/2;
2539                            sumy += Data8->currentQMV->y/2;
2540                    } else {
2541                            pMB->pmvs[i].x = Data8->currentMV->x - Data8->predMV.x;
2542                            pMB->pmvs[i].y = Data8->currentMV->y - Data8->predMV.y;
2543                            sumx += Data8->currentMV->x;
2544                            sumy += Data8->currentMV->y;
2545                    }
2546                    pMB->mvs[i] = *Data8->currentMV;
2547                    pMB->sad8[i] = 4 * *Data8->iMinSAD;
2548                    if (Data8->cbp[0]) cbp |= 1 << (5 - i);
2549    
2550  // previous frame MV          } /* end - for all luma blocks */
         CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x, prevMB->mvs[iSubBlock].y);  
2551    
2552  // 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);  
2553    
2554  // top right neighbour, if allowed          /* let's check chroma */
2555                  if (psad[3] != MV_MAX_ERROR) {          sumx = (sumx >> 3) + roundtab_76[sumx & 0xf];
2556                          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);  
                 }  
         }  
2557    
2558  /*  // this bias is zero anyway, at the moment!          /* chroma U */
2559            ptr = interpolate8x8_switch2(Data->RefQ + 64, Data->RefP[4], 0, 0, sumx, sumy, Data->iEdgedWidth/2, Data->rounding);
2560            transfer_8to16subro(in, Data->CurU, ptr, Data->iEdgedWidth/2);
2561            bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 4);
2562    
2563          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)          if (bits >= *Data->iMinSAD) return bits;
                 iMinSAD -= MV8_00_BIAS;  
2564    
2565  */          /* chroma V */
2566            ptr = interpolate8x8_switch2(Data->RefQ + 64, Data->RefP[5], 0, 0, sumx, sumy, Data->iEdgedWidth/2, Data->rounding);
2567            transfer_8to16subro(in, Data->CurV, ptr, Data->iEdgedWidth/2);
2568            bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 5);
2569    
2570  /* 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]  
 */  
2571    
2572          if (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */          *Data->cbp = cbp;
2573                  if (MotionFlags & PMV_QUICKSTOP8)          return bits;
                         goto EPZS8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
2574          }          }
2575    
2576  /************ (Diamond Search)  **************/  static int
2577    findRDintra(const SearchData * const Data)
2578          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  {
2579            int bits = BITS_MULT*1; /* this one is ac/dc prediction flag bit */
2580            int cbp = 0, i, dc = 0;
2581            int16_t *in = Data->dctSpace, * coeff = Data->dctSpace + 64;
2582    
2583          if (!(MotionFlags & PMV_HALFPELDIAMOND8))          for(i = 0; i < 4; i++) {
2584                  iDiamondSize *= 2;                  int s = 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2585                    transfer_8to16copy(in, Data->Cur + s, Data->iEdgedWidth);
2586                    bits += Block_CalcBitsIntra(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, i, &dc);
2587    
2588  /* default: use best prediction as starting point for one call of EPZS_MainSearch */                  if (bits >= Data->iMinSAD[0]) return bits;
2589            }
2590    
2591  // there is no EPZS^2 for inter4v at the moment          bits += BITS_MULT*xvid_cbpy_tab[cbp>>2].len;
2592    
2593    if (MotionFlags & PMV_USESQUARES8)          /*chroma U */
2594        MainSearchPtr = Square8_MainSearch;          transfer_8to16copy(in, Data->CurU, Data->iEdgedWidth/2);
2595    else          bits += Block_CalcBitsIntra(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 4, &dc);
2596    
2597          if (MotionFlags & PMV_ADVANCEDDIAMOND8)          if (bits >= Data->iMinSAD[0]) return bits;
                 MainSearchPtr = AdvDiamond8_MainSearch;  
         else  
                 MainSearchPtr = Diamond8_MainSearch;  
2598    
2599          iSAD =          /* chroma V */
2600                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,          transfer_8to16copy(in, Data->CurV, Data->iEdgedWidth/2);
2601                                                    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);  
2602    
2603            bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTRA & 7) | ((cbp & 3) << 3)].len;
2604    
2605          if (iSAD < iMinSAD) {          return bits;
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
2606          }          }
2607    
2608          if (MotionFlags & PMV_EXTSEARCH8) {  static int
2609  /* 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)
2610    {
2611                  if (!(MVequal(pmv[0], backupMV))) {          int bits = BITS_MULT*1; /* this one is mcsel */
2612                          iSAD =          int cbp = 0, i;
2613                                  (*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);  
2614    
2615                          if (iSAD < iMinSAD) {          for(i = 0; i < 4; i++) {
2616                                  *currMV = newMV;                  int s = 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2617                                  iMinSAD = iSAD;                  transfer_8to16subro(in, Data->Cur + s, vGMC->y + s + 16*(x+y*Data->iEdgedWidth), Data->iEdgedWidth);
2618                          }                  bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, i);
2619                    if (bits >= Data->iMinSAD[0]) return bits;
2620                  }                  }
2621    
2622                  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);  
2623    
2624                          if (iSAD < iMinSAD) {          /*chroma U */
2625                                  *currMV = newMV;          transfer_8to16subro(in, Data->CurU, vGMC->u + 8*(x+y*(Data->iEdgedWidth/2)), Data->iEdgedWidth/2);
2626                                  iMinSAD = iSAD;          bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 4);
                         }  
                 }  
         }  
2627    
2628  /***************        Choose best MV found     **************/          if (bits >= Data->iMinSAD[0]) return bits;
2629    
2630    EPZS8_Terminate_with_Refine:          /* chroma V */
2631          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step          transfer_8to16subro(in, Data->CurV , vGMC->v + 8*(x+y*(Data->iEdgedWidth/2)), Data->iEdgedWidth/2);
2632                  iMinSAD =          bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 5);
                         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);  
2633    
2634    EPZS8_Terminate_without_Refine:          bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTER & 7) | ((cbp & 3) << 3)].len;
2635    
2636          currPMV->x = currMV->x - center_x;          *Data->cbp = cbp;
2637          currPMV->y = currMV->y - center_y;  
2638          return iMinSAD;          return bits;
2639  }  }
2640    
2641    
2642    
2643  int32_t  
2644  PMVfastIntSearch16(const uint8_t * const pRef,  static __inline void
2645    GMEanalyzeMB (  const uint8_t * const pCur,
2646                                    const uint8_t * const pRef,
2647                                  const uint8_t * const pRefH,                                  const uint8_t * const pRefH,
2648                                  const uint8_t * const pRefV,                                  const uint8_t * const pRefV,
2649                                  const uint8_t * const pRefHV,                                  const uint8_t * const pRefHV,
                                 const IMAGE * const pCur,  
2650                                  const int x,                                  const int x,
2651                                  const int y,                                  const int y,
                                 const int start_x,              /* start should be most likely vector */  
                                 const int start_y,  
                                 const int center_x,             /* center is from where length of MVs is measured */  
                                 const int center_y,  
                                 const uint32_t MotionFlags,  
                                 const uint32_t iQuant,  
                                 const uint32_t iFcode,  
2652                                  const MBParam * const pParam,                                  const MBParam * const pParam,
2653                                  const MACROBLOCK * const pMBs,                                  MACROBLOCK * const pMBs,
2654                                  const MACROBLOCK * const prevMBs,                                  SearchData * const Data)
                                 VECTOR * const currMV,  
                                 VECTOR * const currPMV)  
2655  {  {
         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;  
2656    
2657          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          int i=0;
2658          const VECTOR zeroMV = { 0, 0 };          MACROBLOCK * const pMB = &pMBs[x + y * pParam->mb_width];
2659    
2660          int32_t iDiamondSize;          Data->iMinSAD[0] = MV_MAX_ERROR;
2661    
2662          int32_t min_dx;          Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
2663    
2664          int32_t iFound;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
2665                                    pParam->width, pParam->height, 16, 1, 0);
2666    
2667          VECTOR newMV;          Data->Cur = pCur + 16*(x + y * pParam->edged_width);
2668          VECTOR backupMV;          Data->RefP[0] = pRef + 16*(x + y * pParam->edged_width);
2669            Data->RefP[1] = pRefV + 16*(x + y * pParam->edged_width);
2670            Data->RefP[2] = pRefH + 16*(x + y * pParam->edged_width);
2671            Data->RefP[3] = pRefHV + 16*(x + y * pParam->edged_width);
2672    
2673          VECTOR pmv[4];          Data->currentMV[0].x = Data->currentMV[0].y = 0;
2674          int32_t psad[4];          CheckCandidate16I(0, 0, Data, 255);
2675    
2676          MainSearch16FuncPtr MainSearchPtr;          if ( (Data->predMV.x !=0) || (Data->predMV.y != 0) )
2677                    CheckCandidate16I(Data->predMV.x, Data->predMV.y, Data, 255);
2678    
2679          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;          DiamondSearch(Data->currentMV[0].x, Data->currentMV[0].y, Data, 255, CheckCandidate16I);
         MACROBLOCK *const pMB = pMBs + x + y * iWcount;  
2680    
2681          int32_t threshA, threshB;          SubpelRefine(Data, CheckCandidate16I);
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD;  
2682    
2683    
2684  /* Get maximum range */          /* for QPel halfpel positions are worse than in halfpel mode :( */
2685          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  /*      if (Data->qpel) {
2686                            iFcode);                  Data->currentQMV->x = 2*Data->currentMV->x;
2687                    Data->currentQMV->y = 2*Data->currentMV->y;
2688                    Data->qpel_precision = 1;
2689                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
2690                                            pParam->width, pParam->height, iFcode, 2, 0);
2691                    SubpelRefine(Data);
2692            }
2693    */
2694    
2695  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
2696            pMB->sad16 = Data->iMinSAD[0];
2697            pMB->mode = MODE_INTER;
2698            pMB->sad16 += 10*d_mv_bits(pMB->mvs[0].x, pMB->mvs[0].y, Data->predMV, Data->iFcode, 0, 0);
2699            return;
2700    }
2701    
2702          if ((x == 0) && (y == 0)) {  void
2703                  threshA = 512;  GMEanalysis(const MBParam * const pParam,
2704                  threshB = 1024;                          const FRAMEINFO * const current,
2705                            const FRAMEINFO * const reference,
2706                            const IMAGE * const pRefH,
2707                            const IMAGE * const pRefV,
2708                            const IMAGE * const pRefHV)
2709    {
2710            uint32_t x, y;
2711            MACROBLOCK * const pMBs = current->mbs;
2712            const IMAGE * const pCurrent = &current->image;
2713            const IMAGE * const pReference = &reference->image;
2714    
2715                  bPredEq = 0;          int32_t iMinSAD[5], temp[5];
2716                  psad[0] = psad[1] = psad[2] = psad[3] = 0;          VECTOR currentMV[5];
2717                  *currMV = pmv[0] = pmv[1] = pmv[2] = pmv[3] = zeroMV;          uint32_t dir;
2718            SearchData Data;
2719            memset(&Data, 0, sizeof(SearchData));
2720    
2721          } else {          Data.iEdgedWidth = pParam->edged_width;
2722                  threshA = psad[0];          Data.rounding = pParam->m_rounding_type;
                 threshB = threshA + 256;  
                 if (threshA < 512)  
                         threshA = 512;  
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
   
                 bPredEq = get_ipmvdata(pMBs, iWcount, 0, x, y, 0, pmv, psad);  
                 *currMV = pmv[0];                       /* current best := prediction */  
         }  
   
         iFound = 0;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
2723    
2724          if (currMV->x > max_dx) {          Data.currentMV = &currentMV[0];
2725                  currMV->x = EVEN(max_dx);          Data.iMinSAD = &iMinSAD[0];
2726          }          Data.iFcode = current->fcode;
2727          if (currMV->x < min_dx) {          Data.temp = temp;
2728                  currMV->x = EVEN(min_dx);          Data.dir = &dir;
         }  
         if (currMV->y > max_dy) {  
                 currMV->y = EVEN(max_dy);  
         }  
         if (currMV->y < min_dy) {  
                 currMV->y = EVEN(min_dy);  
         }  
2729    
2730          iMinSAD =          if (sadInit) (*sadInit) ();
                 sad16(cur,  
                           get_iref_mv(pRef, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
2731    
2732          if ((iMinSAD < 256) ||          for (y = 0; y < pParam->mb_height; y ++) {
2733                  ((MVequal(*currMV, prevMB->i_mvs[0])) &&                  for (x = 0; x < pParam->mb_width; x ++) {
2734                   ((int32_t) iMinSAD < prevMB->i_sad16))) {                          GMEanalyzeMB(pCurrent->y, pReference->y, pRefH->y, pRefV->y, pRefHV->y, x, y, pParam, pMBs, &Data);
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
                 {  
                         if (!MVzero(*currMV)) {  
                                 iMinSAD += MV16_00_BIAS;  
                                 CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures  
                                 iMinSAD -= MV16_00_BIAS;  
2735                          }                          }
2736                  }                  }
2737            return;
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfastInt16_Terminate_with_Refine;  
2738          }          }
2739    
2740    
2741  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  WARPPOINTS
2742     vector of the median.  GlobalMotionEst(MACROBLOCK * const pMBs,
2743     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2                                  const MBParam * const pParam,
2744  */                                  const FRAMEINFO * const current,
2745                                    const FRAMEINFO * const reference,
2746          if ((bPredEq) && (MVequal(pmv[0], prevMB->i_mvs[0])))                                  const IMAGE * const pRefH,
2747                  iFound = 2;                                  const IMAGE * const pRefV,
2748                                    const IMAGE * const pRefHV)
2749    {
2750    
2751  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          const int deltax=8;             // upper bound for difference between a MV and it's neighbour MVs
2752     Otherwise select large Diamond Search.          const int deltay=8;
2753  */          const unsigned int gradx=512;           // lower bound for gradient in MB (ignore "flat" blocks)
2754            const unsigned int grady=512;
2755    
2756          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))          double sol[4] = { 0., 0., 0., 0. };
                 iDiamondSize = 2;               // halfpel units!  
         else  
                 iDiamondSize = 4;               // halfpel units!  
2757    
2758  /*          WARPPOINTS gmc;
    Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  
    Also calculate (0,0) but do not subtract offset.  
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset.  
 */  
2759    
2760  // (0,0) is often a good choice          uint32_t mx, my;
2761    
2762          if (!MVzero(pmv[0]))          int MBh = pParam->mb_height;
2763                  CHECK_MV16_ZERO;          int MBw = pParam->mb_width;
2764            const int minblocks = 9; //MBh*MBw/32+3;                /* just some reasonable number 3% + 3 */
2765            const int maxblocks = MBh*MBw/4;                /* just some reasonable number 3% + 3 */
2766    
2767  // previous frame MV is always possible          int num=0;
2768            int oldnum;
2769    
2770          if (!MVzero(prevMB->i_mvs[0]))          gmc.duv[0].x = gmc.duv[0].y = gmc.duv[1].x = gmc.duv[1].y = gmc.duv[2].x = gmc.duv[2].y = 0;
                 if (!MVequal(prevMB->i_mvs[0], pmv[0]))  
                         CHECK_MV16_CANDIDATE(prevMB->i_mvs[0].x, prevMB->i_mvs[0].y);  
   
 // left neighbour, if allowed  
   
         if (!MVzero(pmv[1]))  
                 if (!MVequal(pmv[1], prevMB->i_mvs[0]))  
                         if (!MVequal(pmv[1], pmv[0]))  
                                 CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
   
 // top neighbour, if allowed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], prevMB->i_mvs[0]))  
                         if (!MVequal(pmv[2], pmv[0]))  
                                 if (!MVequal(pmv[2], pmv[1]))  
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed  
                                         if (!MVzero(pmv[3]))  
                                                 if (!MVequal(pmv[3], prevMB->i_mvs[0]))  
                                                         if (!MVequal(pmv[3], pmv[0]))  
                                                                 if (!MVequal(pmv[3], pmv[1]))  
                                                                         if (!MVequal(pmv[3], pmv[2]))  
                                                                                 CHECK_MV16_CANDIDATE(pmv[3].x,  
                                                                                                                          pmv[3].y);  
   
         if ((MVzero(*currMV)) &&  
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV16_00_BIAS;  
2771    
2772            GMEanalysis(pParam,current, reference, pRefH, pRefV, pRefHV);
2773    
2774  /* Step 6: If MinSAD <= thresa goto Step 10.          /* block based ME isn't done, yet, so do a quick presearch */
    If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
 */  
2775    
2776          if ((iMinSAD <= threshA) ||  // filter mask of all blocks
                 (MVequal(*currMV, prevMB->i_mvs[0]) &&  
                  ((int32_t) iMinSAD < prevMB->i_sad16))) {  
2777    
2778                  if (MotionFlags & PMV_EARLYSTOP16)          for (my = 0; my < (uint32_t)MBh; my++)
2779                          goto PMVfastInt16_Terminate_with_Refine;          for (mx = 0; mx < (uint32_t)MBw; mx++)
2780            {
2781                    const int mbnum = mx + my * MBw;
2782                            pMBs[mbnum].mcsel = 0;
2783          }          }
2784    
2785    
2786  /************ (Diamond Search)  **************/          for (my = 1; my < (uint32_t)MBh-1; my++) /* ignore boundary blocks */
2787  /*          for (mx = 1; mx < (uint32_t)MBw-1; mx++) /* theirs MVs are often wrong */
2788     Step 7: Perform Diamond search, with either the small or large diamond.          {
2789     If Found=2 only examine one Diamond pattern, and afterwards goto step 10                  const int mbnum = mx + my * MBw;
2790     Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.                  MACROBLOCK *const pMB = &pMBs[mbnum];
2791     If center then goto step 10.                  const VECTOR mv = pMB->mvs[0];
    Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
    Refine by using small diamond and goto step 10.  
 */  
2792    
2793          if (MotionFlags & PMV_USESQUARES16)                  /* don't use object boundaries */
2794                  MainSearchPtr = Square16_MainSearch;                  if   ( (abs(mv.x -   (pMB-1)->mvs[0].x) < deltax)
2795          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)                          && (abs(mv.y -   (pMB-1)->mvs[0].y) < deltay)
2796                  MainSearchPtr = AdvDiamond16_MainSearch;                          && (abs(mv.x -   (pMB+1)->mvs[0].x) < deltax)
2797          else                          && (abs(mv.y -   (pMB+1)->mvs[0].y) < deltay)
2798                  MainSearchPtr = Diamond16_MainSearch;                          && (abs(mv.x - (pMB-MBw)->mvs[0].x) < deltax)
2799                            && (abs(mv.y - (pMB-MBw)->mvs[0].y) < deltay)
2800                            && (abs(mv.x - (pMB+MBw)->mvs[0].x) < deltax)
2801                            && (abs(mv.y - (pMB+MBw)->mvs[0].y) < deltay) )
2802                    {       const int iEdgedWidth = pParam->edged_width;
2803                            const uint8_t *const pCur = current->image.y + 16*(my*iEdgedWidth + mx);
2804                            if ( (sad16 ( pCur, pCur+1 , iEdgedWidth, 65536) >= gradx )
2805                             &&  (sad16 ( pCur, pCur+iEdgedWidth, iEdgedWidth, 65536) >= grady ) )
2806                             {      pMB->mcsel = 1;
2807                                    num++;
2808                             }
2809    
2810          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                  /* only use "structured" blocks */
2811                    }
2812            }
2813            emms();
2814    
2815            /*      further filtering would be possible, but during iteration, remaining
2816                    outliers usually are removed, too */
2817    
2818  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          if (num>= minblocks)
2819          iSAD =          do {            /* until convergence */
2820                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,                  double DtimesF[4];
2821                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,                  double a,b,c,n,invdenom;
2822                                                    min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,                  double meanx,meany;
                                                   iQuant, iFound);  
2823    
2824          if (iSAD < iMinSAD) {                  a = b = c = n = 0;
2825                  *currMV = newMV;                  DtimesF[0] = DtimesF[1] = DtimesF[2] = DtimesF[3] = 0.;
2826                  iMinSAD = iSAD;                  for (my = 1; my < (uint32_t)MBh-1; my++)
2827          }                  for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2828                    {
2829                            const int mbnum = mx + my * MBw;
2830                            const VECTOR mv = pMBs[mbnum].mvs[0];
2831    
2832          if (MotionFlags & PMV_EXTSEARCH16) {                          if (!pMBs[mbnum].mcsel)
2833  /* extended: search (up to) two more times: orignal prediction and (0,0) */                                  continue;
2834    
2835                  if (!(MVequal(pmv[0], backupMV))) {                          n++;
2836                          iSAD =                          a += 16*mx+8;
2837                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                          b += 16*my+8;
2838                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,                          c += (16*mx+8)*(16*mx+8)+(16*my+8)*(16*my+8);
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
2839    
2840                          if (iSAD < iMinSAD) {                          DtimesF[0] += (double)mv.x;
2841                                  *currMV = newMV;                          DtimesF[1] += (double)mv.x*(16*mx+8) + (double)mv.y*(16*my+8);
2842                                  iMinSAD = iSAD;                          DtimesF[2] += (double)mv.x*(16*my+8) - (double)mv.y*(16*mx+8);
2843                            DtimesF[3] += (double)mv.y;
2844                          }                          }
                 }  
   
                 if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {  
                         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);  
2845    
2846                          if (iSAD < iMinSAD) {          invdenom = a*a+b*b-c*n;
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
                 }  
         }  
2847    
2848  /*  /* Solve the system:    sol = (D'*E*D)^{-1} D'*E*F   */
2849     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  /* D'*E*F has been calculated in the same loop as matrix */
 */  
2850    
2851  PMVfastInt16_Terminate_with_Refine:          sol[0] = -c*DtimesF[0] + a*DtimesF[1] + b*DtimesF[2];
2852            sol[1] =  a*DtimesF[0] - n*DtimesF[1]                           + b*DtimesF[3];
2853            sol[2] =  b*DtimesF[0]                          - n*DtimesF[2] - a*DtimesF[3];
2854            sol[3] =                                 b*DtimesF[1] - a*DtimesF[2] - c*DtimesF[3];
2855    
2856          pMB->i_mvs[0] = pMB->i_mvs[1] = pMB->i_mvs[2] = pMB->i_mvs[3] = pMB->i_mv16 = *currMV;          sol[0] /= invdenom;
2857          pMB->i_sad8[0] = pMB->i_sad8[1] = pMB->i_sad8[2] = pMB->i_sad8[3] = pMB->i_sad16 = iMinSAD;          sol[1] /= invdenom;
2858            sol[2] /= invdenom;
2859            sol[3] /= invdenom;
2860    
2861          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step          meanx = meany = 0.;
2862                  iMinSAD =          oldnum = 0;
2863                          Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,          for (my = 1; my < (uint32_t)MBh-1; my++)
2864                                                           iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,                  for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2865                                                           iFcode, iQuant, iEdgedWidth);                  {
2866                            const int mbnum = mx + my * MBw;
2867                            const VECTOR mv = pMBs[mbnum].mvs[0];
2868    
2869          pmv[0] = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          // get _REAL_ prediction (halfpel possible)                          if (!pMBs[mbnum].mcsel)
2870                                    continue;
2871    
2872  PMVfastInt16_Terminate_without_Refine:                          oldnum++;
2873          currPMV->x = currMV->x - center_x;                          meanx += fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - (double)mv.x );
2874          currPMV->y = currMV->y - center_y;                          meany += fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - (double)mv.y );
         return iMinSAD;  
2875  }  }
2876    
2877            if (4*meanx > oldnum)   /* better fit than 0.25 (=1/4pel) is useless */
2878                    meanx /= oldnum;
2879            else
2880                    meanx = 0.25;
2881    
2882            if (4*meany > oldnum)
2883                    meany /= oldnum;
2884            else
2885                    meany = 0.25;
2886    
2887  /* ***********************************************************          num = 0;
2888          bvop motion estimation          for (my = 0; my < (uint32_t)MBh; my++)
2889  ***************************************************************/                  for (mx = 0; mx < (uint32_t)MBw; mx++)
   
 void  
 MotionEstimationBVOP(MBParam * const pParam,  
                                          FRAMEINFO * const frame,  
                                          const int32_t time_bp,  
                                          const int32_t time_pp,  
                                          // forward (past) reference  
                                          const MACROBLOCK * const f_mbs,  
                                          const IMAGE * const f_ref,  
                                          const IMAGE * const f_refH,  
                                          const IMAGE * const f_refV,  
                                          const IMAGE * const f_refHV,  
                                          // backward (future) reference  
                                          const MACROBLOCK * const b_mbs,  
                                          const IMAGE * const b_ref,  
                                          const IMAGE * const b_refH,  
                                          const IMAGE * const b_refV,  
                                          const IMAGE * const b_refHV)  
2890  {  {
2891          const int mb_width = pParam->mb_width;                          const int mbnum = mx + my * MBw;
2892          const int mb_height = pParam->mb_height;                          const VECTOR mv = pMBs[mbnum].mvs[0];
         const int edged_width = pParam->edged_width;  
2893    
2894          const int32_t iWidth = pParam->width;                          if (!pMBs[mbnum].mcsel)
2895          const int32_t iHeight = pParam->height;                                  continue;
2896    
2897          int i, j, k;                          if  ( ( fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - (double)mv.x ) > meanx )
2898                                    || ( fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - (double)mv.y ) > meany ) )
2899                                    pMBs[mbnum].mcsel=0;
2900                            else
2901                                    num++;
2902                    }
2903    
2904          static const VECTOR zeroMV={0,0};          } while ( (oldnum != num) && (num>= minblocks) );
2905    
2906          int f_sad16;    /* forward (as usual) search */          if (num < minblocks)
2907          int b_sad16;    /* backward (only in b-frames) search */          {
2908          int i_sad16;    /* interpolated (both direction, b-frames only) */                  const int iEdgedWidth = pParam->edged_width;
2909          int d_sad16;    /* direct mode (assume almost linear motion) */                  num = 0;
2910    
2911          int best_sad;  /*              fprintf(stderr,"Warning! Unreliable GME (%d/%d blocks), falling back to translation.\n",num,MBh*MBw);
2912    */
2913                    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;
2914    
2915          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/                  if (!(current->motion_flags & XVID_ME_GME_REFINE))
2916          VECTOR f_interpolMV, b_interpolMV;                          return gmc;
         VECTOR pmv_dontcare;  
2917    
2918          int min_dx, max_dx, min_dy, max_dy;                  for (my = 1; my < (uint32_t)MBh-1; my++) /* ignore boundary blocks */
2919          int f_min_dx, f_max_dx, f_min_dy, f_max_dy;                  for (mx = 1; mx < (uint32_t)MBw-1; mx++) /* theirs MVs are often wrong */
2920          int b_min_dx, b_max_dx, b_min_dy, b_max_dy;                  {
2921                            const int mbnum = mx + my * MBw;
2922          int f_count=0;                          MACROBLOCK *const pMB = &pMBs[mbnum];
2923          int b_count=0;                          const uint8_t *const pCur = current->image.y + 16*(my*iEdgedWidth + mx);
2924          int i_count=0;                          if ( (sad16 ( pCur, pCur+1 , iEdgedWidth, 65536) >= gradx )
2925          int d_count=0;                           &&  (sad16 ( pCur, pCur+iEdgedWidth, iEdgedWidth, 65536) >= grady ) )
2926                             {      pMB->mcsel = 1;
2927          const int64_t TRB = (int32_t)time_pp - (int32_t)time_bp;                                  gmc.duv[0].x += pMB->mvs[0].x;
2928      const int64_t TRD = (int32_t)time_pp;                                  gmc.duv[0].y += pMB->mvs[0].y;
2929                                    num++;
2930          // 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), cpb=0 without further ado */  
   
 #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;  
                                 continue;  
2931                          }                          }
 #endif  
2932    
2933                          if (b_mb->mode == MODE_INTER4V)                  if (gmc.duv[0].x)
2934                          {                          gmc.duv[0].x /= num;
2935                                  d_sad16 = 0;                  if (gmc.duv[0].y)
2936                          /* same method of scaling as in decoder.c, so we copy from there */                          gmc.duv[0].y /= num;
2937                      for (k = 0; k < 4; k++) {          } else {
2938    
2939                                          mb->directmv[k] = b_mb->mvs[k];                  gmc.duv[0].x=(int)(sol[0]+0.5);
2940                    gmc.duv[0].y=(int)(sol[3]+0.5);
2941    
2942                                          mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);                  gmc.duv[1].x=(int)(sol[1]*pParam->width+0.5);
2943                      mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)                  gmc.duv[1].y=(int)(-sol[2]*pParam->width+0.5);
2944                                                                                  ? ((TRB - TRD) * mb->directmv[k].x) / TRD  
2945                                              : mb->mvs[k].x - mb->directmv[k].x);                  gmc.duv[2].x=-gmc.duv[1].y;             /* two warp points only */
2946                    gmc.duv[2].y=gmc.duv[1].x;
                     mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);  
                         mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)  
                                                                                 ? ((TRB - TRD) * mb->directmv[k].y) / TRD  
                                             : mb->mvs[k].y - mb->directmv[k].y);  
   
                                         d_sad16 +=  
                                                 sad8bi(frame->image.y + 2*(i+(k&1))*8 + 2*(j+(k>>1))*8*edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 2*(i+(k&1)), 2*(j+(k>>1)), 8, &mb->mvs[k], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 2*(i+(k&1)), 2*(j+(k>>1)), 8, &mb->b_mvs[k], edged_width),  
                                                   edged_width);  
                                 }  
2947                          }                          }
2948            if (num>maxblocks)
2949            {       for (my = 1; my < (uint32_t)MBh-1; my++)
2950                    for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2951                    {
2952                            const int mbnum = mx + my * MBw;
2953                            if (pMBs[mbnum-1].mcsel)
2954                                    pMBs[mbnum].mcsel=0;
2955                          else                          else
2956                          {                                  if (pMBs[mbnum-MBw].mcsel)
2957                                  mb->directmv[3] = mb->directmv[2] = mb->directmv[1] =                                          pMBs[mbnum].mcsel=0;
2958                                          mb->directmv[0] = b_mb->mvs[0];                  }
2959            }
2960                                  mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);          return gmc;
                     mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)  
                                                                         ? ((TRB - TRD) * mb->directmv[0].x) / TRD  
                                     : mb->mvs[0].x - mb->directmv[0].x);  
   
                     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);  
   
2961              }              }
                     d_sad16 += calc_delta_16(mb->deltamv.x, mb->deltamv.y, 1, frame->quant);  
   
                         // forward search  
                         f_sad16 = SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 &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);  
2962    
2963    int
2964    GlobalMotionEstRefine(
2965                                    WARPPOINTS *const startwp,
2966                                    MACROBLOCK * const pMBs,
2967                                    const MBParam * const pParam,
2968                                    const FRAMEINFO * const current,
2969                                    const FRAMEINFO * const reference,
2970                                    const IMAGE * const pCurr,
2971                                    const IMAGE * const pRef,
2972                                    const IMAGE * const pRefH,
2973                                    const IMAGE * const pRefV,
2974                                    const IMAGE * const pRefHV)
2975    {
2976            uint8_t* GMCblock = (uint8_t*)malloc(16*pParam->edged_width);
2977            WARPPOINTS bestwp=*startwp;
2978            WARPPOINTS centerwp,currwp;
2979            int gmcminSAD=0;
2980            int gmcSAD=0;
2981            int direction;
2982    //      int mx,my;
2983    
2984                          // backward search  /* use many blocks... */
2985                          b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  /*              for (my = 0; my < (uint32_t)pParam->mb_height; my++)
2986                                                  &frame->image, i, j,                  for (mx = 0; mx < (uint32_t)pParam->mb_width; mx++)
2987                                                  mb->b_mvs[0].x, mb->b_mvs[0].y,         /* start point b_directMV */                  {
2988                                                  b_predMV.x, b_predMV.y,                         /* center is b-prediction */                          const int mbnum = mx + my * pParam->mb_width;
2989                                                  frame->motion_flags,                          pMBs[mbnum].mcsel=1;
                                                 frame->quant, frame->bcode, pParam,  
                                                 b_mbs, b_mbs,  
                                                 &mb->b_mvs[0], &pmv_dontcare);  
   
                         i_sad16 =  
                                 sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 i, j, 16, &mb->mvs[0], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 i, j, 16, &mb->b_mvs[0], edged_width),  
                                                   edged_width);  
                     i_sad16 += calc_delta_16(mb->mvs[0].x-f_predMV.x, mb->mvs[0].y-f_predMV.y,  
                                                                 frame->fcode, frame->quant);  
                     i_sad16 += calc_delta_16(mb->b_mvs[0].x-b_predMV.x, mb->b_mvs[0].y-b_predMV.y,  
                                                                 frame->bcode, frame->quant);  
   
                         get_range(&f_min_dx, &f_max_dx, &f_min_dy, &f_max_dy, i, j, 16, iWidth, iHeight,  
                           frame->fcode);  
                         get_range(&b_min_dx, &b_max_dx, &b_min_dy, &b_max_dy, i, j, 16, iWidth, iHeight,  
                           frame->bcode);  
   
 /* Interpolated MC motion vector search, this is tedious and more complicated because there are  
    two values for everything, always one for backward and one for forward ME. Still, we don't gain  
    much from this search, maybe it should simply be skipped and simply current i_sad16 value used  
    as "optimal". */  
   
                         i_sad16 = Diamond16_InterpolMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i * 16 + j * 16 * edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 mb->mvs[0].x, mb->mvs[0].y,  
                                                 mb->b_mvs[0].x, mb->b_mvs[0].y,  
                                                 i_sad16,  
                                                 &f_interpolMV, &b_interpolMV,  
                                                 f_predMV.x, f_predMV.y, b_predMV.x, b_predMV.y,  
                                                 f_min_dx, f_max_dx, f_min_dy, f_max_dy,  
                                                 b_min_dx, b_max_dx, b_min_dy, b_max_dy,  
                                                 edged_width,  1,  
                                                 frame->fcode, frame->bcode,frame->quant,0);  
   
   
 /*  DIRECT MODE DELTA VECTOR SEARCH.  
     This has to be made more effective, but at the moment I'm happy it's running at all */  
   
 /* range is taken without fcode restriction, just a hack instead of writing down the dimensions, of course */  
   
                         get_range(&min_dx, &max_dx, &min_dy, &max_dy, i, j, 16, iWidth, iHeight, 19);  
   
                         d_sad16 = Diamond16_DirectMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i*16 + j*16*edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 TRB,TRD,  
                                                 0,0,  
                                                 d_sad16,  
                                                 &mb->deltamv,  
                                                 mb->directmv, // this has to be pre-initialized with b_mb->mvs[}  
                                         min_dx, max_dx, min_dy, max_dy,  
                                                 edged_width, 1, frame->quant, 0);  
   
   
 //                      i_sad16 = 65535;                /* remove the comment to disable any of the MODEs */  
 //                      f_sad16 = 65535;  
 //                      b_sad16 = 65535;  
 //                      d_sad16 = 65535;  
   
                         if (f_sad16 < b_sad16) {  
                                 best_sad = f_sad16;  
                                 mb->mode = MODE_FORWARD;  
                         } else {  
                                 best_sad = b_sad16;  
                                 mb->mode = MODE_BACKWARD;  
2990                          }                          }
2991    */
2992    
2993                          if (i_sad16 < best_sad) {  /* or rather don't use too many blocks... */
2994                                  best_sad = i_sad16;  /*
2995                                  mb->mode = MODE_INTERPOLATE;                  for (my = 1; my < (uint32_t)MBh-1; my++)
2996                          }                  for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2997                    {
2998                            const int mbnum = mx + my * MBw;
2999                            if (MBmask[mbnum-1])
3000                                    MBmask[mbnum-1]=0;
3001                            else
3002                                    if (MBmask[mbnum-MBw])
3003                                            MBmask[mbnum-1]=0;
3004    
3005                          if (d_sad16 < best_sad) {                  }
3006    */
3007                    gmcminSAD = globalSAD(&bestwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3008    
3009                                  if (b_mb->mode == MODE_INTER4V)                  if ( (reference->coding_type == S_VOP)
3010                            && ( (reference->warp.duv[1].x != bestwp.duv[1].x)
3011                              || (reference->warp.duv[1].y != bestwp.duv[1].y)
3012                              || (reference->warp.duv[0].x != bestwp.duv[0].x)
3013                              || (reference->warp.duv[0].y != bestwp.duv[0].y)
3014                              || (reference->warp.duv[2].x != bestwp.duv[2].x)
3015                              || (reference->warp.duv[2].y != bestwp.duv[2].y) ) )
3016                                  {                                  {
3017                            gmcSAD = globalSAD(&reference->warp, pParam, pMBs,
3018                                                                    current, pRef, pCurr, GMCblock);
3019    
3020                            if (gmcSAD < gmcminSAD)
3021                            {       bestwp = reference->warp;
3022                                    gmcminSAD = gmcSAD;
3023                            }
3024                    }
3025    
3026                                  /* how to calc vectors is defined in standard. mvs[] and b_mvs[] are only for motion compensation */          do {
3027                                  /* for the bitstream, the value mb->deltamv is read directly */                  direction = 0;
3028                    centerwp = bestwp;
3029    
3030                              for (k = 0; k < 4; k++) {                  currwp = centerwp;
3031    
3032                                                  mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);                  currwp.duv[0].x--;
3033                              mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)                  gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3034                                                                                          ? ((TRB - TRD) * mb->directmv[k].x) / TRD                  if (gmcSAD < gmcminSAD)
3035                                                      : mb->mvs[k].x - mb->directmv[k].x);                  {       bestwp = currwp;
3036                            gmcminSAD = gmcSAD;
3037                              mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);                          direction = 1;
3038                          mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)                  }
3039                                                                                          ? ((TRB - TRD) * mb->directmv[k].y) / TRD                  else
3040                                              : mb->mvs[k].y - mb->directmv[k].y);                  {
3041                    currwp = centerwp; currwp.duv[0].x++;
3042                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3043                    if (gmcSAD < gmcminSAD)
3044                    {       bestwp = currwp;
3045                            gmcminSAD = gmcSAD;
3046                            direction = 2;
3047                    }
3048                    }
3049                    if (direction) continue;
3050    
3051                    currwp = centerwp; currwp.duv[0].y--;
3052                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3053                    if (gmcSAD < gmcminSAD)
3054                    {       bestwp = currwp;
3055                            gmcminSAD = gmcSAD;
3056                            direction = 4;
3057                    }
3058                    else
3059                    {
3060                    currwp = centerwp; currwp.duv[0].y++;
3061                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3062                    if (gmcSAD < gmcminSAD)
3063                    {       bestwp = currwp;
3064                            gmcminSAD = gmcSAD;
3065                            direction = 8;
3066                    }
3067                    }
3068                    if (direction) continue;
3069    
3070                    currwp = centerwp; currwp.duv[1].x++;
3071                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3072                    if (gmcSAD < gmcminSAD)
3073                    {       bestwp = currwp;
3074                            gmcminSAD = gmcSAD;
3075                            direction = 32;
3076                    }
3077                    currwp.duv[2].y++;
3078                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3079                    if (gmcSAD < gmcminSAD)
3080                    {       bestwp = currwp;
3081                            gmcminSAD = gmcSAD;
3082                            direction = 1024;
3083                    }
3084    
3085                    currwp = centerwp; currwp.duv[1].x--;
3086                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3087                    if (gmcSAD < gmcminSAD)
3088                    {       bestwp = currwp;
3089                            gmcminSAD = gmcSAD;
3090                            direction = 16;
3091                    }
3092                    else
3093                    {
3094                    currwp = centerwp; currwp.duv[1].x++;
3095                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3096                    if (gmcSAD < gmcminSAD)
3097                    {       bestwp = currwp;
3098                            gmcminSAD = gmcSAD;
3099                            direction = 32;
3100                    }
3101                    }
3102                    if (direction) continue;
3103    
3104    
3105                    currwp = centerwp; currwp.duv[1].y--;
3106                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3107                    if (gmcSAD < gmcminSAD)
3108                    {       bestwp = currwp;
3109                            gmcminSAD = gmcSAD;
3110                            direction = 64;
3111                                          }                                          }
3112                    else
3113                    {
3114                    currwp = centerwp; currwp.duv[1].y++;
3115                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3116                    if (gmcSAD < gmcminSAD)
3117                    {       bestwp = currwp;
3118                            gmcminSAD = gmcSAD;
3119                            direction = 128;
3120                    }
3121                    }
3122                    if (direction) continue;
3123    
3124                    currwp = centerwp; currwp.duv[2].x--;
3125                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3126                    if (gmcSAD < gmcminSAD)
3127                    {       bestwp = currwp;
3128                            gmcminSAD = gmcSAD;
3129                            direction = 256;
3130                    }
3131                    else
3132                    {
3133                    currwp = centerwp; currwp.duv[2].x++;
3134                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3135                    if (gmcSAD < gmcminSAD)
3136                    {       bestwp = currwp;
3137                            gmcminSAD = gmcSAD;
3138                            direction = 512;
3139                    }
3140                    }
3141                    if (direction) continue;
3142    
3143                    currwp = centerwp; currwp.duv[2].y--;
3144                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3145                    if (gmcSAD < gmcminSAD)
3146                    {       bestwp = currwp;
3147                            gmcminSAD = gmcSAD;
3148                            direction = 1024;
3149                                  }                                  }
3150                                  else                                  else
3151                                  {                                  {
3152                                          mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);                  currwp = centerwp; currwp.duv[2].y++;
3153                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3154                    if (gmcSAD < gmcminSAD)
3155                    {       bestwp = currwp;
3156                            gmcminSAD = gmcSAD;
3157                            direction = 2048;
3158                    }
3159                    }
3160            } while (direction);
3161            free(GMCblock);
3162    
3163                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)          *startwp = bestwp;
                                                                                 ? ((TRB - TRD) * mb->directmv[0].x) / TRD  
                                         : mb->mvs[0].x - mb->directmv[0].x);  
3164    
3165                              mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);          return gmcminSAD;
3166    }
3167    
3168                          mb->b_mvs[0].y = (int32_t) ((mb->deltamv.y == 0)  int
3169                                                                                  ? ((TRB - TRD) * mb->directmv[0].y) / TRD  globalSAD(const WARPPOINTS *const wp,
3170                                              : mb->mvs[0].y - mb->directmv[0].y);                    const MBParam * const pParam,
3171                      const MACROBLOCK * const pMBs,
3172                      const FRAMEINFO * const current,
3173                      const IMAGE * const pRef,
3174                      const IMAGE * const pCurr,
3175                      uint8_t *const GMCblock)
3176    {
3177            NEW_GMC_DATA gmc_data;
3178            int iSAD, gmcSAD=0;
3179            int num=0;
3180            unsigned int mx, my;
3181    
3182                                          mb->mvs[3] = mb->mvs[2] = mb->mvs[1] = mb->mvs[0];          generate_GMCparameters( 3, 3, wp, pParam->width, pParam->height, &gmc_data);
                                         mb->b_mvs[3] = mb->b_mvs[2] = mb->b_mvs[1] = mb->b_mvs[0];  
                 }  
3183    
3184                                  best_sad = d_sad16;          for (my = 0; my < (uint32_t)pParam->mb_height; my++)
3185                                  mb->mode = MODE_DIRECT;                  for (mx = 0; mx < (uint32_t)pParam->mb_width; mx++) {
                         }  
3186    
3187                          switch (mb->mode)                  const int mbnum = mx + my * pParam->mb_width;
3188                          {                  const int iEdgedWidth = pParam->edged_width;
                                 case MODE_FORWARD:  
                                         f_count++;  
                                         f_predMV = mb->mvs[0];  
                                         break;  
                                 case MODE_BACKWARD:  
                                         b_count++;  
                                         b_predMV = mb->b_mvs[0];  
3189    
3190                                          break;                  if (!pMBs[mbnum].mcsel)
3191                                  case MODE_INTERPOLATE:                          continue;
                                         i_count++;  
                                         mb->mvs[0] = f_interpolMV;  
                                         mb->b_mvs[0] = b_interpolMV;  
                                         f_predMV = mb->mvs[0];  
                                         b_predMV = mb->b_mvs[0];  
                                         break;  
                                 case MODE_DIRECT:  
                                         d_count++;  
                                         break;  
                                 default:  
                                         break;  
                         }  
3192    
3193                    gmc_data.predict_16x16(&gmc_data, GMCblock,
3194                                                    pRef->y,
3195                                                    iEdgedWidth,
3196                                                    iEdgedWidth,
3197                                                    mx, my,
3198                                                    pParam->m_rounding_type);
3199    
3200                    iSAD = sad16 ( pCurr->y + 16*(my*iEdgedWidth + mx),
3201                                                    GMCblock , iEdgedWidth, 65536);
3202                    iSAD -= pMBs[mbnum].sad16;
3203    
3204                    if (iSAD<0)
3205                            gmcSAD += iSAD;
3206                    num++;
3207                  }                  }
3208            return gmcSAD;
3209          }          }
3210    
 #ifdef _DEBUG_BFRAME_STAT  
         fprintf(stderr,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d\n",  
                                 f_count,b_count,i_count,d_count);  
 #endif  
   
 }  

Legend:
Removed from v.346  
changed lines
  Added in v.1135

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