[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 1107, Sat Aug 2 15:08:48 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.24 2003-08-02 15:08:39 edgomez 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), (D), &iDirection, data ); }
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            y <<= qpel;
88            if (rrv) { x = RRV_MV_SCALEDOWN(x); y = RRV_MV_SCALEDOWN(y); }
89    
90            x -= pred.x;
91            bits = (x != 0 ? iFcode:0);
92            x = abs(x);
93            x += q;
94            x >>= (iFcode - 1);
95            bits += mvtab[x];
96    
97            y -= pred.y;
98            bits += (y != 0 ? iFcode:0);
99            y = abs(y);
100            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 = data->RefQ,
113                    * f_refv = data->RefQ + 8,
114                    * b_refu = data->RefQ + 16,
115                    * b_refv = data->RefQ + 24;
116            int offset = (fx>>1) + (fy>>1)*stride;
117    
118            switch (((fx & 1) << 1) | (fy & 1))     {
119                    case 0:
120                            f_refu = (uint8_t*)data->RefP[4] + offset;
121                            f_refv = (uint8_t*)data->RefP[5] + offset;
122                            break;
123                    case 1:
124                            interpolate8x8_halfpel_v(f_refu, data->RefP[4] + offset, stride, data->rounding);
125                            interpolate8x8_halfpel_v(f_refv, data->RefP[5] + offset, stride, data->rounding);
126                            break;
127                    case 2:
128                            interpolate8x8_halfpel_h(f_refu, data->RefP[4] + offset, stride, data->rounding);
129                            interpolate8x8_halfpel_h(f_refv, data->RefP[5] + offset, stride, data->rounding);
130                            break;
131                    default:
132                            interpolate8x8_halfpel_hv(f_refu, data->RefP[4] + offset, stride, data->rounding);
133                            interpolate8x8_halfpel_hv(f_refv, data->RefP[5] + offset, stride, data->rounding);
134                            break;
135            }
136    
137  static int32_t lambda_vec16[32] =       /* rounded values for lambda param for weight of motion bits as in modified H.26L */          offset = (bx>>1) + (by>>1)*stride;
138  { 0, (int) (1.00235 + 0.5), (int) (1.15582 + 0.5), (int) (1.31976 + 0.5),          switch (((bx & 1) << 1) | (by & 1))     {
139                  (int) (1.49591 + 0.5), (int) (1.68601 + 0.5),                  case 0:
140          (int) (1.89187 + 0.5), (int) (2.11542 + 0.5), (int) (2.35878 + 0.5),                          b_refu = (uint8_t*)data->b_RefP[4] + offset;
141                  (int) (2.62429 + 0.5), (int) (2.91455 + 0.5),                          b_refv = (uint8_t*)data->b_RefP[5] + offset;
142          (int) (3.23253 + 0.5), (int) (3.58158 + 0.5), (int) (3.96555 + 0.5),                          break;
143                  (int) (4.38887 + 0.5), (int) (4.85673 + 0.5),                  case 1:
144          (int) (5.37519 + 0.5), (int) (5.95144 + 0.5), (int) (6.59408 + 0.5),                          interpolate8x8_halfpel_v(b_refu, data->b_RefP[4] + offset, stride, data->rounding);
145                  (int) (7.31349 + 0.5), (int) (8.12242 + 0.5),                          interpolate8x8_halfpel_v(b_refv, data->b_RefP[5] + offset, stride, data->rounding);
146          (int) (9.03669 + 0.5), (int) (10.0763 + 0.5), (int) (11.2669 + 0.5),                          break;
147                  (int) (12.6426 + 0.5), (int) (14.2493 + 0.5),                  case 2:
148          (int) (16.1512 + 0.5), (int) (18.442 + 0.5), (int) (21.2656 + 0.5),                          interpolate8x8_halfpel_h(b_refu, data->b_RefP[4] + offset, stride, data->rounding);
149                  (int) (24.8580 + 0.5), (int) (29.6436 + 0.5),                          interpolate8x8_halfpel_h(b_refv, data->b_RefP[5] + offset, stride, data->rounding);
150          (int) (36.4949 + 0.5)                          break;
151  };                  default:
152                            interpolate8x8_halfpel_hv(b_refu, data->b_RefP[4] + offset, stride, data->rounding);
153  static int32_t *lambda_vec8 = lambda_vec16;     /* same table for INTER and INTER4V for now */                          interpolate8x8_halfpel_hv(b_refv, data->b_RefP[5] + offset, stride, data->rounding);
154                            break;
155            }
156    
157  // mv.length table          sad = sad8bi(data->CurU, b_refu, f_refu, stride);
158  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  
 };  
159    
160            return sad;
161    }
162    
163  static __inline uint32_t  static int32_t
164  mv_bits(int32_t component,  ChromaSAD(const int dx, const int dy, const SearchData * const data)
                 const uint32_t iFcode)  
165  {  {
166          if (component == 0)          int sad;
167                  return 1;          const uint32_t stride = data->iEdgedWidth/2;
168            int offset = (dx>>1) + (dy>>1)*stride;
169    
170          if (component < 0)          if (dx == data->temp[5] && dy == data->temp[6]) return data->temp[7]; /* it has been checked recently */
171                  component = -component;          data->temp[5] = dx; data->temp[6] = dy; /* backup */
172    
173          if (iFcode == 1) {          switch (((dx & 1) << 1) | (dy & 1))     {
174                  if (component > 32)                  case 0:
175                          component = 32;                          sad = sad8(data->CurU, data->RefP[4] + offset, stride);
176                            sad += sad8(data->CurV, data->RefP[5] + offset, stride);
177                            break;
178                    case 1:
179                            sad = sad8bi(data->CurU, data->RefP[4] + offset, data->RefP[4] + offset + stride, stride);
180                            sad += sad8bi(data->CurV, data->RefP[5] + offset, data->RefP[5] + offset + stride, stride);
181                            break;
182                    case 2:
183                            sad = sad8bi(data->CurU, data->RefP[4] + offset, data->RefP[4] + offset + 1, stride);
184                            sad += sad8bi(data->CurV, data->RefP[5] + offset, data->RefP[5] + offset + 1, stride);
185                            break;
186                    default:
187                            interpolate8x8_halfpel_hv(data->RefQ, data->RefP[4] + offset, stride, data->rounding);
188                            sad = sad8(data->CurU, data->RefQ, stride);
189    
190                  return mvtab[component] + 1;                          interpolate8x8_halfpel_hv(data->RefQ, data->RefP[5] + offset, stride, data->rounding);
191                            sad += sad8(data->CurV, data->RefQ, stride);
192                            break;
193          }          }
194            data->temp[7] = sad; /* backup, part 2 */
195          component += (1 << (iFcode - 1)) - 1;          return sad;
         component >>= (iFcode - 1);  
   
         if (component > 32)  
                 component = 32;  
   
         return mvtab[component] + 1 + iFcode - 1;  
196  }  }
197    
198    static __inline const uint8_t *
199  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)  
200  {  {
201          return NEIGH_TEND_16X16 * lambda_vec16[iQuant] * (mv_bits(dx, iFcode) +          /* dir : 0 = forward, 1 = backward */
202                                                                                                            mv_bits(dy, iFcode));          const uint8_t *const *const direction = ( dir == 0 ? data->RefP : data->b_RefP );
203            const int picture = ((x&1)<<1) | (y&1);
204            const int offset = (x>>1) + (y>>1)*data->iEdgedWidth;
205            return direction[picture] + offset;
206  }  }
207    
208  static __inline uint32_t  /* this is a simpler copy of GetReferenceB, but as it's __inline anyway, we can keep the two separate */
209  calc_delta_8(const int32_t dx,  static __inline const uint8_t *
210                           const int32_t dy,  GetReference(const int x, const int y, const SearchData * const data)
                          const uint32_t iFcode,  
                          const uint32_t iQuant)  
211  {  {
212          return NEIGH_TEND_8X8 * lambda_vec8[iQuant] * (mv_bits(dx, iFcode) +          const int picture = ((x&1)<<1) | (y&1);
213                                                                                                     mv_bits(dy, iFcode));          const int offset = (x>>1) + (y>>1)*data->iEdgedWidth;
214            return data->RefP[picture] + offset;
215  }  }
216    
217  bool  static uint8_t *
218  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)  
219  {  {
220          const uint32_t iWcount = pParam->mb_width;          /* create or find a qpel-precision reference picture; return pointer to it */
221          const uint32_t iHcount = pParam->mb_height;          uint8_t * Reference = data->RefQ + 16*dir;
222          MACROBLOCK *const pMBs = current->mbs;          const uint32_t iEdgedWidth = data->iEdgedWidth;
223          MACROBLOCK *const prevMBs = reference->mbs;          const uint32_t rounding = data->rounding;
224          const IMAGE *const pCurrent = &current->image;          const int halfpel_x = x/2;
225          const IMAGE *const pRef = &reference->image;          const int halfpel_y = y/2;
226            const uint8_t *ref1, *ref2, *ref3, *ref4;
         static const VECTOR zeroMV = { 0, 0 };  
         VECTOR predMV;  
227    
228          int32_t x, y;          ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
229          int32_t iIntra = 0;          ref1 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
230          VECTOR pmv;          switch( ((x&1)<<1) + (y&1) ) {
231            case 3: /* x and y in qpel resolution - the "corners" (top left/right and */
232          if (sadInit)                          /* bottom left/right) during qpel refinement */
233                  (*sadInit) ();                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
234                    ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
235                    ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);
236                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
237                    ref3 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
238                    ref4 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
239                    interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
240                    break;
241    
242          for (y = 0; y < iHcount; y++)   {          case 1: /* x halfpel, y qpel - top or bottom during qpel refinement */
243                  for (x = 0; x < iWcount; x ++)  {                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
244                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
245                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
246                    break;
247    
248                          MACROBLOCK *const pMB = &pMBs[x + y * iWcount];          case 2: /* x qpel, y halfpel - left or right during qpel refinement */
249                    ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
250                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
251                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
252                    break;
253    
254                          predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          default: /* pure halfpel position */
255                    return (uint8_t *) ref1;
256    
257                          pMB->sad16 =          }
258                                  SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,          return Reference;
259                                                   x, y, predMV.x, predMV.y, predMV.x, predMV.y,  }
                                                  current->motion_flags, current->quant,  
                                                  current->fcode, pParam, pMBs, prevMBs, &pMB->mv16,  
                                                  &pMB->pmvs[0]);  
260    
261                          if (0 < (pMB->sad16 - MV16_INTER_BIAS)) {  static uint8_t *
262                                  int32_t deviation;  Interpolate16x16qpel(const int x, const int y, const uint32_t dir, const SearchData * const data)
263    {
264            /* create or find a qpel-precision reference picture; return pointer to it */
265            uint8_t * Reference = data->RefQ + 16*dir;
266            const uint32_t iEdgedWidth = data->iEdgedWidth;
267            const uint32_t rounding = data->rounding;
268            const int halfpel_x = x/2;
269            const int halfpel_y = y/2;
270            const uint8_t *ref1, *ref2, *ref3, *ref4;
271    
272                                  deviation =          ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
273                                          dev16(pCurrent->y + x * 16 + y * 16 * pParam->edged_width,          switch( ((x&1)<<1) + (y&1) ) {
274                                                    pParam->edged_width);          case 3:
275                    /*
276                     * x and y in qpel resolution - the "corners" (top left/right and
277                     * bottom left/right) during qpel refinement
278                     */
279                    ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
280                    ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
281                    ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);
282                    interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
283                    interpolate8x8_avg4(Reference+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, rounding);
284                    interpolate8x8_avg4(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, rounding);
285                    interpolate8x8_avg4(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, rounding);
286                    break;
287    
288                                  if (deviation < (pMB->sad16 - MV16_INTER_BIAS)) {          case 1: /* x halfpel, y qpel - top or bottom during qpel refinement */
289                                          pMB->mode = MODE_INTRA;                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
290                                          pMB->mv16 = pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
291                                                  pMB->mvs[3] = zeroMV;                  interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
292                                          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);
293                                                  pMB->sad8[3] = 0;                  interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
294                    break;
295    
296                                          iIntra++;          case 2: /* x qpel, y halfpel - left or right during qpel refinement */
297                                          if (iIntra >= iLimit)                  ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
298                                                  return 1;                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
299                    interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
300                    interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
301                    interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
302                    break;
303    
304                                          continue;          default: /* pure halfpel position */
305                    return (uint8_t *) ref1;
306                                  }                                  }
307            return Reference;
308                          }                          }
309    
310                          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]);  
                                         }  
311    
312                                          /* decide: MODE_INTER or MODE_INTER4V  static void
313                                             mpeg4:   if (sad8 < pMB->sad16 - nb/2+1) use_inter4v  CheckCandidate16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
314                                           */  {
315            int xc, yc;
316            const uint8_t * Reference;
317            VECTOR * current;
318            int32_t sad; uint32_t t;
319    
320                                          if (sad8 < pMB->sad16) {          if ( (x > data->max_dx) || (x < data->min_dx)
321                                                  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;  
                                         }  
322    
323            if (!data->qpel_precision) {
324                    Reference = GetReference(x, y, data);
325                    current = data->currentMV;
326                    xc = x; yc = y;
327            } else { /* x and y are in 1/4 precision */
328                    Reference = Interpolate16x16qpel(x, y, 0, data);
329                    xc = x/2; yc = y/2; /* for chroma sad */
330                    current = data->currentQMV;
331                                  }                                  }
332    
333                          pMB->mode = MODE_INTER;          sad = sad16v(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
334                          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);
335                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mv16;  
336                          pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] =          sad += (data->lambda16 * t * sad)>>10;
337                                  pMB->sad16;          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;
338    
339            if (data->chroma && sad < data->iMinSAD[0])
340                    sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
341                                                            (yc >> 1) + roundtab_79[yc & 0x3], data);
342    
343            if (sad < data->iMinSAD[0]) {
344                    data->iMinSAD[0] = sad;
345                    current[0].x = x; current[0].y = y;
346                    *dir = Direction;
347                          }                          }
348    
349            if (data->temp[1] < data->iMinSAD[1]) {
350                    data->iMinSAD[1] = data->temp[1]; current[1].x = x; current[1].y = y; }
351            if (data->temp[2] < data->iMinSAD[2]) {
352                    data->iMinSAD[2] = data->temp[2]; current[2].x = x; current[2].y = y; }
353            if (data->temp[3] < data->iMinSAD[3]) {
354                    data->iMinSAD[3] = data->temp[3]; current[3].x = x; current[3].y = y; }
355            if (data->temp[4] < data->iMinSAD[4]) {
356                    data->iMinSAD[4] = data->temp[4]; current[4].x = x; current[4].y = y; }
357                          }                          }
358    
359          return 0;  static void
360    CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
361    {
362            int32_t sad; uint32_t t;
363            const uint8_t * Reference;
364            VECTOR * current;
365    
366            if ( (x > data->max_dx) || (x < data->min_dx)
367                    || (y > data->max_dy) || (y < data->min_dy) ) return;
368    
369            if (!data->qpel_precision) {
370                    Reference = GetReference(x, y, data);
371                    current = data->currentMV;
372            } else { /* x and y are in 1/4 precision */
373                    Reference = Interpolate8x8qpel(x, y, 0, 0, data);
374                    current = data->currentQMV;
375  }  }
376    
377            sad = sad8(data->Cur, Reference, data->iEdgedWidth);
378            t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
379    
380  #define CHECK_MV16_ZERO {\          sad += (data->lambda8 * t * (sad+NEIGH_8X8_BIAS))>>10;
381    if ( (0 <= max_dx) && (0 >= min_dx) \  
382      && (0 <= max_dy) && (0 >= min_dy) ) \          if (sad < *(data->iMinSAD)) {
383    { \                  *(data->iMinSAD) = sad;
384      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \                  current->x = x; current->y = y;
385      iSAD += calc_delta_16(-center_x, -center_y, (uint8_t)iFcode, iQuant);\                  *dir = Direction;
386      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; } } \  
387  }  }
388    
389  /* too slow and not fully functional at the moment */  static void
390  /*  CheckCandidate32(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
 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)  
391  {  {
392          const int32_t iEdgedWidth = pParam->edged_width;          uint32_t t;
393          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;          const uint8_t * Reference;
         int32_t iSAD;  
         VECTOR pred;  
394    
395            if ( (!(x&1) && x !=0) || (!(y&1) && y !=0) || /* non-zero even value */
396                    (x > data->max_dx) || (x < data->min_dx)
397                    || (y > data->max_dy) || (y < data->min_dy) ) return;
398    
399          pred = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          Reference = GetReference(x, y, data);
400            t = d_mv_bits(x, y, data->predMV, data->iFcode, 0, 1);
401    
402          iSAD = sad16( cur,          data->temp[0] = sad32v_c(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
                 get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth),  
                 iEdgedWidth, MV_MAX_ERROR);  
         if (iSAD <= iQuant * 96)  
                 iSAD -= MV16_00_BIAS;  
403    
404          currMV->x = 0;          data->temp[0] += (data->lambda16 * t * data->temp[0]) >> 10;
405          currMV->y = 0;          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;
         currPMV->x = -pred.x;  
         currPMV->y = -pred.y;  
406    
407          return iSAD;          if (data->temp[0] < data->iMinSAD[0]) {
408                    data->iMinSAD[0] = data->temp[0];
409                    data->currentMV[0].x = x; data->currentMV[0].y = y;
410                    *dir = Direction; }
411    
412            if (data->temp[1] < data->iMinSAD[1]) {
413                    data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
414            if (data->temp[2] < data->iMinSAD[2]) {
415                    data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
416            if (data->temp[3] < data->iMinSAD[3]) {
417                    data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
418            if (data->temp[4] < data->iMinSAD[4]) {
419                    data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
420  }  }
 */  
421    
422  int32_t  static void
423  Diamond16_MainSearch(const uint8_t * const pRef,  CheckCandidate16no4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
424                                           const uint8_t * const pRefH,  {
425                                           const uint8_t * const pRefV,          int32_t sad, xc, yc;
426                                           const uint8_t * const pRefHV,          const uint8_t * Reference;
427                                           const uint8_t * const cur,          uint32_t t;
428                                           const int x,          VECTOR * current;
                                          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 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);  
429    
430          if (iDirection) {          if ( (x > data->max_dx) || ( x < data->min_dx)
431                  while (!iFound) {                  || (y > data->max_dy) || (y < data->min_dy) ) return;
432                          iFound = 1;  
433                          backupMV = *currMV;          if (data->rrv && (!(x&1) && x !=0) | (!(y&1) && y !=0) ) return; /* non-zero even value */
434                          iDirectionBackup = iDirection;  
435            if (data->qpel_precision) { /* x and y are in 1/4 precision */
436                          if (iDirectionBackup != 2)                  Reference = Interpolate16x16qpel(x, y, 0, data);
437                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  current = data->currentQMV;
438                                                                                     backupMV.y, 1);                  xc = x/2; yc = y/2;
                         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);  
                 }  
439          } else {          } else {
440                  currMV->x = start_x;                  Reference = GetReference(x, y, data);
441                  currMV->y = start_y;                  current = data->currentMV;
442                    xc = x; yc = y;
443            }
444            t = d_mv_bits(x, y, data->predMV, data->iFcode,
445                                            data->qpel^data->qpel_precision, data->rrv);
446    
447            sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
448            sad += (data->lambda16 * t * sad)>>10;
449    
450            if (data->chroma && sad < *data->iMinSAD)
451                    sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
452                                                            (yc >> 1) + roundtab_79[yc & 0x3], data);
453    
454            if (sad < *(data->iMinSAD)) {
455                    *(data->iMinSAD) = sad;
456                    current->x = x; current->y = y;
457                    *dir = Direction;
458          }          }
         return iMinSAD;  
459  }  }
460    
461  int32_t  static void
462  Square16_MainSearch(const uint8_t * const pRef,  CheckCandidate16I(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
463                                          const uint8_t * const pRefH,  {
464                                          const uint8_t * const pRefV,          int sad;
465                                          const uint8_t * const pRefHV,  //      int xc, yc;
466                                          const uint8_t * const cur,          const uint8_t * Reference;
467                                          const int x,  //      VECTOR * current;
                                         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  
 */  
468    
469          CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);          if ( (x > data->max_dx) || ( x < data->min_dx)
470          CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);                  || (y > data->max_dy) || (y < data->min_dy) ) return;
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         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);  
471    
472            Reference = GetReference(x, y, data);
473    //      xc = x; yc = y;
474    
475          if (iDirection) {          sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
476                  while (!iFound) {  //      sad += d_mv_bits(x, y, data->predMV, data->iFcode, 0, 0);
                         iFound = 1;  
                         backupMV = *currMV;  
477    
478                          switch (iDirection) {  /*      if (data->chroma) sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
479                          case 1:                                                                                  (yc >> 1) + roundtab_79[yc & 0x3], data);
480                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  */
                                                                                    backupMV.y, 1);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  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;  
481    
482                          case 3:          if (sad < data->iMinSAD[0]) {
483                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                  data->iMinSAD[0] = sad;
484                                                                                   4);                  data->currentMV[0].x = x; data->currentMV[0].y = y;
485                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                  *dir = Direction;
486                                                                                   backupMV.y - iDiamondSize, 7);          }
487                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  }
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
488    
489                          case 4:  static void
490                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  CheckCandidate32I(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
491                                                                                   3);  {
492                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          /* maximum speed - for P/B/I decision */
493                                                                                   backupMV.y - iDiamondSize, 5);          int32_t sad;
                                 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);  
494    
495                                  break;          if ( (x > data->max_dx) || (x < data->min_dx)
496                    || (y > data->max_dy) || (y < data->min_dy) ) return;
497    
498                          case 7:          sad = sad32v_c(data->Cur, data->RefP[0] + (x>>1) + (y>>1)*((int)data->iEdgedWidth),
499                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                                          data->iEdgedWidth, data->temp+1);
                                                                                    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;  
500    
501                          case 8:          if (sad < *(data->iMinSAD)) {
502                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,                  *(data->iMinSAD) = sad;
503                                                                                   2);                  data->currentMV[0].x = x; data->currentMV[0].y = y;
504                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                  *dir = Direction;
                                                                                  4);  
                                 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;  
                         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;  
505                          }                          }
506            if (data->temp[1] < data->iMinSAD[1]) {
507                    data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
508            if (data->temp[2] < data->iMinSAD[2]) {
509                    data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
510            if (data->temp[3] < data->iMinSAD[3]) {
511                    data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
512            if (data->temp[4] < data->iMinSAD[4]) {
513                    data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
514    
515                  }                  }
516    
517    static void
518    CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)
519    {
520            int32_t sad, xb, yb, xcf, ycf, xcb, ycb;
521            uint32_t t;
522            const uint8_t *ReferenceF, *ReferenceB;
523            VECTOR *current;
524    
525            if ((xf > data->max_dx) || (xf < data->min_dx) ||
526                    (yf > data->max_dy) || (yf < data->min_dy))
527                    return;
528    
529            if (!data->qpel_precision) {
530                    ReferenceF = GetReference(xf, yf, data);
531                    xb = data->currentMV[1].x; yb = data->currentMV[1].y;
532                    ReferenceB = GetReferenceB(xb, yb, 1, data);
533                    current = data->currentMV;
534                    xcf = xf; ycf = yf;
535                    xcb = xb; ycb = yb;
536          } else {          } else {
537                  currMV->x = start_x;                  ReferenceF = Interpolate16x16qpel(xf, yf, 0, data);
538                  currMV->y = start_y;                  xb = data->currentQMV[1].x; yb = data->currentQMV[1].y;
539          }                  current = data->currentQMV;
540          return iMinSAD;                  ReferenceB = Interpolate16x16qpel(xb, yb, 1, data);
541                    xcf = xf/2; ycf = yf/2;
542                    xcb = xb/2; ycb = yb/2;
543  }  }
544    
545            t = d_mv_bits(xf, yf, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0)
546                     + d_mv_bits(xb, yb, data->bpredMV, data->iFcode, data->qpel^data->qpel_precision, 0);
547    
548  int32_t          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
549  Full16_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)  
 {  
         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);  
550    
551          return iMinSAD;          if (data->chroma && sad < *data->iMinSAD)
552                    sad += ChromaSAD2((xcf >> 1) + roundtab_79[xcf & 0x3],
553                                                            (ycf >> 1) + roundtab_79[ycf & 0x3],
554                                                            (xcb >> 1) + roundtab_79[xcb & 0x3],
555                                                            (ycb >> 1) + roundtab_79[ycb & 0x3], data);
556    
557            if (sad < *(data->iMinSAD)) {
558                    *(data->iMinSAD) = sad;
559                    current->x = xf; current->y = yf;
560                    *dir = Direction;
561            }
562  }  }
563    
564  int32_t  static void
565  AdvDiamond16_MainSearch(const uint8_t * const pRef,  CheckCandidateDirect(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                                                 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)  
566  {  {
567            int32_t sad = 0, xcf = 0, ycf = 0, xcb = 0, ycb = 0;
568            uint32_t k;
569            const uint8_t *ReferenceF;
570            const uint8_t *ReferenceB;
571            VECTOR mvs, b_mvs;
572    
573          int32_t iSAD;          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
   
 /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */  
574    
575          if (iDirection) {          for (k = 0; k < 4; k++) {
576                  CHECK_MV16_CANDIDATE(start_x - iDiamondSize, start_y);                  mvs.x = data->directmvF[k].x + x;
577                  CHECK_MV16_CANDIDATE(start_x + iDiamondSize, start_y);                  b_mvs.x = ((x == 0) ?
578                  CHECK_MV16_CANDIDATE(start_x, start_y - iDiamondSize);                          data->directmvB[k].x
579                  CHECK_MV16_CANDIDATE(start_x, start_y + iDiamondSize);                          : mvs.x - data->referencemv[k].x);
580    
581                    mvs.y = data->directmvF[k].y + y;
582                    b_mvs.y = ((y == 0) ?
583                            data->directmvB[k].y
584                            : mvs.y - data->referencemv[k].y);
585    
586                    if ((mvs.x > data->max_dx)   || (mvs.x < data->min_dx)   ||
587                            (mvs.y > data->max_dy)   || (mvs.y < data->min_dy)   ||
588                            (b_mvs.x > data->max_dx) || (b_mvs.x < data->min_dx) ||
589                            (b_mvs.y > data->max_dy) || (b_mvs.y < data->min_dy) )
590                            return;
591    
592                    if (data->qpel) {
593                            xcf += mvs.x/2; ycf += mvs.y/2;
594                            xcb += b_mvs.x/2; ycb += b_mvs.y/2;
595          } else {          } else {
596                  int bDirection = 1 + 2 + 4 + 8;                          xcf += mvs.x; ycf += mvs.y;
597                            xcb += b_mvs.x; ycb += b_mvs.y;
598                  do {                          mvs.x *= 2; mvs.y *= 2; /* we move to qpel precision anyway */
599                          iDirection = 0;                          b_mvs.x *= 2; b_mvs.y *= 2;
600                          if (bDirection & 1)     //we only want to check left if we came from the right (our last motion was to the left, up-left or down-left)                  }
                                 CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
601    
602                          if (bDirection & 2)                  ReferenceF = Interpolate8x8qpel(mvs.x, mvs.y, k, 0, data);
603                                  CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);                  ReferenceB = Interpolate8x8qpel(b_mvs.x, b_mvs.y, k, 1, data);
604    
605                          if (bDirection & 4)                  sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
606                                  CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);                                                  ReferenceF, ReferenceB, data->iEdgedWidth);
607                    if (sad > *(data->iMinSAD)) return;
608            }
609    
610                          if (bDirection & 8)          sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;
                                 CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
611    
612                          /* now we're doing diagonal checks near our candidate */          if (data->chroma && sad < *data->iMinSAD)
613                    sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],
614                                                            (ycf >> 3) + roundtab_76[ycf & 0xf],
615                                                            (xcb >> 3) + roundtab_76[xcb & 0xf],
616                                                            (ycb >> 3) + roundtab_76[ycb & 0xf], data);
617    
618                          if (iDirection)         //checking if anything found          if (sad < *(data->iMinSAD)) {
619                          {                  *(data->iMinSAD) = sad;
620                                  bDirection = iDirection;                  data->currentMV->x = x; data->currentMV->y = y;
621                                  iDirection = 0;                  *dir = Direction;
                                 start_x = currMV->x;  
                                 start_y = currMV->y;  
                                 if (bDirection & 3)     //our candidate is left or right  
                                 {  
                                         CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
                                         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);  
622                                  }                                  }
   
                                 if (iDirection) {  
                                         bDirection += iDirection;  
                                         start_x = currMV->x;  
                                         start_y = currMV->y;  
623                                  }                                  }
624                          } else                          //about to quit, eh? not so fast....  
625    static void
626    CheckCandidateDirectno4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
627                          {                          {
628                                  switch (bDirection) {          int32_t sad, xcf, ycf, xcb, ycb;
629                                  case 2:          const uint8_t *ReferenceF;
630                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,          const uint8_t *ReferenceB;
631                                                                                           start_y - iDiamondSize, 2 + 4);          VECTOR mvs, b_mvs;
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1:  
632    
633                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
634                                                                                           start_y - iDiamondSize, 1 + 4);  
635                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,          mvs.x = data->directmvF[0].x + x;
636                                                                                           start_y + iDiamondSize, 1 + 8);          b_mvs.x = ((x == 0) ?
637                                          break;                  data->directmvB[0].x
638                                  case 2 + 4:                  : mvs.x - data->referencemv[0].x);
639                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
640                                                                                           start_y - iDiamondSize, 1 + 4);          mvs.y = data->directmvF[0].y + y;
641                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,          b_mvs.y = ((y == 0) ?
642                                                                                           start_y - iDiamondSize, 2 + 4);                  data->directmvB[0].y
643                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                  : mvs.y - data->referencemv[0].y);
644                                                                                           start_y + iDiamondSize, 2 + 8);  
645                                          break;          if ( (mvs.x > data->max_dx) || (mvs.x < data->min_dx)
646                                  case 4:                  || (mvs.y > data->max_dy) || (mvs.y < data->min_dy)
647                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                  || (b_mvs.x > data->max_dx) || (b_mvs.x < data->min_dx)
648                                                                                           start_y - iDiamondSize, 2 + 4);                  || (b_mvs.y > data->max_dy) || (b_mvs.y < data->min_dy) ) return;
649                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
650                                                                                           start_y - iDiamondSize, 1 + 4);          if (data->qpel) {
651                                          break;                  xcf = 4*(mvs.x/2); ycf = 4*(mvs.y/2);
652                                  case 8:                  xcb = 4*(b_mvs.x/2); ycb = 4*(b_mvs.y/2);
653                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                  ReferenceF = Interpolate16x16qpel(mvs.x, mvs.y, 0, data);
654                                                                                           start_y + iDiamondSize, 2 + 8);                  ReferenceB = Interpolate16x16qpel(b_mvs.x, b_mvs.y, 1, data);
655                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,          } else {
656                                                                                           start_y + iDiamondSize, 1 + 8);                  xcf = 4*mvs.x; ycf = 4*mvs.y;
657                                          break;                  xcb = 4*b_mvs.x; ycb = 4*b_mvs.y;
658                                  case 1 + 4:                  ReferenceF = GetReference(mvs.x, mvs.y, data);
659                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                  ReferenceB = GetReferenceB(b_mvs.x, b_mvs.y, 1, data);
                                                                                          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;  
                                 }  
                                 if (!iDirection)  
                                         break;          //ok, the end. really  
                                 else {  
                                         bDirection = iDirection;  
                                         start_x = currMV->x;  
                                         start_y = currMV->y;  
                                 }  
                         }  
660                  }                  }
661                  while (1);                              //forever  
662            sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
663            sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;
664    
665            if (data->chroma && sad < *data->iMinSAD)
666                    sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],
667                                                            (ycf >> 3) + roundtab_76[ycf & 0xf],
668                                                            (xcb >> 3) + roundtab_76[xcb & 0xf],
669                                                            (ycb >> 3) + roundtab_76[ycb & 0xf], data);
670    
671            if (sad < *(data->iMinSAD)) {
672                    *(data->iMinSAD) = sad;
673                    data->currentMV->x = x; data->currentMV->y = y;
674                    *dir = Direction;
675          }          }
         return iMinSAD;  
676  }  }
677    
 #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,  
678    
679                                           const int x,  static void
680                                           const int y,  CheckCandidateBits16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
681    {
682    
683                                     const int f_start_x,          int16_t *in = data->dctSpace, *coeff = data->dctSpace + 64;
684                                     const int f_start_y,          int32_t bits = 0;
685                                     const int b_start_x,          VECTOR * current;
686                                     const int b_start_y,          const uint8_t * ptr;
687            int i, cbp = 0, t, xc, yc;
                                    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,  
688    
689                                          const int x,          if ( (x > data->max_dx) || (x < data->min_dx)
690                                          const int y,                  || (y > data->max_dy) || (y < data->min_dy) ) return;
691    
692            if (!data->qpel_precision) {
693                    ptr = GetReference(x, y, data);
694                    current = data->currentMV;
695                    xc = x; yc = y;
696            } else { /* x and y are in 1/4 precision */
697                    ptr = Interpolate16x16qpel(x, y, 0, data);
698                    current = data->currentQMV;
699                    xc = x/2; yc = y/2;
700            }
701    
702                                          const int TRB,          for(i = 0; i < 4; i++) {
703                                          const int TRD,                  int s = 8*((i&1) + (i>>1)*data->iEdgedWidth);
704                    transfer_8to16subro(in, data->Cur + s, ptr + s, data->iEdgedWidth);
705                    bits += data->temp[i] = Block_CalcBits(coeff, in, data->dctSpace + 128, data->iQuant, data->quant_type, &cbp, i);
706            }
707    
708                                      const int start_x,          bits += t = BITS_MULT*d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
                                     const int start_y,  
709    
710                                      int iMinSAD,          if (data->temp[0] + t < data->iMinSAD[1]) {
711                                      VECTOR * const currMV,                  data->iMinSAD[1] = data->temp[0] + t; current[1].x = x; current[1].y = y; data->cbp[1] = (data->cbp[1]&~32) | cbp&32; }
712                                          const VECTOR * const directmv,          if (data->temp[1] < data->iMinSAD[2]) {
713                    data->iMinSAD[2] = data->temp[1]; current[2].x = x; current[2].y = y; data->cbp[1] = (data->cbp[1]&~16) | cbp&16; }
714            if (data->temp[2] < data->iMinSAD[3]) {
715                    data->iMinSAD[3] = data->temp[2]; current[3].x = x; current[3].y = y; data->cbp[1] = (data->cbp[1]&~8) | cbp&8; }
716            if (data->temp[3] < data->iMinSAD[4]) {
717                    data->iMinSAD[4] = data->temp[3]; current[4].x = x; current[4].y = y; data->cbp[1] = (data->cbp[1]&~4) | cbp&4; }
718    
719                                      const int32_t min_dx,          bits += BITS_MULT*xvid_cbpy_tab[15-(cbp>>2)].len;
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
720    
721                                          const int32_t iEdgedWidth,          if (bits >= data->iMinSAD[0]) return;
                                         const int32_t iDiamondSize,  
722    
723                                          const int32_t iQuant,          /* chroma */
724                                          int iFound)          xc = (xc >> 1) + roundtab_79[xc & 0x3];
725  {          yc = (yc >> 1) + roundtab_79[yc & 0x3];
 /* Do a diamond search around given starting point, return SAD of best */  
726    
727          int32_t iSAD;          /* chroma U */
728            ptr = interpolate8x8_switch2(data->RefQ, data->RefP[4], 0, 0, xc, yc, data->iEdgedWidth/2, data->rounding);
729            transfer_8to16subro(in, data->CurU, ptr, data->iEdgedWidth/2);
730            bits += Block_CalcBits(coeff, in, data->dctSpace + 128, data->iQuant, data->quant_type, &cbp, 4);
731            if (bits >= data->iMinSAD[0]) return;
732    
733          VECTOR backupMV;          /* chroma V */
734            ptr = interpolate8x8_switch2(data->RefQ, data->RefP[5], 0, 0, xc, yc, data->iEdgedWidth/2, data->rounding);
735            transfer_8to16subro(in, data->CurV, ptr, data->iEdgedWidth/2);
736            bits += Block_CalcBits(coeff, in, data->dctSpace + 128, data->iQuant, data->quant_type, &cbp, 5);
737    
738          currMV->x = start_x;          bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTER & 7) | ((cbp & 3) << 3)].len;
         currMV->y = start_y;  
739    
740  /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */          if (bits < data->iMinSAD[0]) {
741                    data->iMinSAD[0] = bits;
742                    current[0].x = x; current[0].y = y;
743                    *dir = Direction;
744                    *data->cbp = cbp;
745            }
746    }
747    
748          do  static void
749    CheckCandidateBits8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
750          {          {
                 iFound = 1;  
751    
752                  backupMV = *currMV;          int16_t *in = data->dctSpace, *coeff = data->dctSpace + 64;
753            int32_t bits;
754            VECTOR * current;
755            const uint8_t * ptr;
756            int cbp = 0;
757    
758                  CHECK_MV16_DIRECT_FOUND(backupMV.x - iDiamondSize, backupMV.y);          if ( (x > data->max_dx) || (x < data->min_dx)
759                  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);  
760    
761          } while (!iFound);          if (!data->qpel_precision) {
762                    ptr = GetReference(x, y, data);
763                    current = data->currentMV;
764            } else { /* x and y are in 1/4 precision */
765                    ptr = Interpolate8x8qpel(x, y, 0, 0, data);
766                    current = data->currentQMV;
767            }
768    
769            transfer_8to16subro(in, data->Cur, ptr, data->iEdgedWidth);
770            bits = Block_CalcBits(coeff, in, data->dctSpace + 128, data->iQuant, data->quant_type, &cbp, 5);
771            bits += BITS_MULT*d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
772    
773          return iMinSAD;          if (bits < data->iMinSAD[0]) {
774                    *data->cbp = cbp;
775                    data->iMinSAD[0] = bits;
776                    current[0].x = x; current[0].y = y;
777                    *dir = Direction;
778            }
779  }  }
780    
781    /* CHECK_CANDIATE FUNCTIONS END */
782    
783  int32_t  /* MAINSEARCH FUNCTIONS START */
 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)  
 {  
784    
785          int32_t iSAD;  static void
786    AdvDiamondSearch(int x, int y, const SearchData * const data, int bDirection)
787    {
788    
789  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
790    
791          if (iDirection) {          int iDirection;
                 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;  
792    
793                  do {          for(;;) { /* forever */
794                          iDirection = 0;                          iDirection = 0;
795                          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)                  if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
796                                  CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);                  if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
797                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
798                          if (bDirection & 2)                  if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
                                 CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
   
                         if (bDirection & 4)  
                                 CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);  
   
                         if (bDirection & 8)  
                                 CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
799    
800                          /* now we're doing diagonal checks near our candidate */                          /* now we're doing diagonal checks near our candidate */
801    
802                          if (iDirection)         //checking if anything found                  if (iDirection) {               /* if anything found */
                         {  
803                                  bDirection = iDirection;                                  bDirection = iDirection;
804                                  iDirection = 0;                                  iDirection = 0;
805                                  start_x = currMV->x;                          x = data->currentMV->x; y = data->currentMV->y;
806                                  start_y = currMV->y;                          if (bDirection & 3) {   /* our candidate is left or right */
807                                  if (bDirection & 3)     //our candidate is left or right                                  CHECK_CANDIDATE(x, y + iDiamondSize, 8);
808                                  {                                  CHECK_CANDIDATE(x, y - iDiamondSize, 4);
809                                          CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);                          } else {                        /* what remains here is up or down */
810                                          CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y, 2);
811                                  } else                  // what remains here is up or down                                  CHECK_CANDIDATE(x - iDiamondSize, y, 1);
                                 {  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
812                                  }                                  }
813    
814                                  if (iDirection) {                                  if (iDirection) {
815                                          bDirection += iDirection;                                          bDirection += iDirection;
816                                          start_x = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
                                         start_y = currMV->y;  
817                                  }                                  }
818                          } else                          //about to quit, eh? not so fast....                  } else {                                /* about to quit, eh? not so fast.... */
                         {  
819                                  switch (bDirection) {                                  switch (bDirection) {
820                                  case 2:                                  case 2:
821                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
822                                                                                          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);  
823                                          break;                                          break;
824                                  case 1:                                  case 1:
825                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
826                                                                                          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);  
827                                          break;                                          break;
828                                  case 2 + 4:                                  case 2 + 4:
829                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
830                                                                                          start_y - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
831                                          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);  
832                                          break;                                          break;
833                                  case 4:                                  case 4:
834                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
835                                                                                          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);  
836                                          break;                                          break;
837                                  case 8:                                  case 8:
838                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
839                                                                                          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);  
840                                          break;                                          break;
841                                  case 1 + 4:                                  case 1 + 4:
842                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
843                                                                                          start_y + iDiamondSize, 1 + 8);                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
844                                          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);  
845                                          break;                                          break;
846                                  case 2 + 8:                                  case 2 + 8:
847                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
848                                                                                          start_y - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
849                                          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);  
850                                          break;                                          break;
851                                  case 1 + 8:                                  case 1 + 8:
852                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
853                                                                                          start_y - iDiamondSize, 2 + 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
854                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
855                                                                                          start_y + iDiamondSize, 2 + 8);                                  break;
856                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                          default:                /* 1+2+4+8 == we didn't find anything at all */
857                                                                                          start_y + iDiamondSize, 1 + 8);                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
858                                          break;                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
859                                  default:                //1+2+4+8 == we didn't find anything at all                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
860                                          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);  
861                                          break;                                          break;
862                                  }                                  }
863                                  if (!(iDirection))                          if (!iDirection) break;         /* ok, the end. really */
                                         break;          //ok, the end. really  
                                 else {  
864                                          bDirection = iDirection;                                          bDirection = iDirection;
865                                          start_x = currMV->x;                          x = data->currentMV->x; y = data->currentMV->y;
                                         start_y = currMV->y;  
866                                  }                                  }
867                          }                          }
868                  }                  }
                 while (1);                              //forever  
         }  
         return iMinSAD;  
 }  
869    
870    static void
871    SquareSearch(int x, int y, const SearchData * const data, int bDirection)
872    {
873            int iDirection;
874    
875  int32_t          do {
876  Full8_MainSearch(const uint8_t * const pRef,                  iDirection = 0;
877                                   const uint8_t * const pRefH,                  if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);
878                                   const uint8_t * const pRefV,                  if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);
879                                   const uint8_t * const pRefHV,                  if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);
880                                   const uint8_t * const cur,                  if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128);
881                                   const int x,                  if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64);
882                                   const int y,                  if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128);
883                             const int start_x,                  if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128);
884                             const int start_y,                  if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128);
                            int iMinSAD,  
                            VECTOR * const currMV,  
                            const int center_x,  
                            const int center_y,  
                                  const int32_t min_dx,  
                                  const int32_t max_dx,  
                                  const int32_t min_dy,  
                                  const int32_t max_dy,  
                                  const int32_t iEdgedWidth,  
                                  const int32_t iDiamondSize,  
                                  const int32_t iFcode,  
                                  const int32_t iQuant,  
                                  int iFound)  
 {  
         int32_t iSAD;  
         int32_t dx, dy;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV8_CANDIDATE(dx, dy);  
885    
886          return iMinSAD;                  bDirection = iDirection;
887                    x = data->currentMV->x; y = data->currentMV->y;
888            } while (iDirection);
889  }  }
890    
891  Halfpel8_RefineFuncPtr Halfpel8_Refine;  static void
892    DiamondSearch(int x, int y, const SearchData * const data, int bDirection)
 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)  
893  {  {
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
   
         int32_t iSAD;  
         VECTOR backupMV = *currMV;  
894    
895          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y - 1);  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
         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);  
896    
897          return iMinSAD;          int iDirection;
 }  
898    
899  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)          do {
900                    iDirection = 0;
901                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
902                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
903                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
904                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
905    
906                    /* now we're doing diagonal checks near our candidate */
907    
908                    if (iDirection) {               /* checking if anything found */
909                            bDirection = iDirection;
910                            iDirection = 0;
911                            x = data->currentMV->x; y = data->currentMV->y;
912                            if (bDirection & 3) {   /* our candidate is left or right */
913                                    CHECK_CANDIDATE(x, y + iDiamondSize, 8);
914                                    CHECK_CANDIDATE(x, y - iDiamondSize, 4);
915                            } else {                        /* what remains here is up or down */
916                                    CHECK_CANDIDATE(x + iDiamondSize, y, 2);
917                                    CHECK_CANDIDATE(x - iDiamondSize, y, 1);
918                            }
919                            bDirection += iDirection;
920                            x = data->currentMV->x; y = data->currentMV->y;
921                    }
922            }
923            while (iDirection);
924    }
925    
926  int32_t  /* MAINSEARCH FUNCTIONS END */
 PMVfastSearch16(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 int start_x,      /* start is searched first, so it should contain the most */  
                                 const int start_y,  /* likely motion vector for this block */  
                                 const int center_x,     /* center is from where length of MVs is measured */  
                                 const int center_y,  
                                 const uint32_t MotionFlags,  
                                 const uint32_t iQuant,  
                                 const uint32_t iFcode,  
                                 const MBParam * const pParam,  
                                 const MACROBLOCK * const pMBs,  
                                 const MACROBLOCK * const prevMBs,  
                                 VECTOR * const currMV,  
                                 VECTOR * const currPMV)  
 {  
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
927    
928          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;  static void
929    SubpelRefine(const SearchData * const data)
930    {
931    /* Do a half-pel or q-pel refinement */
932            const VECTOR centerMV = data->qpel_precision ? *data->currentQMV : *data->currentMV;
933            int iDirection; /* only needed because macro expects it */
934    
935          int32_t iDiamondSize;          CHECK_CANDIDATE(centerMV.x, centerMV.y - 1, 0);
936            CHECK_CANDIDATE(centerMV.x + 1, centerMV.y - 1, 0);
937            CHECK_CANDIDATE(centerMV.x + 1, centerMV.y, 0);
938            CHECK_CANDIDATE(centerMV.x + 1, centerMV.y + 1, 0);
939            CHECK_CANDIDATE(centerMV.x, centerMV.y + 1, 0);
940            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y + 1, 0);
941            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y, 0);
942            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y - 1, 0);
943    }
944    
945          int32_t min_dx;  static __inline int
946          int32_t max_dx;  SkipDecisionP(const IMAGE * current, const IMAGE * reference,
947          int32_t min_dy;                                                          const int x, const int y,
948          int32_t max_dy;                                                          const uint32_t stride, const uint32_t iQuant, int rrv)
949    
950          int32_t iFound;  {
951            int offset = (x + y*stride)*8;
952            if(!rrv) {
953                    uint32_t sadC = sad8(current->u + offset,
954                                                    reference->u + offset, stride);
955                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
956                    sadC += sad8(current->v + offset,
957                                                    reference->v + offset, stride);
958                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
959                    return 1;
960    
961          VECTOR newMV;          } else {
962          VECTOR backupMV;                        /* just for PMVFAST */                  uint32_t sadC = sad16(current->u + 2*offset,
963                                                    reference->u + 2*offset, stride, 256*4096);
964                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
965                    sadC += sad16(current->v + 2*offset,
966                                                    reference->v + 2*offset, stride, 256*4096);
967                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
968                    return 1;
969            }
970    }
971    
972          VECTOR pmv[4];  static __inline void
973          int32_t psad[4];  SkipMacroblockP(MACROBLOCK *pMB, const int32_t sad)
974    {
975            pMB->mode = MODE_NOT_CODED;
976            pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = zeroMV;
977            pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] = pMB->qmvs[3] = zeroMV;
978            pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
979    }
980    
981          MainSearch16FuncPtr MainSearchPtr;  static __inline void
982    ZeroMacroblockP(MACROBLOCK *pMB, const int32_t sad)
983    {
984            pMB->mode = MODE_INTER;
985            pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = zeroMV;
986            pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] = pMB->qmvs[3] = zeroMV;
987            pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
988    }
989    
990          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;  static __inline void
991    ModeDecision(SearchData * const Data,
992                            MACROBLOCK * const pMB,
993                            const MACROBLOCK * const pMBs,
994                            const int x, const int y,
995                            const MBParam * const pParam,
996                            const uint32_t MotionFlags,
997                            const uint32_t VopFlags,
998                            const uint32_t VolFlags,
999                            const IMAGE * const pCurrent,
1000                            const IMAGE * const pRef,
1001                            const IMAGE * const vGMC,
1002                            const int coding_type)
1003    {
1004            int mode = MODE_INTER;
1005            int mcsel = 0;
1006            int inter4v = (VopFlags & XVID_VOP_INTER4V) && (pMB->dquant == 0);
1007            const uint32_t iQuant = pMB->quant;
1008    
1009            const int skip_possible = (coding_type == P_VOP) && (pMB->dquant == 0);
1010    
1011            pMB->mcsel = 0;
1012    
1013            if (!(VopFlags & XVID_VOP_MODEDECISION_RD)) { /* normal, fast, SAD-based mode decision */
1014                    int sad;
1015                    int InterBias = MV16_INTER_BIAS;
1016                    if (inter4v == 0 || Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
1017                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant) {
1018                            mode = MODE_INTER;
1019                            sad = Data->iMinSAD[0];
1020                    } else {
1021                            mode = MODE_INTER4V;
1022                            sad = Data->iMinSAD[1] + Data->iMinSAD[2] +
1023                                                    Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant;
1024                            Data->iMinSAD[0] = sad;
1025                    }
1026    
1027          int32_t threshA, threshB;                  /* final skip decision, a.k.a. "the vector you found, really that good?" */
1028          int32_t bPredEq;                  if (skip_possible && (pMB->sad16 < (int)iQuant * MAX_SAD00_FOR_SKIP))
1029          int32_t iMinSAD, iSAD;                          if ( (100*sad)/(pMB->sad16+1) > FINAL_SKIP_THRESH)
1030                                    if (Data->chroma || SkipDecisionP(pCurrent, pRef, x, y, Data->iEdgedWidth/2, iQuant, Data->rrv)) {
1031                                            mode = MODE_NOT_CODED;
1032                                            sad = 0;
1033                                    }
1034    
1035  /* Get maximum range */                  /* mcsel */
1036          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,                  if (coding_type == S_VOP) {
                           iFcode);  
1037    
1038  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */                          int32_t iSAD = sad16(Data->Cur,
1039                                    vGMC->y + 16*y*Data->iEdgedWidth + 16*x, Data->iEdgedWidth, 65536);
1040    
1041          if (!(MotionFlags & PMV_HALFPEL16)) {                          if (Data->chroma) {
1042                  min_dx = EVEN(min_dx);                                  iSAD += sad8(Data->CurU, vGMC->u + 8*y*(Data->iEdgedWidth/2) + 8*x, Data->iEdgedWidth/2);
1043                  max_dx = EVEN(max_dx);                                  iSAD += sad8(Data->CurV, vGMC->v + 8*y*(Data->iEdgedWidth/2) + 8*x, Data->iEdgedWidth/2);
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
1044          }          }
1045    
1046          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */                          if (iSAD <= sad) {              /* mode decision GMC */
1047          //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);                                  mode = MODE_INTER;
1048          bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);                                  mcsel = 1;
1049                                    sad = iSAD;
1050                            }
1051    
         if ((x == 0) && (y == 0)) {  
                 threshA = 512;  
                 threshB = 1024;  
         } else {  
                 threshA = psad[0];  
                 threshB = threshA + 256;  
                 if (threshA < 512)  
                         threshA = 512;  
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
1052          }          }
1053    
1054          iFound = 0;                  /* intra decision */
   
 /* 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.  
 */  
1055    
1056          currMV->x = start_x;                  if (iQuant > 8) InterBias += 100 * (iQuant - 8); /* to make high quants work */
1057          currMV->y = start_y;                  if (y != 0)
1058                            if ((pMB - pParam->mb_width)->mode == MODE_INTRA ) InterBias -= 80;
1059                    if (x != 0)
1060                            if ((pMB - 1)->mode == MODE_INTRA ) InterBias -= 80;
1061    
1062          if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */                  if (Data->chroma) InterBias += 50; /* dev8(chroma) ??? <-- yes, we need dev8 (no big difference though) */
1063                  currMV->x = EVEN(currMV->x);                  if (Data->rrv) InterBias *= 4;
                 currMV->y = EVEN(currMV->y);  
         }  
1064    
1065          if (currMV->x > max_dx) {                  if (InterBias < sad) {
1066                  currMV->x = max_dx;                          int32_t deviation;
1067                            if (!Data->rrv)
1068                                    deviation = dev16(Data->Cur, Data->iEdgedWidth);
1069                            else
1070                                    deviation = dev16(Data->Cur, Data->iEdgedWidth) + /* dev32() */
1071                                                            dev16(Data->Cur+16, Data->iEdgedWidth) +
1072                                                            dev16(Data->Cur + 16*Data->iEdgedWidth, Data->iEdgedWidth) +
1073                                                            dev16(Data->Cur+16+16*Data->iEdgedWidth, Data->iEdgedWidth);
1074    
1075                            if (deviation < (sad - InterBias)) mode = MODE_INTRA;
1076          }          }
1077          if (currMV->x < min_dx) {  
1078                  currMV->x = min_dx;                  pMB->cbp = 63;
1079                    pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
1080    
1081            } else { /* BITS */
1082    
1083                    int bits, intra, i, cbp, c[2] = {0, 0};
1084                    VECTOR backup[5], *v;
1085                    Data->iQuant = iQuant;
1086                    Data->cbp = c;
1087    
1088                    v = Data->qpel ? Data->currentQMV : Data->currentMV;
1089                    for (i = 0; i < 5; i++) {
1090                            Data->iMinSAD[i] = 256*4096;
1091                            backup[i] = v[i];
1092          }          }
1093          if (currMV->y > max_dy) {  
1094                  currMV->y = max_dy;                  bits = CountMBBitsInter(Data, pMBs, x, y, pParam, MotionFlags);
1095                    cbp = *Data->cbp;
1096    
1097                    if (coding_type == S_VOP) {
1098                            int bits_gmc;
1099                            *Data->iMinSAD = bits += BITS_MULT*1; /* mcsel */
1100                            bits_gmc = CountMBBitsGMC(Data, vGMC, x, y);
1101                            if (bits_gmc < bits) {
1102                                    mcsel = 1;
1103                                    *Data->iMinSAD = bits = bits_gmc;
1104                                    mode = MODE_INTER;
1105                                    cbp = *Data->cbp;
1106          }          }
         if (currMV->y < min_dy) {  
                 currMV->y = min_dy;  
1107          }          }
1108    
1109          iMinSAD =                  if (inter4v) {
1110                  sad16(cur,                          int bits_4v;
1111                            get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,                          bits_4v = CountMBBitsInter4v(Data, pMB, pMBs, x, y, pParam, MotionFlags, backup);
1112                                                   iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);                          if (bits_4v < bits) {
1113          iMinSAD +=                                  Data->iMinSAD[0] = bits = bits_4v;
1114                  calc_delta_16(currMV->x - center_x, currMV->y - center_y,                                  mode = MODE_INTER4V;
1115                                            (uint8_t) iFcode, iQuant);                                  cbp = *Data->cbp;
   
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
                 {  
                         if (!MVzero(*currMV)) {  
                                 iMinSAD += MV16_00_BIAS;  
                                 CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures  
                                 iMinSAD -= MV16_00_BIAS;  
1116                          }                          }
1117                  }                  }
1118    
1119                  if (MotionFlags & PMV_QUICKSTOP16)                  intra = CountMBBitsIntra(Data);
1120                          goto PMVfast16_Terminate_without_Refine;                  if (intra < bits) {
1121                  if (MotionFlags & PMV_EARLYSTOP16)                          *Data->iMinSAD = bits = intra;
1122                          goto PMVfast16_Terminate_with_Refine;                          mode = MODE_INTRA;
1123          }          }
1124    
1125                    pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = 0;
1126                    pMB->cbp = cbp;
1127            }
1128    
1129  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion          if (Data->rrv) {
1130     vector of the median.                          Data->currentMV[0].x = RRV_MV_SCALEDOWN(Data->currentMV[0].x);
1131     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2                          Data->currentMV[0].y = RRV_MV_SCALEDOWN(Data->currentMV[0].y);
1132  */          }
1133    
1134          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[0])))          if (mode == MODE_INTER && mcsel == 0) {
1135                  iFound = 2;                  pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
1136    
1137  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.                  if(Data->qpel) {
1138     Otherwise select large Diamond Search.                          pMB->qmvs[0] = pMB->qmvs[1]
1139  */                                  = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1140                            pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1141                            pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;
1142                    } else {
1143                            pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1144                            pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
1145                    }
1146    
1147          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))          } else if (mode == MODE_INTER ) { // but mcsel == 1
                 iDiamondSize = 1;               // halfpel!  
         else  
                 iDiamondSize = 2;               // halfpel!  
1148    
1149          if (!(MotionFlags & PMV_HALFPELDIAMOND16))                  pMB->mcsel = 1;
1150                  iDiamondSize *= 2;                  if (Data->qpel) {
1151                            pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] = pMB->qmvs[3] = pMB->amv;
1152                            pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = pMB->amv.x/2;
1153                            pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = pMB->amv.y/2;
1154                    } else
1155                            pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->amv;
1156    
1157            } else
1158                    if (mode == MODE_INTER4V) ; /* anything here? */
1159            else    /* INTRA, NOT_CODED */
1160                    SkipMacroblockP(pMB, 0);
1161    
1162  /*          pMB->mode = mode;
1163     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.  
 */  
1164    
1165  // (0,0) is always possible  bool
1166    MotionEstimation(MBParam * const pParam,
1167                                     FRAMEINFO * const current,
1168                                     FRAMEINFO * const reference,
1169                                     const IMAGE * const pRefH,
1170                                     const IMAGE * const pRefV,
1171                                     const IMAGE * const pRefHV,
1172                                    const IMAGE * const pGMC,
1173                                     const uint32_t iLimit)
1174    {
1175            MACROBLOCK *const pMBs = current->mbs;
1176            const IMAGE *const pCurrent = &current->image;
1177            const IMAGE *const pRef = &reference->image;
1178    
1179          if (!MVzero(pmv[0]))          uint32_t mb_width = pParam->mb_width;
1180                  CHECK_MV16_ZERO;          uint32_t mb_height = pParam->mb_height;
1181            const uint32_t iEdgedWidth = pParam->edged_width;
1182            const uint32_t MotionFlags = MakeGoodMotionFlags(current->motion_flags, current->vop_flags, current->vol_flags);
1183    
1184            uint32_t x, y;
1185            uint32_t iIntra = 0;
1186            int32_t quant = current->quant, sad00;
1187            int skip_thresh = INITIAL_SKIP_THRESH * \
1188                    (current->vop_flags & XVID_VOP_REDUCED ? 4:1) * \
1189                    (current->vop_flags & XVID_VOP_MODEDECISION_RD ? 2:1);
1190    
1191            /* some pre-initialized thingies for SearchP */
1192            int32_t temp[8];
1193            VECTOR currentMV[5];
1194            VECTOR currentQMV[5];
1195            int32_t iMinSAD[5];
1196            DECLARE_ALIGNED_MATRIX(dct_space, 3, 64, int16_t, CACHE_LINE);
1197            SearchData Data;
1198            memset(&Data, 0, sizeof(SearchData));
1199            Data.iEdgedWidth = iEdgedWidth;
1200            Data.currentMV = currentMV;
1201            Data.currentQMV = currentQMV;
1202            Data.iMinSAD = iMinSAD;
1203            Data.temp = temp;
1204            Data.iFcode = current->fcode;
1205            Data.rounding = pParam->m_rounding_type;
1206            Data.qpel = (current->vol_flags & XVID_VOL_QUARTERPEL ? 1:0);
1207            Data.chroma = MotionFlags & XVID_ME_CHROMA_PVOP;
1208            Data.rrv = (current->vop_flags & XVID_VOP_REDUCED) ? 1:0;
1209            Data.dctSpace = dct_space;
1210            Data.quant_type = !(pParam->vol_flags & XVID_VOL_MPEGQUANT);
1211    
1212            if ((current->vop_flags & XVID_VOP_REDUCED)) {
1213                    mb_width = (pParam->width + 31) / 32;
1214                    mb_height = (pParam->height + 31) / 32;
1215                    Data.qpel = 0;
1216            }
1217    
1218            Data.RefQ = pRefV->u; /* a good place, also used in MC (for similar purpose) */
1219            if (sadInit) (*sadInit) ();
1220    
1221            for (y = 0; y < mb_height; y++) {
1222                    for (x = 0; x < mb_width; x++)  {
1223                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1224    
1225                            if (!Data.rrv) pMB->sad16 =
1226                                    sad16v(pCurrent->y + (x + y * iEdgedWidth) * 16,
1227                                                            pRef->y + (x + y * iEdgedWidth) * 16,
1228                                                            pParam->edged_width, pMB->sad8 );
1229    
1230                            else pMB->sad16 =
1231                                    sad32v_c(pCurrent->y + (x + y * iEdgedWidth) * 32,
1232                                                            pRef->y + (x + y * iEdgedWidth) * 32,
1233                                                            pParam->edged_width, pMB->sad8 );
1234    
1235                            if (Data.chroma) {
1236                                    Data.temp[7] = sad8(pCurrent->u + x*8 + y*(iEdgedWidth/2)*8,
1237                                                                            pRef->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2)
1238                                                                    + sad8(pCurrent->v + (x + y*(iEdgedWidth/2))*8,
1239                                                                            pRef->v + (x + y*(iEdgedWidth/2))*8, iEdgedWidth/2);
1240                                    pMB->sad16 += Data.temp[7];
1241                            }
1242    
1243                            sad00 = pMB->sad16;
1244    
1245                            if (pMB->dquant != 0) {
1246                                    quant += DQtab[pMB->dquant];
1247                                    if (quant > 31) quant = 31;
1248                                    else if (quant < 1) quant = 1;
1249                            }
1250                            pMB->quant = quant;
1251    
1252                            /* initial skip decision */
1253                            /* no early skip for GMC (global vector = skip vector is unknown!)  */
1254                            if (current->coding_type != S_VOP)      { /* no fast SKIP for S(GMC)-VOPs */
1255                                    if (pMB->dquant == 0 && sad00 < pMB->quant * skip_thresh)
1256                                            if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, iEdgedWidth/2, pMB->quant, Data.rrv)) {
1257                                                    SkipMacroblockP(pMB, sad00);
1258                                                    continue;
1259                                            }
1260                            }
1261    
1262  // previous frame MV is always possible                          if ((current->vop_flags & XVID_VOP_CARTOON) &&
1263                                    (sad00 < pMB->quant * 4 * skip_thresh)) { /* favorize (0,0) vector for cartoons */
1264                                    ZeroMacroblockP(pMB, sad00);
1265                                    continue;
1266                            }
1267    
1268          if (!MVzero(prevMB->mvs[0]))                          SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1269                  if (!MVequal(prevMB->mvs[0], pmv[0]))                                          y, MotionFlags, current->vop_flags, current->vol_flags,
1270                          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);                                          &Data, pParam, pMBs, reference->mbs, pMB);
1271    
1272  // left neighbour, if allowed                          ModeDecision(&Data, pMB, pMBs, x, y, pParam,
1273                                                     MotionFlags, current->vop_flags, current->vol_flags,
1274                                                     pCurrent, pRef, pGMC, current->coding_type);
1275    
1276          if (!MVzero(pmv[1]))                          if (pMB->mode == MODE_INTRA)
1277                  if (!MVequal(pmv[1], prevMB->mvs[0]))                                  if (++iIntra > iLimit) return 1;
                         if (!MVequal(pmv[1], pmv[0])) {  
                                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                                         pmv[1].x = EVEN(pmv[1].x);  
                                         pmv[1].y = EVEN(pmv[1].y);  
1278                                  }                                  }
   
                                 CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
1279                          }                          }
1280  // top neighbour, if allowed  
1281          if (!MVzero(pmv[2]))  //      if (current->vol_flags & XVID_VOL_GMC ) /* GMC only for S(GMC)-VOPs */
1282                  if (!MVequal(pmv[2], prevMB->mvs[0]))  //      {
1283                          if (!MVequal(pmv[2], pmv[0]))  //              current->warp = GlobalMotionEst( pMBs, pParam, current, reference, pRefH, pRefV, pRefHV);
1284                                  if (!MVequal(pmv[2], pmv[1])) {  //      }
1285                                          if (!(MotionFlags & PMV_HALFPEL16)) {          return 0;
                                                 pmv[2].x = EVEN(pmv[2].x);  
                                                 pmv[2].y = EVEN(pmv[2].y);  
1286                                          }                                          }
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
1287    
1288  // top right neighbour, if allowed  
1289                                          if (!MVzero(pmv[3]))  static __inline int
1290                                                  if (!MVequal(pmv[3], prevMB->mvs[0]))  make_mask(const VECTOR * const pmv, const int i)
1291                                                          if (!MVequal(pmv[3], pmv[0]))  {
1292                                                                  if (!MVequal(pmv[3], pmv[1]))          int mask = 255, j;
1293                                                                          if (!MVequal(pmv[3], pmv[2])) {          for (j = 0; j < i; j++) {
1294                                                                                  if (!(MotionFlags & PMV_HALFPEL16)) {                  if (MVequal(pmv[i], pmv[j])) return 0; /* same vector has been checked already */
1295                                                                                          pmv[3].x = EVEN(pmv[3].x);                  if (pmv[i].x == pmv[j].x) {
1296                                                                                          pmv[3].y = EVEN(pmv[3].y);                          if (pmv[i].y == pmv[j].y + iDiamondSize) mask &= ~4;
1297                            else if (pmv[i].y == pmv[j].y - iDiamondSize) mask &= ~8;
1298                    } else
1299                            if (pmv[i].y == pmv[j].y) {
1300                                    if (pmv[i].x == pmv[j].x + iDiamondSize) mask &= ~1;
1301                                    else if (pmv[i].x == pmv[j].x - iDiamondSize) mask &= ~2;
1302                                                                                  }                                                                                  }
                                                                                 CHECK_MV16_CANDIDATE(pmv[3].x,  
                                                                                                                          pmv[3].y);  
1303                                                                          }                                                                          }
1304            return mask;
1305                                  }                                  }
1306    
1307          if ((MVzero(*currMV)) &&  static __inline void
1308                  (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  PreparePredictionsP(VECTOR * const pmv, int x, int y, int iWcount,
1309                  iMinSAD -= MV16_00_BIAS;                          int iHcount, const MACROBLOCK * const prevMB, int rrv)
1310    {
1311            /* this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself */
1312            if (rrv) { iWcount /= 2; iHcount /= 2; }
1313    
1314            if ( (y != 0) && (x < (iWcount-1)) ) {          /* [5] top-right neighbour */
1315                    pmv[5].x = EVEN(pmv[3].x);
1316                    pmv[5].y = EVEN(pmv[3].y);
1317            } else pmv[5].x = pmv[5].y = 0;
1318    
1319  /* Step 6: If MinSAD <= thresa goto Step 10.          if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }/* pmv[3] is left neighbour */
1320     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.          else pmv[3].x = pmv[3].y = 0;
 */  
1321    
1322          if ((iMinSAD <= threshA) ||          if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }/* [4] top neighbour */
1323                  (MVequal(*currMV, prevMB->mvs[0]) &&          else pmv[4].x = pmv[4].y = 0;
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
         }  
1324    
1325            /* [1] median prediction */
1326            pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
1327    
1328  /************ (Diamond Search)  **************/          pmv[0].x = pmv[0].y = 0; /* [0] is zero; not used in the loop (checked before) but needed here for make_mask */
 /*  
    Step 7: Perform Diamond search, with either the small or large diamond.  
    If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
    Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
    If center then goto step 10.  
    Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
    Refine by using small diamond and goto step 10.  
 */  
1329    
1330          if (MotionFlags & PMV_USESQUARES16)          pmv[2].x = EVEN(prevMB->mvs[0].x); /* [2] is last frame */
1331                  MainSearchPtr = Square16_MainSearch;          pmv[2].y = EVEN(prevMB->mvs[0].y);
1332          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
1333                  MainSearchPtr = AdvDiamond16_MainSearch;          if ((x < iWcount-1) && (y < iHcount-1)) {
1334          else                  pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); /* [6] right-down neighbour in last frame */
1335                  MainSearchPtr = Diamond16_MainSearch;                  pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
1336            } else pmv[6].x = pmv[6].y = 0;
1337    
1338            if (rrv) {
1339                    int i;
1340                    for (i = 0; i < 7; i++) {
1341                            pmv[i].x = RRV_MV_SCALEUP(pmv[i].x);
1342                            pmv[i].y = RRV_MV_SCALEUP(pmv[i].y);
1343                    }
1344            }
1345    }
1346    
1347    static void
1348    SearchP(const IMAGE * const pRef,
1349                    const uint8_t * const pRefH,
1350                    const uint8_t * const pRefV,
1351                    const uint8_t * const pRefHV,
1352                    const IMAGE * const pCur,
1353                    const int x,
1354                    const int y,
1355                    const uint32_t MotionFlags,
1356                    const uint32_t VopFlags,
1357                    const uint32_t VolFlags,
1358                    SearchData * const Data,
1359                    const MBParam * const pParam,
1360                    const MACROBLOCK * const pMBs,
1361                    const MACROBLOCK * const prevMBs,
1362                    MACROBLOCK * const pMB)
1363    {
1364    
1365          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          int i, iDirection = 255, mask, threshA;
1366            VECTOR pmv[7];
1367            int inter4v = (VopFlags & XVID_VOP_INTER4V) && (pMB->dquant == 0);
1368    
1369            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1370                                                    pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
1371    
1372            get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);
1373    
1374            Data->temp[5] = Data->temp[6] = 0; /* chroma-sad cache */
1375            i = Data->rrv ? 2 : 1;
1376            Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16*i;
1377            Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1378            Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1379    
1380            Data->RefP[0] = pRef->y + (x + Data->iEdgedWidth*y) * 16*i;
1381            Data->RefP[2] = pRefH + (x + Data->iEdgedWidth*y) * 16*i;
1382            Data->RefP[1] = pRefV + (x + Data->iEdgedWidth*y) * 16*i;
1383            Data->RefP[3] = pRefHV + (x + Data->iEdgedWidth*y) * 16*i;
1384            Data->RefP[4] = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1385            Data->RefP[5] = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1386    
1387            Data->lambda16 = lambda_vec16[pMB->quant];
1388            Data->lambda8 = lambda_vec8[pMB->quant];
1389            Data->qpel_precision = 0;
1390    
1391            memset(Data->currentMV, 0, 5*sizeof(VECTOR));
1392    
1393            if (Data->qpel) Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1394            else Data->predMV = pmv[0];
1395    
1396            i = d_mv_bits(0, 0, Data->predMV, Data->iFcode, 0, 0);
1397            Data->iMinSAD[0] = pMB->sad16 + ((Data->lambda16 * i * pMB->sad16)>>10);
1398            Data->iMinSAD[1] = pMB->sad8[0] + ((Data->lambda8 * i * (pMB->sad8[0]+NEIGH_8X8_BIAS)) >> 10);
1399            Data->iMinSAD[2] = pMB->sad8[1];
1400            Data->iMinSAD[3] = pMB->sad8[2];
1401            Data->iMinSAD[4] = pMB->sad8[3];
1402    
1403            if ((!(VopFlags & XVID_VOP_MODEDECISION_RD)) && (x | y)) {
1404                    threshA = Data->temp[0]; /* that's where we keep this SAD atm */
1405                    if (threshA < 512) threshA = 512;
1406                    else if (threshA > 1024) threshA = 1024;
1407            } else
1408                    threshA = 512;
1409    
1410            PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
1411                                            prevMBs + x + y * pParam->mb_width, Data->rrv);
1412    
1413  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          if (!Data->rrv) {
1414          iSAD =                  if (inter4v | Data->chroma) CheckCandidate = CheckCandidate16;
1415                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                          else CheckCandidate = CheckCandidate16no4v; /* for extra speed */
1416                                                    currMV->x, currMV->y, iMinSAD, &newMV, center_x, center_y,          } else CheckCandidate = CheckCandidate32;
1417                                                    min_dx, max_dx,  
1418                                                    min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  /* main loop. checking all predictions (but first, which is 0,0 and has been checked in MotionEstimation())*/
1419                                                    iQuant, iFound);  
1420            for (i = 1; i < 7; i++) {
1421                    if (!(mask = make_mask(pmv, i)) ) continue;
1422                    CheckCandidate(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1423                    if (Data->iMinSAD[0] <= threshA) break;
1424            }
1425    
1426            if ((Data->iMinSAD[0] <= threshA) ||
1427                            (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
1428                            (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16)))
1429                    inter4v = 0;
1430            else {
1431    
1432          if (iSAD < iMinSAD) {                  MainSearchFunc * MainSearchPtr;
1433                  *currMV = newMV;                  if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1434                  iMinSAD = iSAD;                  else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1435          }                          else MainSearchPtr = DiamondSearch;
1436    
1437          if (MotionFlags & PMV_EXTSEARCH16) {                  MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
1438    
1439                  if (!(MVequal(pmv[0], backupMV))) {  /* extended search, diamond starting in 0,0 and in prediction.
1440                          iSAD =          note that this search is/might be done in halfpel positions,
1441                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,          which makes it more different than the diamond above */
                                                                   center_x, center_y, iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
1442    
1443                          if (iSAD < iMinSAD) {                  if (MotionFlags & XVID_ME_EXTSEARCH16) {
1444                                  *currMV = newMV;                          int32_t bSAD;
1445                                  iMinSAD = iSAD;                          VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
1446                            if (Data->rrv) {
1447                                    startMV.x = RRV_MV_SCALEUP(startMV.x);
1448                                    startMV.y = RRV_MV_SCALEUP(startMV.y);
1449                          }                          }
1450                            if (!(MVequal(startMV, backupMV))) {
1451                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1452    
1453                                    CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1454                                    MainSearchPtr(startMV.x, startMV.y, Data, 255);
1455                                    if (bSAD < Data->iMinSAD[0]) {
1456                                            Data->currentMV[0] = backupMV;
1457                                            Data->iMinSAD[0] = bSAD; }
1458                  }                  }
1459    
1460                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                          backupMV = Data->currentMV[0];
1461                          iSAD =                          startMV.x = startMV.y = 1;
1462                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                          if (!(MVequal(startMV, backupMV))) {
1463                                                                    iMinSAD, &newMV, center_x, center_y,                                  bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
                                                                   min_dx, max_dx, min_dy, max_dy,  
                                                                   iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
1464    
1465                          if (iSAD < iMinSAD) {                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1466                                  *currMV = newMV;                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1467                                  iMinSAD = iSAD;                                  if (bSAD < Data->iMinSAD[0]) {
1468                                            Data->currentMV[0] = backupMV;
1469                                            Data->iMinSAD[0] = bSAD; }
1470                          }                          }
1471                  }                  }
1472          }          }
1473    
1474  /*          if (MotionFlags & XVID_ME_HALFPELREFINE16)
1475     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.                          SubpelRefine(Data);
 */  
1476    
1477    PMVfast16_Terminate_with_Refine:          for(i = 0; i < 5; i++) {
1478          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; /* initialize qpel vectors */
1479                  iMinSAD =                  Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
                         Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
   
   PMVfast16_Terminate_without_Refine:  
         currPMV->x = currMV->x - center_x;  
         currPMV->y = currMV->y - center_y;  
         return iMinSAD;  
1480  }  }
1481    
1482            if (Data->qpel) {
1483                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1484                                    pParam->width, pParam->height, Data->iFcode, 1, 0);
1485                    Data->qpel_precision = 1;
1486                    if (MotionFlags & XVID_ME_QUARTERPELREFINE16)
1487                            SubpelRefine(Data);
1488            }
1489    
1490            if (Data->iMinSAD[0] < (int32_t)pMB->quant * 30)
1491                    inter4v = 0;
1492    
1493            if (inter4v) {
1494                    SearchData Data8;
1495                    memcpy(&Data8, Data, sizeof(SearchData)); /* quick copy of common data */
1496    
1497                    Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
1498                    Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
1499                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
1500                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
1501    
1502                    if ((Data->chroma) && (!(VopFlags & XVID_VOP_MODEDECISION_RD))) {
1503                            /* chroma is only used for comparsion to INTER. if the comparsion will be done in BITS domain, it will not be used */
1504                            int sumx = 0, sumy = 0;
1505    
1506  int32_t                          if (Data->qpel)
1507  Diamond8_MainSearch(const uint8_t * const pRef,                                  for (i = 1; i < 5; i++) {
1508                                          const uint8_t * const pRefH,                                          sumx += Data->currentQMV[i].x/2;
1509                                          const uint8_t * const pRefV,                                          sumy += Data->currentQMV[i].y/2;
1510                                          const uint8_t * const pRefHV,                                  }
1511                                          const uint8_t * const cur,                          else
1512                                          const int x,                                  for (i = 1; i < 5; i++) {
1513                                          const int y,                                          sumx += Data->currentMV[i].x;
1514                                          int32_t start_x,                                          sumy += Data->currentMV[i].y;
1515                                          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);  
1516    
1517          if (iDirection) {                          Data->iMinSAD[1] += ChromaSAD(  (sumx >> 3) + roundtab_76[sumx & 0xf],
1518                  while (!iFound) {                                                                                          (sumy >> 3) + roundtab_76[sumy & 0xf], Data);
                         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);  
1519                  }                  }
1520          } else {          } else Data->iMinSAD[1] = 4096*256;
                 currMV->x = start_x;  
                 currMV->y = start_y;  
1521          }          }
1522          return iMinSAD;  
1523    static void
1524    Search8(const SearchData * const OldData,
1525                    const int x, const int y,
1526                    const uint32_t MotionFlags,
1527                    const MBParam * const pParam,
1528                    MACROBLOCK * const pMB,
1529                    const MACROBLOCK * const pMBs,
1530                    const int block,
1531                    SearchData * const Data)
1532    {
1533            int i = 0;
1534            Data->iMinSAD = OldData->iMinSAD + 1 + block;
1535            Data->currentMV = OldData->currentMV + 1 + block;
1536            Data->currentQMV = OldData->currentQMV + 1 + block;
1537    
1538            if(Data->qpel) {
1539                    Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1540                    if (block != 0) i = d_mv_bits(  Data->currentQMV->x, Data->currentQMV->y,
1541                                                                                    Data->predMV, Data->iFcode, 0, 0);
1542            } else {
1543                    Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1544                    if (block != 0) i = d_mv_bits(  Data->currentMV->x, Data->currentMV->y,
1545                                                                                    Data->predMV, Data->iFcode, 0, Data->rrv);
1546  }  }
1547    
1548            *(Data->iMinSAD) += (Data->lambda8 * i * (*Data->iMinSAD + NEIGH_8X8_BIAS))>>10;
1549    
1550            if (MotionFlags & (XVID_ME_EXTSEARCH8|XVID_ME_HALFPELREFINE8|XVID_ME_QUARTERPELREFINE8)) {
1551    
1552                    if (Data->rrv) i = 16; else i = 8;
1553    
1554  int32_t                  Data->RefP[0] = OldData->RefP[0] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1555  Square8_MainSearch(const uint8_t * const pRef,                  Data->RefP[1] = OldData->RefP[1] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1556                                          const uint8_t * const pRefH,                  Data->RefP[2] = OldData->RefP[2] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1557                                          const uint8_t * const pRefV,                  Data->RefP[3] = OldData->RefP[3] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x,  
                                         const int y,  
                                         int32_t start_x,  
                                         int32_t start_y,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a 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  
 */  
1558    
1559          CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);                  Data->Cur = OldData->Cur + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1560          CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);                  Data->qpel_precision = 0;
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
   
         CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 5);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 6);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 7);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 8);  
1561    
1562                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1563                                            pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
1564    
1565          if (iDirection) {                  if (!Data->rrv) CheckCandidate = CheckCandidate8;
1566                  while (!iFound) {                  else CheckCandidate = CheckCandidate16no4v;
                         iFound = 1;  
                         backupMV = *currMV;  
1567    
1568                          switch (iDirection) {                  if (MotionFlags & XVID_ME_EXTSEARCH8 && (!(MotionFlags & XVID_ME_EXTSEARCH_RD))) {
1569                          case 1:                          int32_t temp_sad = *(Data->iMinSAD); /* store current MinSAD */
                                 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;  
1570    
1571                          case 3:                          MainSearchFunc *MainSearchPtr;
1572                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                          if (MotionFlags & XVID_ME_USESQUARES8) MainSearchPtr = SquareSearch;
1573                                                                                   4);                                  else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1574                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                                          else MainSearchPtr = DiamondSearch;
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
1575    
1576                          case 4:                          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, 255);
                                 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);  
                                 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);  
1577    
1578                                  break;                          if(*(Data->iMinSAD) < temp_sad) {
1579                                            Data->currentQMV->x = 2 * Data->currentMV->x; /* update our qpel vector */
1580                                            Data->currentQMV->y = 2 * Data->currentMV->y;
1581                            }
1582                    }
1583    
1584                          case 7:                  if (MotionFlags & XVID_ME_HALFPELREFINE8) {
1585                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          int32_t temp_sad = *(Data->iMinSAD); /* store current MinSAD */
                                                                                    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;  
1586    
1587                          case 8:                          SubpelRefine(Data); /* perform halfpel refine of current best vector */
1588                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
1589                                                                                   2);                          if(*(Data->iMinSAD) < temp_sad) { /* we have found a better match */
1590                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                                  Data->currentQMV->x = 2 * Data->currentMV->x; /* update our qpel vector */
1591                                                                                   4);                                  Data->currentQMV->y = 2 * Data->currentMV->y;
1592                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          }
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         default:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
   
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
1593                          }                          }
1594    
1595                    if (Data->qpel && MotionFlags & XVID_ME_QUARTERPELREFINE8) {
1596                                    Data->qpel_precision = 1;
1597                                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1598                                            pParam->width, pParam->height, Data->iFcode, 1, 0);
1599                                    SubpelRefine(Data);
1600                  }                  }
1601            }
1602    
1603            if (Data->rrv) {
1604                            Data->currentMV->x = RRV_MV_SCALEDOWN(Data->currentMV->x);
1605                            Data->currentMV->y = RRV_MV_SCALEDOWN(Data->currentMV->y);
1606            }
1607    
1608            if(Data->qpel) {
1609                    pMB->pmvs[block].x = Data->currentQMV->x - Data->predMV.x;
1610                    pMB->pmvs[block].y = Data->currentQMV->y - Data->predMV.y;
1611                    pMB->qmvs[block] = *Data->currentQMV;
1612          } else {          } else {
1613                  currMV->x = start_x;                  pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1614                  currMV->y = start_y;                  pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
1615          }          }
1616          return iMinSAD;  
1617            pMB->mvs[block] = *Data->currentMV;
1618            pMB->sad8[block] = 4 * *Data->iMinSAD;
1619  }  }
1620    
1621    /* motion estimation for B-frames */
1622    
1623    static __inline VECTOR
1624    ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1625    {
1626    /* the stupidiest function ever */
1627            return (mode == MODE_FORWARD ? pMB->mvs[0] : pMB->b_mvs[0]);
1628    }
1629    
1630    static void __inline
1631    PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
1632                                                            const uint32_t iWcount,
1633                                                            const MACROBLOCK * const pMB,
1634                                                            const uint32_t mode_curr)
1635    {
1636    
1637            /* [0] is prediction */
1638            pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
1639    
1640  int32_t          pmv[1].x = pmv[1].y = 0; /* [1] is zero */
 Halfpel8_Refine_c(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)  
 {  
 /* 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);  
1641    
1642          return iMinSAD;          pmv[2] = ChoosePred(pMB, mode_curr);
1643  }          pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
1644    
1645            if ((y != 0)&&(x != (int)(iWcount+1))) {                        /* [3] top-right neighbour */
1646                    pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
1647                    pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
1648            } else pmv[3].x = pmv[3].y = 0;
1649    
1650  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)          if (y != 0) {
1651                    pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
1652                    pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
1653            } else pmv[4].x = pmv[4].y = 0;
1654    
1655  int32_t          if (x != 0) {
1656  PMVfastSearch8(const uint8_t * const pRef,                  pmv[5] = ChoosePred(pMB-1, mode_curr);
1657                    pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1658            } else pmv[5].x = pmv[5].y = 0;
1659    
1660            if (x != 0 && y != 0) {
1661                    pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
1662                    pmv[6].x = EVEN(pmv[6].x); pmv[6].y = EVEN(pmv[6].y);
1663            } else pmv[6].x = pmv[6].y = 0;
1664    }
1665    
1666    
1667    /* search backward or forward */
1668    static void
1669    SearchBF(       const IMAGE * const pRef,
1670                             const uint8_t * const pRefH,                             const uint8_t * const pRefH,
1671                             const uint8_t * const pRefV,                             const uint8_t * const pRefV,
1672                             const uint8_t * const pRefHV,                             const uint8_t * const pRefHV,
1673                             const IMAGE * const pCur,                             const IMAGE * const pCur,
1674                             const int x,                          const int x, const int y,
                            const int y,  
                            const int start_x,  
                            const int start_y,  
                                 const int center_x,  
                                 const int center_y,  
1675                             const uint32_t MotionFlags,                             const uint32_t MotionFlags,
                            const uint32_t iQuant,  
1676                             const uint32_t iFcode,                             const uint32_t iFcode,
1677                             const MBParam * const pParam,                             const MBParam * const pParam,
1678                             const MACROBLOCK * const pMBs,                          MACROBLOCK * const pMB,
1679                             const MACROBLOCK * const prevMBs,                          const VECTOR * const predMV,
1680                             VECTOR * const currMV,                          int32_t * const best_sad,
1681                             VECTOR * const currPMV)                          const int32_t mode_current,
1682                            SearchData * const Data)
1683  {  {
         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;  
1684    
1685          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;          int i, iDirection = 255, mask;
1686            VECTOR pmv[7];
1687            MainSearchFunc *MainSearchPtr;
1688            *Data->iMinSAD = MV_MAX_ERROR;
1689            Data->iFcode = iFcode;
1690            Data->qpel_precision = 0;
1691            Data->temp[5] = Data->temp[6] = Data->temp[7] = 256*4096; /* reset chroma-sad cache */
1692    
1693            Data->RefP[0] = pRef->y + (x + Data->iEdgedWidth*y) * 16;
1694            Data->RefP[2] = pRefH + (x + Data->iEdgedWidth*y) * 16;
1695            Data->RefP[1] = pRefV + (x + Data->iEdgedWidth*y) * 16;
1696            Data->RefP[3] = pRefHV + (x + Data->iEdgedWidth*y) * 16;
1697            Data->RefP[4] = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8;
1698            Data->RefP[5] = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8;
1699    
1700          int32_t iDiamondSize;          Data->predMV = *predMV;
1701    
1702          int32_t min_dx;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1703          int32_t max_dx;                                  pParam->width, pParam->height, iFcode - Data->qpel, 0, 0);
         int32_t min_dy;  
         int32_t max_dy;  
1704    
1705          VECTOR pmv[4];          pmv[0] = Data->predMV;
1706          int32_t psad[4];          if (Data->qpel) { pmv[0].x /= 2; pmv[0].y /= 2; }
         VECTOR newMV;  
         VECTOR backupMV;  
         VECTOR startMV;  
1707    
1708  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);
         const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;  
1709    
1710           int32_t threshA, threshB;          Data->currentMV->x = Data->currentMV->y = 0;
1711          int32_t iFound, bPredEq;          CheckCandidate = CheckCandidate16no4v;
         int32_t iMinSAD, iSAD;  
1712    
1713          int32_t iSubBlock = (y & 1) + (y & 1) + (x & 1);          /* main loop. checking all predictions */
1714            for (i = 0; i < 7; i++) {
1715                    if (!(mask = make_mask(pmv, i)) ) continue;
1716                    CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1717            }
1718    
1719          MainSearch8FuncPtr MainSearchPtr;          if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1720            else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1721                    else MainSearchPtr = DiamondSearch;
1722    
1723          /* Init variables */          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
         startMV.x = start_x;  
         startMV.y = start_y;  
1724    
1725          /* Get maximum range */          SubpelRefine(Data);
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,  
                           iFcode);  
1726    
1727          if (!(MotionFlags & PMV_HALFPELDIAMOND8)) {          if (Data->qpel && *Data->iMinSAD < *best_sad + 300) {
1728                  min_dx = EVEN(min_dx);                  Data->currentQMV->x = 2*Data->currentMV->x;
1729                  max_dx = EVEN(max_dx);                  Data->currentQMV->y = 2*Data->currentMV->y;
1730                  min_dy = EVEN(min_dy);                  Data->qpel_precision = 1;
1731                  max_dy = EVEN(max_dy);                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1732                                            pParam->width, pParam->height, iFcode, 1, 0);
1733                    SubpelRefine(Data);
1734          }          }
1735    
1736          /* because we might use IF (dx>max_dx) THEN dx=max_dx; */          /* three bits are needed to code backward mode. four for forward */
         //bPredEq = get_pmvdata(pMBs, (x >> 1), (y >> 1), iWcount, iSubBlock, pmv, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, (x >> 1), (y >> 1), iSubBlock, pmv, psad);  
1737    
1738          if ((x == 0) && (y == 0)) {          if (mode_current == MODE_FORWARD) *Data->iMinSAD += 4 * Data->lambda16;
1739                  threshA = 512 / 4;          else *Data->iMinSAD += 3 * Data->lambda16;
                 threshB = 1024 / 4;  
1740    
1741            if (*Data->iMinSAD < *best_sad) {
1742                    *best_sad = *Data->iMinSAD;
1743                    pMB->mode = mode_current;
1744                    if (Data->qpel) {
1745                            pMB->pmvs[0].x = Data->currentQMV->x - predMV->x;
1746                            pMB->pmvs[0].y = Data->currentQMV->y - predMV->y;
1747                            if (mode_current == MODE_FORWARD)
1748                                    pMB->qmvs[0] = *Data->currentQMV;
1749                            else
1750                                    pMB->b_qmvs[0] = *Data->currentQMV;
1751          } else {          } else {
1752                  threshA = psad[0] / 4;  /* good estimate? */                          pMB->pmvs[0].x = Data->currentMV->x - predMV->x;
1753                  threshB = threshA + 256 / 4;                          pMB->pmvs[0].y = Data->currentMV->y - predMV->y;
1754                  if (threshA < 512 / 4)                  }
1755                          threshA = 512 / 4;                  if (mode_current == MODE_FORWARD) pMB->mvs[0] = *Data->currentMV;
1756                  if (threshA > 1024 / 4)                  else pMB->b_mvs[0] = *Data->currentMV;
1757                          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.  
 */  
1758    
1759            if (mode_current == MODE_FORWARD) *(Data->currentMV+2) = *Data->currentMV;
1760            else *(Data->currentMV+1) = *Data->currentMV; /* we store currmv for interpolate search */
1761    }
1762    
1763    static void
1764    SkipDecisionB(const IMAGE * const pCur,
1765                                    const IMAGE * const f_Ref,
1766                                    const IMAGE * const b_Ref,
1767                                    MACROBLOCK * const pMB,
1768                                    const uint32_t x, const uint32_t y,
1769                                    const SearchData * const Data)
1770    {
1771            int dx = 0, dy = 0, b_dx = 0, b_dy = 0;
1772            int32_t sum;
1773            const int div = 1 + Data->qpel;
1774            int k;
1775            const uint32_t stride = Data->iEdgedWidth/2;
1776            /* this is not full chroma compensation, only it's fullpel approximation. should work though */
1777    
1778  // Prepare for main loop          for (k = 0; k < 4; k++) {
1779                    dy += Data->directmvF[k].y / div;
1780                    dx += Data->directmvF[k].x / div;
1781                    b_dy += Data->directmvB[k].y / div;
1782                    b_dx += Data->directmvB[k].x / div;
1783            }
1784    
1785            dy = (dy >> 3) + roundtab_76[dy & 0xf];
1786            dx = (dx >> 3) + roundtab_76[dx & 0xf];
1787            b_dy = (b_dy >> 3) + roundtab_76[b_dy & 0xf];
1788            b_dx = (b_dx >> 3) + roundtab_76[b_dx & 0xf];
1789    
1790            sum = sad8bi(pCur->u + 8 * x + 8 * y * stride,
1791                                            f_Ref->u + (y*8 + dy/2) * stride + x*8 + dx/2,
1792                                            b_Ref->u + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1793                                            stride);
1794    
1795            if (sum >= 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) return; /* no skip */
1796    
1797            sum += sad8bi(pCur->v + 8*x + 8 * y * stride,
1798                                            f_Ref->v + (y*8 + dy/2) * stride + x*8 + dx/2,
1799                                            b_Ref->v + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1800                                            stride);
1801    
1802    if (MotionFlags & PMV_USESQUARES8)          if (sum < 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) {
1803        MainSearchPtr = Square8_MainSearch;                  pMB->mode = MODE_DIRECT_NONE_MV; /* skipped */
1804    else                  for (k = 0; k < 4; k++) {
1805                            pMB->qmvs[k] = pMB->mvs[k];
1806                            pMB->b_qmvs[k] = pMB->b_mvs[k];
1807                    }
1808            }
1809    }
1810    
1811          if (MotionFlags & PMV_ADVANCEDDIAMOND8)  static __inline uint32_t
1812                  MainSearchPtr = AdvDiamond8_MainSearch;  SearchDirect(const IMAGE * const f_Ref,
1813          else                                  const uint8_t * const f_RefH,
1814                  MainSearchPtr = Diamond8_MainSearch;                                  const uint8_t * const f_RefV,
1815                                    const uint8_t * const f_RefHV,
1816                                    const IMAGE * const b_Ref,
1817                                    const uint8_t * const b_RefH,
1818                                    const uint8_t * const b_RefV,
1819                                    const uint8_t * const b_RefHV,
1820                                    const IMAGE * const pCur,
1821                                    const int x, const int y,
1822                                    const uint32_t MotionFlags,
1823                                    const int32_t TRB, const int32_t TRD,
1824                                    const MBParam * const pParam,
1825                                    MACROBLOCK * const pMB,
1826                                    const MACROBLOCK * const b_mb,
1827                                    int32_t * const best_sad,
1828                                    SearchData * const Data)
1829    
1830    {
1831            int32_t skip_sad;
1832            int k = (x + Data->iEdgedWidth*y) * 16;
1833            MainSearchFunc *MainSearchPtr;
1834    
1835            *Data->iMinSAD = 256*4096;
1836            Data->RefP[0] = f_Ref->y + k;
1837            Data->RefP[2] = f_RefH + k;
1838            Data->RefP[1] = f_RefV + k;
1839            Data->RefP[3] = f_RefHV + k;
1840            Data->b_RefP[0] = b_Ref->y + k;
1841            Data->b_RefP[2] = b_RefH + k;
1842            Data->b_RefP[1] = b_RefV + k;
1843            Data->b_RefP[3] = b_RefHV + k;
1844            Data->RefP[4] = f_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1845            Data->RefP[5] = f_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1846            Data->b_RefP[4] = b_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1847            Data->b_RefP[5] = b_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1848    
1849            k = Data->qpel ? 4 : 2;
1850            Data->max_dx = k * (pParam->width - x * 16);
1851            Data->max_dy = k * (pParam->height - y * 16);
1852            Data->min_dx = -k * (16 + x * 16);
1853            Data->min_dy = -k * (16 + y * 16);
1854    
1855            Data->referencemv = Data->qpel ? b_mb->qmvs : b_mb->mvs;
1856            Data->qpel_precision = 0;
1857    
1858          *currMV = startMV;          for (k = 0; k < 4; k++) {
1859                    pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);
1860                    pMB->b_mvs[k].x = Data->directmvB[k].x = ((TRB - TRD) * Data->referencemv[k].x) / TRD;
1861                    pMB->mvs[k].y = Data->directmvF[k].y = ((TRB * Data->referencemv[k].y) / TRD);
1862                    pMB->b_mvs[k].y = Data->directmvB[k].y = ((TRB - TRD) * Data->referencemv[k].y) / TRD;
1863    
1864          iMinSAD =                  if ( (pMB->b_mvs[k].x > Data->max_dx) | (pMB->b_mvs[k].x < Data->min_dx)
1865                  sad8(cur,                          | (pMB->b_mvs[k].y > Data->max_dy) | (pMB->b_mvs[k].y < Data->min_dy) ) {
                          get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  
                                                 iEdgedWidth), iEdgedWidth);  
         iMinSAD +=  
                 calc_delta_8(currMV->x - center_x, currMV->y - center_y,  
                                          (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256 / 4) || ((MVequal(*currMV, prevMB->mvs[iSubBlock]))  
                                                                 && ((int32_t) iMinSAD <  
                                                                         prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  
    vector of the median.  
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
1866    
1867          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[iSubBlock])))                          *best_sad = 256*4096; /* in that case, we won't use direct mode */
1868                  iFound = 2;                          pMB->mode = MODE_DIRECT; /* just to make sure it doesn't say "MODE_DIRECT_NONE_MV" */
1869                            pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;
1870                            return 256*4096;
1871                    }
1872                    if (b_mb->mode != MODE_INTER4V) {
1873                            pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mvs[0];
1874                            pMB->b_mvs[1] = pMB->b_mvs[2] = pMB->b_mvs[3] = pMB->b_mvs[0];
1875                            Data->directmvF[1] = Data->directmvF[2] = Data->directmvF[3] = Data->directmvF[0];
1876                            Data->directmvB[1] = Data->directmvB[2] = Data->directmvB[3] = Data->directmvB[0];
1877                            break;
1878                    }
1879            }
1880    
1881  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          CheckCandidate = b_mb->mode == MODE_INTER4V ? CheckCandidateDirect : CheckCandidateDirectno4v;
    Otherwise select large Diamond Search.  
 */  
1882    
1883          if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))          CheckCandidate(0, 0, 255, &k, Data);
                 iDiamondSize = 1;               // 1 halfpel!  
         else  
                 iDiamondSize = 2;               // 2 halfpel = 1 full pixel!  
1884    
1885          if (!(MotionFlags & PMV_HALFPELDIAMOND8))          /* initial (fast) skip decision */
1886                  iDiamondSize *= 2;          if (*Data->iMinSAD < pMB->quant * INITIAL_SKIP_THRESH * (Data->chroma?3:2)) {
1887                    /* possible skip */
1888                    if (Data->chroma) {
1889                            pMB->mode = MODE_DIRECT_NONE_MV;
1890                            return *Data->iMinSAD; /* skip. */
1891                    } else {
1892                            SkipDecisionB(pCur, f_Ref, b_Ref, pMB, x, y, Data);
1893                            if (pMB->mode == MODE_DIRECT_NONE_MV) return *Data->iMinSAD; /* skip. */
1894                    }
1895            }
1896    
1897            *Data->iMinSAD += Data->lambda16;
1898            skip_sad = *Data->iMinSAD;
1899    
1900  /*  /*
1901     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.           * DIRECT MODE DELTA VECTOR SEARCH.
1902     Also calculate (0,0) but do not subtract offset.           * This has to be made more effective, but at the moment I'm happy it's running at all
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset.  
1903  */  */
1904    
1905  // the median prediction might be even better than mv16          if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1906                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1907                            else MainSearchPtr = DiamondSearch;
1908    
1909          if (!MVequal(pmv[0], startMV))          MainSearchPtr(0, 0, Data, 255);
                 CHECK_MV8_CANDIDATE(center_x, center_y);  
1910    
1911  // (0,0) if needed          SubpelRefine(Data);
         if (!MVzero(pmv[0]))  
                 if (!MVzero(startMV))  
                         CHECK_MV8_ZERO;  
   
 // previous frame MV if needed  
         if (!MVzero(prevMB->mvs[iSubBlock]))  
                 if (!MVequal(prevMB->mvs[iSubBlock], startMV))  
                         if (!MVequal(prevMB->mvs[iSubBlock], pmv[0]))  
                                 CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x,  
                                                                         prevMB->mvs[iSubBlock].y);  
   
         if ((iMinSAD <= threshA) ||  
                 (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&  
                  ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 // left neighbour, if allowed and needed  
         if (!MVzero(pmv[1]))  
                 if (!MVequal(pmv[1], startMV))  
                         if (!MVequal(pmv[1], prevMB->mvs[iSubBlock]))  
                                 if (!MVequal(pmv[1], pmv[0])) {  
                                         if (!(MotionFlags & PMV_HALFPEL8)) {  
                                                 pmv[1].x = EVEN(pmv[1].x);  
                                                 pmv[1].y = EVEN(pmv[1].y);  
                                         }  
                                         CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);  
                                 }  
 // top neighbour, if allowed and needed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], startMV))  
                         if (!MVequal(pmv[2], prevMB->mvs[iSubBlock]))  
                                 if (!MVequal(pmv[2], pmv[0]))  
                                         if (!MVequal(pmv[2], pmv[1])) {  
                                                 if (!(MotionFlags & PMV_HALFPEL8)) {  
                                                         pmv[2].x = EVEN(pmv[2].x);  
                                                         pmv[2].y = EVEN(pmv[2].y);  
                                                 }  
                                                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed and needed  
                                                 if (!MVzero(pmv[3]))  
                                                         if (!MVequal(pmv[3], startMV))  
                                                                 if (!MVequal(pmv[3], prevMB->mvs[iSubBlock]))  
                                                                         if (!MVequal(pmv[3], pmv[0]))  
                                                                                 if (!MVequal(pmv[3], pmv[1]))  
                                                                                         if (!MVequal(pmv[3], pmv[2])) {  
                                                                                                 if (!  
                                                                                                         (MotionFlags &  
                                                                                                          PMV_HALFPEL8)) {  
                                                                                                         pmv[3].x = EVEN(pmv[3].x);  
                                                                                                         pmv[3].y = EVEN(pmv[3].y);  
                                                                                                 }  
                                                                                                 CHECK_MV8_CANDIDATE(pmv[3].x,  
                                                                                                                                         pmv[3].y);  
                                                                                         }  
                                         }  
   
         if ((MVzero(*currMV)) &&  
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV8_00_BIAS;  
1912    
1913            *best_sad = *Data->iMinSAD;
1914    
1915  /* Step 6: If MinSAD <= thresa goto Step 10.          if (Data->qpel || b_mb->mode == MODE_INTER4V) pMB->mode = MODE_DIRECT;
1916     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.          else pMB->mode = MODE_DIRECT_NO4V; /* for faster compensation */
1917  */  
1918            pMB->pmvs[3] = *Data->currentMV;
1919    
1920          if ((iMinSAD <= threshA) ||          for (k = 0; k < 4; k++) {
1921                  (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&                  pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
1922                   ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {                  pMB->b_mvs[k].x = (     (Data->currentMV->x == 0)
1923                  if (MotionFlags & PMV_QUICKSTOP16)                                                          ? Data->directmvB[k].x
1924                          goto PMVfast8_Terminate_without_Refine;                                                          :pMB->mvs[k].x - Data->referencemv[k].x);
1925                  if (MotionFlags & PMV_EARLYSTOP16)                  pMB->mvs[k].y = (Data->directmvF[k].y + Data->currentMV->y);
1926                          goto PMVfast8_Terminate_with_Refine;                  pMB->b_mvs[k].y = ((Data->currentMV->y == 0)
1927                                                            ? Data->directmvB[k].y
1928                                                            : pMB->mvs[k].y - Data->referencemv[k].y);
1929                    if (Data->qpel) {
1930                            pMB->qmvs[k].x = pMB->mvs[k].x; pMB->mvs[k].x /= 2;
1931                            pMB->b_qmvs[k].x = pMB->b_mvs[k].x; pMB->b_mvs[k].x /= 2;
1932                            pMB->qmvs[k].y = pMB->mvs[k].y; pMB->mvs[k].y /= 2;
1933                            pMB->b_qmvs[k].y = pMB->b_mvs[k].y; pMB->b_mvs[k].y /= 2;
1934                    }
1935    
1936                    if (b_mb->mode != MODE_INTER4V) {
1937                            pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1938                            pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1939                            pMB->qmvs[3] = pMB->qmvs[2] = pMB->qmvs[1] = pMB->qmvs[0];
1940                            pMB->b_qmvs[3] = pMB->b_qmvs[2] = pMB->b_qmvs[1] = pMB->b_qmvs[0];
1941                            break;
1942          }          }
1943            }
1944            return skip_sad;
1945    }
1946    
1947    static void
1948    SearchInterpolate(const IMAGE * const f_Ref,
1949                                    const uint8_t * const f_RefH,
1950                                    const uint8_t * const f_RefV,
1951                                    const uint8_t * const f_RefHV,
1952                                    const IMAGE * const b_Ref,
1953                                    const uint8_t * const b_RefH,
1954                                    const uint8_t * const b_RefV,
1955                                    const uint8_t * const b_RefHV,
1956                                    const IMAGE * const pCur,
1957                                    const int x, const int y,
1958                                    const uint32_t fcode,
1959                                    const uint32_t bcode,
1960                                    const uint32_t MotionFlags,
1961                                    const MBParam * const pParam,
1962                                    const VECTOR * const f_predMV,
1963                                    const VECTOR * const b_predMV,
1964                                    MACROBLOCK * const pMB,
1965                                    int32_t * const best_sad,
1966                                    SearchData * const fData)
1967    
1968  /************ (Diamond Search)  **************/  {
 /*  
    Step 7: Perform Diamond search, with either the small or large diamond.  
    If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
    Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
    If center then goto step 10.  
    Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
    Refine by using small diamond and goto step 10.  
 */  
1969    
1970          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          int iDirection, i, j;
1971            SearchData bData;
1972    
1973            fData->qpel_precision = 0;
1974            memcpy(&bData, fData, sizeof(SearchData)); /* quick copy of common data */
1975            *fData->iMinSAD = 4096*256;
1976            bData.currentMV++; bData.currentQMV++;
1977            fData->iFcode = bData.bFcode = fcode; fData->bFcode = bData.iFcode = bcode;
1978    
1979            i = (x + y * fData->iEdgedWidth) * 16;
1980    
1981            bData.b_RefP[0] = fData->RefP[0] = f_Ref->y + i;
1982            bData.b_RefP[2] = fData->RefP[2] = f_RefH + i;
1983            bData.b_RefP[1] = fData->RefP[1] = f_RefV + i;
1984            bData.b_RefP[3] = fData->RefP[3] = f_RefHV + i;
1985            bData.RefP[0] = fData->b_RefP[0] = b_Ref->y + i;
1986