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

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

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

trunk/xvidcore/src/motion/motion_est.c revision 370, Mon Aug 12 10:07:16 2002 UTC branches/dev-api-4/xvidcore/src/motion/motion_est.c revision 1084, Sun Jul 13 09:58:44 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.22 2003-07-13 09:58:44 syskin Exp $
   
 /**************************************************************************  
  *  
  *  Modifications:  
  *  
  *      01.05.2002      updated MotionEstimationBVOP  
  *      25.04.2002 partial prevMB conversion  
  *  22.04.2002 remove some compile warning by chenm001 <chenm001@163.com>  
  *  14.04.2002 added MotionEstimationBVOP()  
  *  02.04.2002 add EPZS(^2) as ME algorithm, use PMV_USESQUARES to choose between  
  *             EPZS and EPZS^2  
  *  08.02.2002 split up PMVfast into three routines: PMVFast, PMVFast_MainLoop  
  *             PMVFast_Refine to support multiple searches with different start points  
  *  07.01.2002 uv-block-based interpolation  
  *  06.01.2002 INTER/INTRA-decision is now done before any SEARCH8 (speedup)  
  *             changed INTER_BIAS to 150 (as suggested by suxen_drol)  
  *             removed halfpel refinement step in PMVfastSearch8 + quality=5  
  *             added new quality mode = 6 which performs halfpel refinement  
  *             filesize difference between quality 5 and 6 is smaller than 1%  
  *             (Isibaar)  
  *  31.12.2001 PMVfastSearch16 and PMVfastSearch8 (gruel)  
  *  30.12.2001 get_range/MotionSearchX simplified; blue/green bug fix  
  *  22.12.2001 commented best_point==99 check  
  *  19.12.2001 modified get_range (purple bug fix)  
  *  15.12.2001 moved pmv displacement from mbprediction  
  *  02.12.2001 motion estimation/compensation split (Isibaar)  
  *  16.11.2001 rewrote/tweaked search algorithms; pross@cs.rmit.edu.au  
  *  10.11.2001 support for sad16/sad8 functions  
  *  28.08.2001 reactivated MODE_INTER4V for EXT_MODE  
  *  24.08.2001 removed MODE_INTER4V_Q, disabled MODE_INTER4V for EXT_MODE  
  *  22.08.2001 added MODE_INTER4V_Q  
  *  20.08.2001 added pragma to get rid of internal compiler error with VC6  
  *             idea by Cyril. Thanks.  
25   *   *
26   *  Michael Militzer <isibaar@videocoding.de>   ****************************************************************************/
  *  
  **************************************************************************/  
27    
28  #include <assert.h>  #include <assert.h>
29  #include <stdio.h>  #include <stdio.h>
30  #include <stdlib.h>  #include <stdlib.h>
31    #include <string.h>     /* memcpy */
32    #include <math.h>       /* lrint */
33    
34  #include "../encoder.h"  #include "../encoder.h"
35  #include "../utils/mbfunctions.h"  #include "../utils/mbfunctions.h"
36  #include "../prediction/mbprediction.h"  #include "../prediction/mbprediction.h"
37  #include "../global.h"  #include "../global.h"
38  #include "../utils/timer.h"  #include "../utils/timer.h"
39    #include "../image/interpolate8x8.h"
40    #include "motion_est.h"
41  #include "motion.h"  #include "motion.h"
42  #include "sad.h"  #include "sad.h"
43    #include "gmc.h"
44    #include "../utils/emms.h"
45    #include "../dct/fdct.h"
46    
47    /*****************************************************************************
48     * Modified rounding tables -- declared in motion.h
49     * Original tables see ISO spec tables 7-6 -> 7-9
50     ****************************************************************************/
51    
52    const uint32_t roundtab[16] =
53    {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2 };
54    
55    /* K = 4 */
56    const uint32_t roundtab_76[16] =
57    { 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1 };
58    
59    /* K = 2 */
60    const uint32_t roundtab_78[8] =
61    { 0, 0, 1, 1, 0, 0, 0, 1  };
62    
63    /* K = 1 */
64    const uint32_t roundtab_79[4] =
65    { 0, 1, 0, 0 };
66    
67    #define INITIAL_SKIP_THRESH     (10)
68    #define FINAL_SKIP_THRESH       (50)
69    #define MAX_SAD00_FOR_SKIP      (20)
70    #define MAX_CHROMA_SAD_FOR_SKIP (22)
71    
72    #define CHECK_CANDIDATE(X,Y,D) { \
73    CheckCandidate((X),(Y), (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;
227    
228          static const VECTOR zeroMV = { 0, 0 };          ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
229          VECTOR predMV;          ref1 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
230            switch( ((x&1)<<1) + (y&1) ) {
231            case 3: /* x and y in qpel resolution - the "corners" (top left/right and */
232                            /* bottom left/right) during qpel refinement */
233                    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          int32_t x, y;          case 1: /* x halfpel, y qpel - top or bottom during qpel refinement */
243          int32_t iIntra = 0;                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
244          VECTOR pmv;                  ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
245                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
246                    break;
247    
248          if (sadInit)          case 2: /* x qpel, y halfpel - left or right during qpel refinement */
249                  (*sadInit) ();                  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          for (y = 0; y < iHcount; y++)   {          default: /* pure halfpel position */
255                  for (x = 0; x < iWcount; x ++)  {                  return (uint8_t *) ref1;
256    
257                          MACROBLOCK *const pMB = &pMBs[x + y * iWcount];          }
258            return Reference;
259    }
260    
261                          if (pMB->mode == MODE_NOT_CODED)  static uint8_t *
262                                  continue;  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                          predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
273            switch( ((x&1)<<1) + (y&1) ) {
274            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                          pMB->sad16 =          case 1: /* x halfpel, y qpel - top or bottom during qpel refinement */
289                                  SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
290                                                   x, y, predMV.x, predMV.y, predMV.x, predMV.y,                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
291                                                   current->motion_flags, current->quant,                  interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
292                                                   current->fcode, pParam, pMBs, prevMBs, &pMB->mv16,                  interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
293                                                   &pMB->pmvs[0]);                  interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
294                    break;
295    
296                          if (0 < (pMB->sad16 - MV16_INTER_BIAS)) {          case 2: /* x qpel, y halfpel - left or right during qpel refinement */
297                                  int32_t deviation;                  ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
298                    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                                  deviation =          default: /* pure halfpel position */
305                                          dev16(pCurrent->y + x * 16 + y * 16 * pParam->edged_width,                  return (uint8_t *) ref1;
306                                                    pParam->edged_width);          }
307            return Reference;
308    }
309    
310                                  if (deviation < (pMB->sad16 - MV16_INTER_BIAS)) {  /* CHECK_CANDIATE FUNCTIONS START */
                                         pMB->mode = MODE_INTRA;  
                                         pMB->mv16 = pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =  
                                                 pMB->mvs[3] = zeroMV;  
                                         pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =  
                                                 pMB->sad8[3] = 0;  
311    
312                                          iIntra++;  static void
313                                          if (iIntra >= iLimit)  CheckCandidate16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
314                                                  return 1;  {
315            int xc, yc;
316            const uint8_t * Reference;
317            VECTOR * current;
318            int32_t sad; uint32_t t;
319    
320                                          continue;          if ( (x > data->max_dx) || (x < data->min_dx)
321                                  }                  || (y > data->max_dy) || (y < data->min_dy) ) return;
                         }  
322    
323                          pmv = pMB->pmvs[0];          if (!data->qpel_precision) {
324                          if (current->global_flags & XVID_INTER4V)                  Reference = GetReference(x, y, data);
325                                  if ((!(current->global_flags & XVID_LUMIMASKING) ||                  current = data->currentMV;
326                                           pMB->dquant == NO_CHANGE)) {                  xc = x; yc = y;
327                                          int32_t sad8 = IMV16X16 * current->quant;          } else { /* x and y are in 1/4 precision */
328                    Reference = Interpolate16x16qpel(x, y, 0, data);
329                                          if (sad8 < pMB->sad16) {                  xc = x/2; yc = y/2; /* for chroma sad */
330                                                  sad8 += pMB->sad8[0] =                  current = data->currentQMV;
                                                         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]);  
331                                          }                                          }
332    
333                                          /* decide: MODE_INTER or MODE_INTER4V          sad = sad16v(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
334                                             mpeg4:   if (sad8 < pMB->sad16 - nb/2+1) use_inter4v          t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
                                          */  
335    
336                                          if (sad8 < pMB->sad16) {          sad += (data->lambda16 * t * sad)>>10;
337                                                  pMB->mode = MODE_INTER4V;          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;
                                                 pMB->sad8[0] *= 4;  
                                                 pMB->sad8[1] *= 4;  
                                                 pMB->sad8[2] *= 4;  
                                                 pMB->sad8[3] *= 4;  
                                                 continue;  
                                         }  
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                          pMB->mode = MODE_INTER;          if (sad < data->iMinSAD[0]) {
344                          pMB->pmvs[0] = pmv;     /* pMB->pmvs[1] = pMB->pmvs[2] = pMB->pmvs[3]  are not needed for INTER */                  data->iMinSAD[0] = sad;
345                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mv16;                  current[0].x = x; current[0].y = y;
346                          pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] =                  *dir = Direction;
                                 pMB->sad16;  
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;
550                                    const uint8_t * const pRefH,  
551                                    const uint8_t * const pRefV,          if (data->chroma && sad < *data->iMinSAD)
552                                    const uint8_t * const pRefHV,                  sad += ChromaSAD2((xcf >> 1) + roundtab_79[xcf & 0x3],
553                                    const uint8_t * const cur,                                                          (ycf >> 1) + roundtab_79[ycf & 0x3],
554                                    const int x,                                                          (xcb >> 1) + roundtab_79[xcb & 0x3],
555                                    const int y,                                                          (ycb >> 1) + roundtab_79[ycb & 0x3], data);
                                    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);  
556    
557          return iMinSAD;          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;
574    
575  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */          for (k = 0; k < 4; k++) {
576                    mvs.x = data->directmvF[k].x + x;
577          if (iDirection) {                  b_mvs.x = ((x == 0) ?
578                  CHECK_MV16_CANDIDATE(start_x - iDiamondSize, start_y);                          data->directmvB[k].x
579                  CHECK_MV16_CANDIDATE(start_x + iDiamondSize, start_y);                          : mvs.x - data->referencemv[k].x);
580                  CHECK_MV16_CANDIDATE(start_x, start_y - iDiamondSize);  
581                  CHECK_MV16_CANDIDATE(start_x, start_y + iDiamondSize);                  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                                          const int TRB,          if (!data->qpel_precision) {
693                                          const int TRD,                  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 start_x,          for(i = 0; i < 4; i++) {
703                                      const int start_y,                  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                                      int iMinSAD,          bits += t = BITS_MULT*d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
                                     VECTOR * const currMV,  
                                         const VECTOR * const directmv,  
709    
710                                      const int32_t min_dx,          if (data->temp[0] + t < data->iMinSAD[1]) {
711                                          const int32_t max_dx,                  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 int32_t min_dy,          if (data->temp[1] < data->iMinSAD[2]) {
713                                          const int32_t max_dy,                  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 iEdgedWidth,          bits += BITS_MULT*xvid_cbpy_tab[15-(cbp>>2)].len;
                                         const int32_t iDiamondSize,  
720    
721                                          const int32_t iQuant,          if (bits >= data->iMinSAD[0]) return;
                                         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
722    
723          int32_t iSAD;          /* chroma */
724            xc = (xc >> 1) + roundtab_79[xc & 0x3];
725            yc = (yc >> 1) + roundtab_79[yc & 0x3];
726    
727          VECTOR backupMV;          /* 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          currMV->x = start_x;          /* chroma V */
734          currMV->y = start_y;          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  /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */          bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTER & 7) | ((cbp & 3) << 3)].len;
739    
740          do          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    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            if ( (x > data->max_dx) || (x < data->min_dx)
759                    || (y > data->max_dy) || (y < data->min_dy) ) return;
760    
761                  CHECK_MV16_DIRECT_FOUND(backupMV.x - iDiamondSize, backupMV.y);          if (!data->qpel_precision) {
762                  CHECK_MV16_DIRECT_FOUND(backupMV.x + iDiamondSize, backupMV.y);                  ptr = GetReference(x, y, data);
763                  CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y - iDiamondSize);                  current = data->currentMV;
764                  CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y + iDiamondSize);          } else { /* x and y are in 1/4 precision */
765                    ptr = Interpolate8x8qpel(x, y, 0, 0, data);
766                    current = data->currentQMV;
767            }
768    
769          } while (!iFound);          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                  }                  }
                 while (1);                              //forever  
         }  
         return iMinSAD;  
 }  
   
   
 int32_t  
 Full8_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,  
                            const int start_x,  
                            const int start_y,  
                            int iMinSAD,  
                            VECTOR * const currMV,  
                            const int center_x,  
                            const int center_y,  
                                  const int32_t min_dx,  
                                  const int32_t max_dx,  
                                  const int32_t min_dy,  
                                  const int32_t max_dy,  
                                  const int32_t iEdgedWidth,  
                                  const int32_t iDiamondSize,  
                                  const int32_t iFcode,  
                                  const int32_t iQuant,  
                                  int iFound)  
 {  
         int32_t iSAD;  
         int32_t dx, dy;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV8_CANDIDATE(dx, dy);  
   
         return iMinSAD;  
868  }  }
869    
870  Halfpel8_RefineFuncPtr Halfpel8_Refine;  static void
871    SquareSearch(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)  
872  {  {
873  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */          int iDirection;
   
         int32_t iSAD;  
         VECTOR backupMV = *currMV;  
874    
875          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y - 1);          do {
876          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y - 1);                  iDirection = 0;
877          CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y - 1);                  if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);
878          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y);                  if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);
879          CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y);                  if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);
880          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y + 1);                  if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128);
881          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y + 1);                  if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64);
882          CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y + 1);                  if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128);
883                    if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128);
884                    if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128);
885    
886          return iMinSAD;                  bDirection = iDirection;
887                    x = data->currentMV->x; y = data->currentMV->y;
888            } while (iDirection);
889  }  }
890    
891  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)  static void
892    DiamondSearch(int x, int y, const SearchData * const data, int bDirection)
   
   
 int32_t  
 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)  
893  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
   
         const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;  
894    
895          int32_t iDiamondSize;  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
896    
897          int32_t min_dx;          int iDirection;
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
898    
899          int32_t iFound;          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          VECTOR newMV;                  /* now we're doing diagonal checks near our candidate */
         VECTOR backupMV;                        /* just for PMVFAST */  
907    
908          VECTOR pmv[4];                  if (iDirection) {               /* checking if anything found */
909          int32_t psad[4];                          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          MainSearch16FuncPtr MainSearchPtr;  /* MAINSEARCH FUNCTIONS END */
927    
928          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;  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 threshA, threshB;          CHECK_CANDIDATE(centerMV.x, centerMV.y - 1, 0);
936          int32_t bPredEq;          CHECK_CANDIDATE(centerMV.x + 1, centerMV.y - 1, 0);
937          int32_t iMinSAD, iSAD;          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  /* Get maximum range */  static __inline int
946          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  SkipDecisionP(const IMAGE * current, const IMAGE * reference,
947                            iFcode);                                                          const int x, const int y,
948                                                            const uint32_t stride, const uint32_t iQuant, int rrv)
949    
950  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  {
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          if (!(MotionFlags & PMV_HALFPEL16)) {          } else {
962                  min_dx = EVEN(min_dx);                  uint32_t sadC = sad16(current->u + 2*offset,
963                  max_dx = EVEN(max_dx);                                                  reference->u + 2*offset, stride, 256*4096);
964                  min_dy = EVEN(min_dy);                  if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
965                  max_dy = EVEN(max_dy);                  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          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  static __inline void
973          //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  SkipMacroblockP(MACROBLOCK *pMB, const int32_t sad)
974          bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);  {
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          if ((x == 0) && (y == 0)) {  static __inline void
982                  threshA = 512;  ModeDecision(SearchData * const Data,
983                  threshB = 1024;                          MACROBLOCK * const pMB,
984                            const MACROBLOCK * const pMBs,
985                            const int x, const int y,
986                            const MBParam * const pParam,
987                            const uint32_t MotionFlags,
988                            const uint32_t VopFlags,
989                            const uint32_t VolFlags,
990                            const IMAGE * const pCurrent,
991                            const IMAGE * const pRef,
992                            const IMAGE * const vGMC,
993                            const int coding_type)
994    {
995            int mode = MODE_INTER;
996            int mcsel = 0;
997            int inter4v = (VopFlags & XVID_VOP_INTER4V) && (pMB->dquant == 0);
998            const uint32_t iQuant = pMB->quant;
999    
1000            const int skip_possible = (coding_type == P_VOP) && (pMB->dquant == 0);
1001    
1002            pMB->mcsel = 0;
1003    
1004            if (!(VopFlags & XVID_VOP_MODEDECISION_BITS)) { /* normal, fast, SAD-based mode decision */
1005                    int sad;
1006                    int InterBias = MV16_INTER_BIAS;
1007                    if (inter4v == 0 || Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
1008                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant) {
1009                            mode = MODE_INTER;
1010                            sad = Data->iMinSAD[0];
1011          } else {          } else {
1012                  threshA = psad[0];                          mode = MODE_INTER4V;
1013                  threshB = threshA + 256;                          sad = Data->iMinSAD[1] + Data->iMinSAD[2] +
1014                  if (threshA < 512)                                                  Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant;
1015                          threshA = 512;                          Data->iMinSAD[0] = sad;
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
1016          }          }
1017    
1018          iFound = 0;                  /* final skip decision, a.k.a. "the vector you found, really that good?" */
1019                    if (skip_possible && (pMB->sad16 < (int)iQuant * MAX_SAD00_FOR_SKIP))
1020  /* Step 4: Calculate SAD around the Median prediction.                          if ( (100*sad)/(pMB->sad16+1) > FINAL_SKIP_THRESH)
1021     MinSAD=SAD                                  if (Data->chroma || SkipDecisionP(pCurrent, pRef, x, y, Data->iEdgedWidth/2, iQuant, Data->rrv)) {
1022     If Motion Vector equal to Previous frame motion vector                                          mode = MODE_NOT_CODED;
1023     and MinSAD<PrevFrmSAD goto Step 10.                                          sad = 0;
    If SAD<=256 goto Step 10.  
 */  
   
         currMV->x = start_x;  
         currMV->y = start_y;  
   
         if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */  
                 currMV->x = EVEN(currMV->x);  
                 currMV->y = EVEN(currMV->y);  
1024          }          }
1025    
1026          if (currMV->x > max_dx) {                  /* mcsel */
1027                  currMV->x = max_dx;                  if (coding_type == S_VOP) {
         }  
         if (currMV->x < min_dx) {  
                 currMV->x = min_dx;  
         }  
         if (currMV->y > max_dy) {  
                 currMV->y = max_dy;  
         }  
         if (currMV->y < min_dy) {  
                 currMV->y = min_dy;  
         }  
1028    
1029          iMinSAD =                          int32_t iSAD = sad16(Data->Cur,
1030                  sad16(cur,                                  vGMC->y + 16*y*Data->iEdgedWidth + 16*x, Data->iEdgedWidth, 65536);
                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
1031    
1032          if ((iMinSAD < 256) ||                          if (Data->chroma) {
1033                  ((MVequal(*currMV, prevMB->mvs[0])) &&                                  iSAD += sad8(Data->CurU, vGMC->u + 8*y*(Data->iEdgedWidth/2) + 8*x, Data->iEdgedWidth/2);
1034                   ((int32_t) iMinSAD < prevMB->sad16))) {                                  iSAD += sad8(Data->CurV, vGMC->v + 8*y*(Data->iEdgedWidth/2) + 8*x, Data->iEdgedWidth/2);
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
                 {  
                         if (!MVzero(*currMV)) {  
                                 iMinSAD += MV16_00_BIAS;  
                                 CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures  
                                 iMinSAD -= MV16_00_BIAS;  
                         }  
1035                  }                  }
1036    
1037                  if (MotionFlags & PMV_QUICKSTOP16)                          if (iSAD <= sad) {              /* mode decision GMC */
1038                          goto PMVfast16_Terminate_without_Refine;                                  mode = MODE_INTER;
1039                  if (MotionFlags & PMV_EARLYSTOP16)                                  mcsel = 1;
1040                          goto PMVfast16_Terminate_with_Refine;                                  sad = iSAD;
1041          }          }
1042    
1043                    }
1044    
1045  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion                  /* intra decision */
    vector of the median.  
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
1046    
1047          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[0])))                  if (iQuant > 8) InterBias += 100 * (iQuant - 8); /* to make high quants work */
1048                  iFound = 2;                  if (y != 0)
1049                            if ((pMB - pParam->mb_width)->mode == MODE_INTRA ) InterBias -= 80;
1050                    if (x != 0)
1051                            if ((pMB - 1)->mode == MODE_INTRA ) InterBias -= 80;
1052    
1053  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.                  if (Data->chroma) InterBias += 50; /* dev8(chroma) ??? <-- yes, we need dev8 (no big difference though) */
1054     Otherwise select large Diamond Search.                  if (Data->rrv) InterBias *= 4;
 */  
1055    
1056          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))                  if (InterBias < sad) {
1057                  iDiamondSize = 1;               // halfpel!                          int32_t deviation;
1058                            if (!Data->rrv)
1059                                    deviation = dev16(Data->Cur, Data->iEdgedWidth);
1060          else          else
1061                  iDiamondSize = 2;               // halfpel!                                  deviation = dev16(Data->Cur, Data->iEdgedWidth) + /* dev32() */
1062                                                            dev16(Data->Cur+16, Data->iEdgedWidth) +
1063          if (!(MotionFlags & PMV_HALFPELDIAMOND16))                                                          dev16(Data->Cur + 16*Data->iEdgedWidth, Data->iEdgedWidth) +
1064                  iDiamondSize *= 2;                                                          dev16(Data->Cur+16+16*Data->iEdgedWidth, Data->iEdgedWidth);
   
 /*  
    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.  
 */  
1065    
1066  // (0,0) is always possible                          if (deviation < (sad - InterBias)) mode = MODE_INTRA;
1067                    }
         if (!MVzero(pmv[0]))  
                 CHECK_MV16_ZERO;  
1068    
1069  // previous frame MV is always possible                  pMB->cbp = 63;
1070                    pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
1071    
1072          if (!MVzero(prevMB->mvs[0]))          } else { /* BITS */
                 if (!MVequal(prevMB->mvs[0], pmv[0]))  
                         CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);  
1073    
1074  // left neighbour, if allowed                  int bits, intra, i, cbp, c[2] = {0, 0};
1075                    VECTOR backup[5], *v;
1076                    Data->iQuant = iQuant;
1077                    Data->cbp = c;
1078    
1079          if (!MVzero(pmv[1]))                  v = Data->qpel ? Data->currentQMV : Data->currentMV;
1080                  if (!MVequal(pmv[1], prevMB->mvs[0]))                  for (i = 0; i < 5; i++) {
1081                          if (!MVequal(pmv[1], pmv[0])) {                          Data->iMinSAD[i] = 256*4096;
1082                                  if (!(MotionFlags & PMV_HALFPEL16)) {                          backup[i] = v[i];
                                         pmv[1].x = EVEN(pmv[1].x);  
                                         pmv[1].y = EVEN(pmv[1].y);  
1083                                  }                                  }
1084    
1085                                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);                  bits = CountMBBitsInter(Data, pMBs, x, y, pParam, MotionFlags);
1086                    cbp = *Data->cbp;
1087    
1088                    if (coding_type == S_VOP) {
1089                            int bits_gmc;
1090                            *Data->iMinSAD = bits += BITS_MULT*1; /* mcsel */
1091                            bits_gmc = CountMBBitsGMC(Data, vGMC, x, y);
1092                            if (bits_gmc < bits) {
1093                                    mcsel = 1;
1094                                    *Data->iMinSAD = bits = bits_gmc;
1095                                    mode = MODE_INTER;
1096                                    cbp = *Data->cbp;
1097                          }                          }
 // top neighbour, if allowed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], prevMB->mvs[0]))  
                         if (!MVequal(pmv[2], pmv[0]))  
                                 if (!MVequal(pmv[2], pmv[1])) {  
                                         if (!(MotionFlags & PMV_HALFPEL16)) {  
                                                 pmv[2].x = EVEN(pmv[2].x);  
                                                 pmv[2].y = EVEN(pmv[2].y);  
1098                                          }                                          }
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
1099    
1100  // top right neighbour, if allowed                  if (inter4v) {
1101                                          if (!MVzero(pmv[3]))                          int bits_4v;
1102                                                  if (!MVequal(pmv[3], prevMB->mvs[0]))                          bits_4v = CountMBBitsInter4v(Data, pMB, pMBs, x, y, pParam, MotionFlags, backup);
1103                                                          if (!MVequal(pmv[3], pmv[0]))                          if (bits_4v < bits) {
1104                                                                  if (!MVequal(pmv[3], pmv[1]))                                  Data->iMinSAD[0] = bits = bits_4v;
1105                                                                          if (!MVequal(pmv[3], pmv[2])) {                                  mode = MODE_INTER4V;
1106                                                                                  if (!(MotionFlags & PMV_HALFPEL16)) {                                  cbp = *Data->cbp;
                                                                                         pmv[3].x = EVEN(pmv[3].x);  
                                                                                         pmv[3].y = EVEN(pmv[3].y);  
                                                                                 }  
                                                                                 CHECK_MV16_CANDIDATE(pmv[3].x,  
                                                                                                                          pmv[3].y);  
1107                                                                          }                                                                          }
1108                                  }                                  }
1109    
1110          if ((MVzero(*currMV)) &&                  intra = CountMBBitsIntra(Data);
1111                  (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )                  if (intra < bits) {
1112                  iMinSAD -= MV16_00_BIAS;                          *Data->iMinSAD = bits = intra;
1113                            mode = MODE_INTRA;
1114                    }
1115    
1116  /* Step 6: If MinSAD <= thresa goto Step 10.                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = 0;
1117     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.                  pMB->cbp = cbp;
1118  */          }
1119    
1120          if ((iMinSAD <= threshA) ||          if (Data->rrv) {
1121                  (MVequal(*currMV, prevMB->mvs[0]) &&                          Data->currentMV[0].x = RRV_MV_SCALEDOWN(Data->currentMV[0].x);
1122                   ((int32_t) iMinSAD < prevMB->sad16))) {                          Data->currentMV[0].y = RRV_MV_SCALEDOWN(Data->currentMV[0].y);
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
1123          }          }
1124    
1125            if (mode == MODE_INTER && mcsel == 0) {
1126                    pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
1127    
1128  /************ (Diamond Search)  **************/                  if(Data->qpel) {
1129  /*                          pMB->qmvs[0] = pMB->qmvs[1]
1130     Step 7: Perform Diamond search, with either the small or large diamond.                                  = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1131     If Found=2 only examine one Diamond pattern, and afterwards goto step 10                          pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1132     Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.                          pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;
1133     If center then goto step 10.                  } else {
1134     Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.                          pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1135     Refine by using small diamond and goto step 10.                          pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
1136  */                  }
1137    
1138          if (MotionFlags & PMV_USESQUARES16)          } else if (mode == MODE_INTER ) { // but mcsel == 1
                 MainSearchPtr = Square16_MainSearch;  
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
1139    
1140          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                  pMB->mcsel = 1;
1141                    if (Data->qpel) {
1142                            pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] = pMB->qmvs[3] = pMB->amv;
1143                            pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = pMB->amv.x/2;
1144                            pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = pMB->amv.y/2;
1145                    } else
1146                            pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->amv;
1147    
1148            } else
1149                    if (mode == MODE_INTER4V) ; /* anything here? */
1150            else    /* INTRA, NOT_CODED */
1151                    SkipMacroblockP(pMB, 0);
1152    
1153            pMB->mode = mode;
1154    }
1155    
1156  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  bool
1157          iSAD =  MotionEstimation(MBParam * const pParam,
1158                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                   FRAMEINFO * const current,
1159                                                    currMV->x, currMV->y, iMinSAD, &newMV, center_x, center_y,                                   FRAMEINFO * const reference,
1160                                                    min_dx, max_dx,                                   const IMAGE * const pRefH,
1161                                                    min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,                                   const IMAGE * const pRefV,
1162                                                    iQuant, iFound);                                   const IMAGE * const pRefHV,
1163                                    const IMAGE * const pGMC,
1164                                     const uint32_t iLimit)
1165    {
1166            MACROBLOCK *const pMBs = current->mbs;
1167            const IMAGE *const pCurrent = &current->image;
1168            const IMAGE *const pRef = &reference->image;
1169    
1170          if (iSAD < iMinSAD) {          uint32_t mb_width = pParam->mb_width;
1171                  *currMV = newMV;          uint32_t mb_height = pParam->mb_height;
1172                  iMinSAD = iSAD;          const uint32_t iEdgedWidth = pParam->edged_width;
1173            const uint32_t MotionFlags = MakeGoodMotionFlags(current->motion_flags, current->vop_flags, current->vol_flags);
1174    
1175            uint32_t x, y;
1176            uint32_t iIntra = 0;
1177            int32_t quant = current->quant, sad00;
1178            int skip_thresh = INITIAL_SKIP_THRESH * \
1179                    (current->vop_flags & XVID_VOP_REDUCED ? 4:1) * \
1180                    (current->vop_flags & XVID_VOP_MODEDECISION_BITS ? 2:1);
1181    
1182            /* some pre-initialized thingies for SearchP */
1183            int32_t temp[8];
1184            VECTOR currentMV[5];
1185            VECTOR currentQMV[5];
1186            int32_t iMinSAD[5];
1187            DECLARE_ALIGNED_MATRIX(dct_space, 3, 64, int16_t, CACHE_LINE);
1188            SearchData Data;
1189            memset(&Data, 0, sizeof(SearchData));
1190            Data.iEdgedWidth = iEdgedWidth;
1191            Data.currentMV = currentMV;
1192            Data.currentQMV = currentQMV;
1193            Data.iMinSAD = iMinSAD;
1194            Data.temp = temp;
1195            Data.iFcode = current->fcode;
1196            Data.rounding = pParam->m_rounding_type;
1197            Data.qpel = (current->vol_flags & XVID_VOL_QUARTERPEL ? 1:0);
1198            Data.chroma = MotionFlags & XVID_ME_CHROMA16;
1199            Data.rrv = (current->vop_flags & XVID_VOP_REDUCED) ? 1:0;
1200            Data.dctSpace = dct_space;
1201            Data.quant_type = !(pParam->vol_flags & XVID_VOL_MPEGQUANT);
1202    
1203            if ((current->vop_flags & XVID_VOP_REDUCED)) {
1204                    mb_width = (pParam->width + 31) / 32;
1205                    mb_height = (pParam->height + 31) / 32;
1206                    Data.qpel = 0;
1207            }
1208    
1209            Data.RefQ = pRefV->u; /* a good place, also used in MC (for similar purpose) */
1210            if (sadInit) (*sadInit) ();
1211    
1212            for (y = 0; y < mb_height; y++) {
1213                    for (x = 0; x < mb_width; x++)  {
1214                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1215    
1216                            if (!Data.rrv) pMB->sad16 =
1217                                    sad16v(pCurrent->y + (x + y * iEdgedWidth) * 16,
1218                                                            pRef->y + (x + y * iEdgedWidth) * 16,
1219                                                            pParam->edged_width, pMB->sad8 );
1220    
1221                            else pMB->sad16 =
1222                                    sad32v_c(pCurrent->y + (x + y * iEdgedWidth) * 32,
1223                                                            pRef->y + (x + y * iEdgedWidth) * 32,
1224                                                            pParam->edged_width, pMB->sad8 );
1225    
1226                            if (Data.chroma) {
1227                                    Data.temp[7] = sad8(pCurrent->u + x*8 + y*(iEdgedWidth/2)*8,
1228                                                                            pRef->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2)
1229                                                                    + sad8(pCurrent->v + (x + y*(iEdgedWidth/2))*8,
1230                                                                            pRef->v + (x + y*(iEdgedWidth/2))*8, iEdgedWidth/2);
1231                                    pMB->sad16 += Data.temp[7];
1232                            }
1233    
1234                            sad00 = pMB->sad16;
1235    
1236                            if (pMB->dquant != 0) {
1237                                    quant += DQtab[pMB->dquant];
1238                                    if (quant > 31) quant = 31;
1239                                    else if (quant < 1) quant = 1;
1240                            }
1241                            pMB->quant = quant;
1242    
1243                            /* initial skip decision */
1244                            /* no early skip for GMC (global vector = skip vector is unknown!)  */
1245                            if (current->coding_type != S_VOP)      { /* no fast SKIP for S(GMC)-VOPs */
1246                                    if (pMB->dquant == 0 && sad00 < pMB->quant * skip_thresh)
1247                                            if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, iEdgedWidth/2, pMB->quant, Data.rrv)) {
1248                                                    SkipMacroblockP(pMB, sad00);
1249                                                    continue;
1250                                            }
1251          }          }
1252    
1253          if (MotionFlags & PMV_EXTSEARCH16) {                          SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1254  /* extended: search (up to) two more times: orignal prediction and (0,0) */                                          y, MotionFlags, current->vop_flags, current->vol_flags,
1255                                            &Data, pParam, pMBs, reference->mbs, pMB);
1256    
1257                  if (!(MVequal(pmv[0], backupMV))) {                          ModeDecision(&Data, pMB, pMBs, x, y, pParam,
1258                          iSAD =                                                   MotionFlags, current->vop_flags, current->vol_flags,
1259                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                                   pCurrent, pRef, pGMC, current->coding_type);
                                                                   center_x, center_y, iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
1260    
1261                          if (iSAD < iMinSAD) {                          if (pMB->mode == MODE_INTRA)
1262                                  *currMV = newMV;                                  if (++iIntra > iLimit) return 1;
                                 iMinSAD = iSAD;  
1263                          }                          }
1264                  }                  }
1265    
1266                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {  //      if (current->vol_flags & XVID_VOL_GMC ) /* GMC only for S(GMC)-VOPs */
1267                          iSAD =  //      {
1268                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  //              current->warp = GlobalMotionEst( pMBs, pParam, current, reference, pRefH, pRefV, pRefHV);
1269                                                                    iMinSAD, &newMV, center_x, center_y,  //      }
1270                                                                    min_dx, max_dx, min_dy, max_dy,          return 0;
1271                                                                    iEdgedWidth, iDiamondSize, iFcode,  }
1272                                                                    iQuant, iFound);  
1273    
1274                          if (iSAD < iMinSAD) {  static __inline int
1275                                  *currMV = newMV;  make_mask(const VECTOR * const pmv, const int i)
1276                                  iMinSAD = iSAD;  {
1277            int mask = 255, j;
1278            for (j = 0; j < i; j++) {
1279                    if (MVequal(pmv[i], pmv[j])) return 0; /* same vector has been checked already */
1280                    if (pmv[i].x == pmv[j].x) {
1281                            if (pmv[i].y == pmv[j].y + iDiamondSize) mask &= ~4;
1282                            else if (pmv[i].y == pmv[j].y - iDiamondSize) mask &= ~8;
1283                    } else
1284                            if (pmv[i].y == pmv[j].y) {
1285                                    if (pmv[i].x == pmv[j].x + iDiamondSize) mask &= ~1;
1286                                    else if (pmv[i].x == pmv[j].x - iDiamondSize) mask &= ~2;
1287                          }                          }
1288                  }                  }
1289            return mask;
1290          }          }
1291    
1292  /*  static __inline void
1293     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  PreparePredictionsP(VECTOR * const pmv, int x, int y, int iWcount,
1294  */                          int iHcount, const MACROBLOCK * const prevMB, int rrv)
1295    {
1296    PMVfast16_Terminate_with_Refine:          /* this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself */
1297          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step          if (rrv) { iWcount /= 2; iHcount /= 2; }
                 iMinSAD =  
                         Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
1298    
1299    PMVfast16_Terminate_without_Refine:          if ( (y != 0) && (x < (iWcount-1)) ) {          /* [5] top-right neighbour */
1300          currPMV->x = currMV->x - center_x;                  pmv[5].x = EVEN(pmv[3].x);
1301          currPMV->y = currMV->y - center_y;                  pmv[5].y = EVEN(pmv[3].y);
1302          return iMinSAD;          } else pmv[5].x = pmv[5].y = 0;
 }  
1303    
1304            if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }/* pmv[3] is left neighbour */
1305            else pmv[3].x = pmv[3].y = 0;
1306    
1307            if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }/* [4] top neighbour */
1308            else pmv[4].x = pmv[4].y = 0;
1309    
1310            /* [1] median prediction */
1311            pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
1312    
1313            pmv[0].x = pmv[0].y = 0; /* [0] is zero; not used in the loop (checked before) but needed here for make_mask */
1314    
1315            pmv[2].x = EVEN(prevMB->mvs[0].x); /* [2] is last frame */
1316            pmv[2].y = EVEN(prevMB->mvs[0].y);
1317    
1318  int32_t          if ((x < iWcount-1) && (y < iHcount-1)) {
1319  Diamond8_MainSearch(const uint8_t * const pRef,                  pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); /* [6] right-down neighbour in last frame */
1320                                          const uint8_t * const pRefH,                  pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
1321                                          const uint8_t * const pRefV,          } else pmv[6].x = pmv[6].y = 0;
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x,  
                                         const int y,  
                                         int32_t start_x,  
                                         int32_t start_y,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t 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);  
1322    
1323          if (iDirection) {          if (rrv) {
1324                  while (!iFound) {                  int i;
1325                          iFound = 1;                  for (i = 0; i < 7; i++) {
1326                          backupMV = *currMV;     // since iDirection!=0, this is well defined!                          pmv[i].x = RRV_MV_SCALEUP(pmv[i].x);
1327                          iDirectionBackup = iDirection;                          pmv[i].y = RRV_MV_SCALEUP(pmv[i].y);
   
                         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);  
1328                  }                  }
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
1329          }          }
         return iMinSAD;  
1330  }  }
1331    
1332    static void
1333    SearchP(const IMAGE * const pRef,
   
 int32_t  
 Square8_MainSearch(const uint8_t * const pRef,  
1334                                          const uint8_t * const pRefH,                                          const uint8_t * const pRefH,
1335                                          const uint8_t * const pRefV,                                          const uint8_t * const pRefV,
1336                                          const uint8_t * const pRefHV,                                          const uint8_t * const pRefHV,
1337                                          const uint8_t * const cur,                  const IMAGE * const pCur,
1338                                          const int x,                                          const int x,
1339                                          const int y,                                          const int y,
1340                                          int32_t start_x,                  const uint32_t MotionFlags,
1341                                          int32_t start_y,                  const uint32_t VopFlags,
1342                                          int32_t iMinSAD,                  const uint32_t VolFlags,
1343                                          VECTOR * const currMV,                  SearchData * const Data,
1344                                     const int center_x,                  const MBParam * const pParam,
1345                                     const int center_y,                  const MACROBLOCK * const pMBs,
1346                                          const int32_t min_dx,                  const MACROBLOCK * const prevMBs,
1347                                          const int32_t max_dx,                  MACROBLOCK * const pMB)
1348                                          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  
 */  
1349    
1350          CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);          int i, iDirection = 255, mask, threshA;
1351          CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);          VECTOR pmv[7];
1352          CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);          int inter4v = (VopFlags & XVID_VOP_INTER4V) && (pMB->dquant == 0);
1353          CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
1354            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1355          CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,                                                  pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
1356                                                           backupMV.y - iDiamondSize, 5);  
1357          CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,          get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);
1358                                                           backupMV.y + iDiamondSize, 6);  
1359          CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,          Data->temp[5] = Data->temp[6] = 0; /* chroma-sad cache */
1360                                                           backupMV.y - iDiamondSize, 7);          i = Data->rrv ? 2 : 1;
1361          CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,          Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16*i;
1362                                                           backupMV.y + iDiamondSize, 8);          Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1363            Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1364    
1365            Data->RefP[0] = pRef->y + (x + Data->iEdgedWidth*y) * 16*i;
1366            Data->RefP[2] = pRefH + (x + Data->iEdgedWidth*y) * 16*i;
1367            Data->RefP[1] = pRefV + (x + Data->iEdgedWidth*y) * 16*i;
1368            Data->RefP[3] = pRefHV + (x + Data->iEdgedWidth*y) * 16*i;
1369            Data->RefP[4] = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1370            Data->RefP[5] = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1371    
1372            Data->lambda16 = lambda_vec16[pMB->quant];
1373            Data->lambda8 = lambda_vec8[pMB->quant];
1374            Data->qpel_precision = 0;
1375    
1376            memset(Data->currentMV, 0, 5*sizeof(VECTOR));
1377    
1378            if (Data->qpel) Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1379            else Data->predMV = pmv[0];
1380    
1381            i = d_mv_bits(0, 0, Data->predMV, Data->iFcode, 0, 0);
1382            Data->iMinSAD[0] = pMB->sad16 + ((Data->lambda16 * i * pMB->sad16)>>10);
1383            Data->iMinSAD[1] = pMB->sad8[0] + ((Data->lambda8 * i * (pMB->sad8[0]+NEIGH_8X8_BIAS)) >> 10);
1384            Data->iMinSAD[2] = pMB->sad8[1];
1385            Data->iMinSAD[3] = pMB->sad8[2];
1386            Data->iMinSAD[4] = pMB->sad8[3];
1387    
1388            if ((!(VopFlags & XVID_VOP_MODEDECISION_BITS)) && (x | y)) {
1389                    threshA = Data->temp[0]; /* that's where we keep this SAD atm */
1390                    if (threshA < 512) threshA = 512;
1391                    else if (threshA > 1024) threshA = 1024;
1392            } else
1393                    threshA = 512;
1394    
1395            PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
1396                                            prevMBs + x + y * pParam->mb_width, Data->rrv);
1397    
1398          if (iDirection) {          if (!Data->rrv) {
1399                  while (!iFound) {                  if (inter4v | Data->chroma) CheckCandidate = CheckCandidate16;
1400                          iFound = 1;                          else CheckCandidate = CheckCandidate16no4v; /* for extra speed */
1401                          backupMV = *currMV;          } else CheckCandidate = CheckCandidate32;
1402    
1403    /* main loop. checking all predictions (but first, which is 0,0 and has been checked in MotionEstimation())*/
1404    
1405            for (i = 1; i < 7; i++) {
1406                    if (!(mask = make_mask(pmv, i)) ) continue;
1407                    CheckCandidate(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1408                    if (Data->iMinSAD[0] <= threshA) break;
1409            }
1410    
1411            if ((Data->iMinSAD[0] <= threshA) ||
1412                            (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
1413                            (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16)))
1414                    inter4v = 0;
1415            else {
1416    
1417                          switch (iDirection) {                  MainSearchFunc * MainSearchPtr;
1418                          case 1:                  if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1419                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1420                                                                                     backupMV.y, 1);                          else MainSearchPtr = DiamondSearch;
                                 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;  
1421    
1422                          case 3:                  MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
1423    
1424                          case 4:  /* extended search, diamond starting in 0,0 and in prediction.
1425                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,          note that this search is/might be done in halfpel positions,
1426                                                                                   3);          which makes it more different than the diamond above */
                                 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);  
1427    
1428                                  break;                  if (MotionFlags & XVID_ME_EXTSEARCH16) {
1429                            int32_t bSAD;
1430                            VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
1431                            if (Data->rrv) {
1432                                    startMV.x = RRV_MV_SCALEUP(startMV.x);
1433                                    startMV.y = RRV_MV_SCALEUP(startMV.y);
1434                            }
1435                            if (!(MVequal(startMV, backupMV))) {
1436                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1437    
1438                          case 7:                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1439                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1440                                                                                     backupMV.y, 1);                                  if (bSAD < Data->iMinSAD[0]) {
1441                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                                          Data->currentMV[0] = backupMV;
1442                                                                                   4);                                          Data->iMinSAD[0] = bSAD; }
1443                                  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;  
1444    
1445                          case 8:                          backupMV = Data->currentMV[0];
1446                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,                          startMV.x = startMV.y = 1;
1447                                                                                   2);                          if (!(MVequal(startMV, backupMV))) {
1448                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                                  bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1449                                                                                   4);  
1450                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1451                                                                                   backupMV.y + iDiamondSize, 6);                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1452                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                                  if (bSAD < Data->iMinSAD[0]) {
1453                                                                                   backupMV.y - iDiamondSize, 7);                                          Data->currentMV[0] = backupMV;
1454                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                                          Data->iMinSAD[0] = bSAD; }
                                                                                  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;  
1455                          }                          }
1456                  }                  }
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
1457          }          }
1458          return iMinSAD;  
1459            if (MotionFlags & XVID_ME_HALFPELREFINE16)
1460                            SubpelRefine(Data);
1461    
1462            for(i = 0; i < 5; i++) {
1463                    Data->currentQMV[i].x = 2 * Data->currentMV[i].x; /* initialize qpel vectors */
1464                    Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
1465  }  }
1466    
1467            if (Data->qpel) {
1468                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1469                                    pParam->width, pParam->height, Data->iFcode, 1, 0);
1470                    Data->qpel_precision = 1;
1471                    if (MotionFlags & XVID_ME_QUARTERPELREFINE16)
1472                            SubpelRefine(Data);
1473            }
1474    
1475            if (Data->iMinSAD[0] < (int32_t)pMB->quant * 30)
1476                    inter4v = 0;
1477    
1478            if (inter4v) {
1479                    SearchData Data8;
1480                    memcpy(&Data8, Data, sizeof(SearchData)); /* quick copy of common data */
1481    
1482                    Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
1483                    Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
1484                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
1485                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
1486    
1487  int32_t                  if ((Data->chroma) && (!(VopFlags & XVID_VOP_MODEDECISION_BITS))) {
1488  Halfpel8_Refine_c(const uint8_t * const pRef,                          /* chroma is only used for comparsion to INTER. if the comparsion will be done in BITS domain, it will not be used */
1489                                  const uint8_t * const pRefH,                          int sumx = 0, sumy = 0;
                                 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);  
1490    
1491          return iMinSAD;                          if (Data->qpel)
1492                                    for (i = 1; i < 5; i++) {
1493                                            sumx += Data->currentQMV[i].x/2;
1494                                            sumy += Data->currentQMV[i].y/2;
1495                                    }
1496                            else
1497                                    for (i = 1; i < 5; i++) {
1498                                            sumx += Data->currentMV[i].x;
1499                                            sumy += Data->currentMV[i].y;
1500  }  }
1501    
1502                            Data->iMinSAD[1] += ChromaSAD(  (sumx >> 3) + roundtab_76[sumx & 0xf],
1503                                                                                            (sumy >> 3) + roundtab_76[sumy & 0xf], Data);
1504                    }
1505            } else Data->iMinSAD[1] = 4096*256;
1506    }
1507    
1508  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)  static void
1509    Search8(const SearchData * const OldData,
1510  int32_t                  const int x, const int y,
 PMVfastSearch8(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,  
                            const int start_y,  
                                 const int center_x,  
                                 const int center_y,  
1511                             const uint32_t MotionFlags,                             const uint32_t MotionFlags,
                            const uint32_t iQuant,  
                            const uint32_t iFcode,  
1512                             const MBParam * const pParam,                             const MBParam * const pParam,
1513                    MACROBLOCK * const pMB,
1514                             const MACROBLOCK * const pMBs,                             const MACROBLOCK * const pMBs,
1515                             const MACROBLOCK * const prevMBs,                  const int block,
1516                             VECTOR * const currMV,                  SearchData * const Data)
                            VECTOR * const currPMV)  
1517  {  {
1518          const uint32_t iWcount = pParam->mb_width;          int i = 0;
1519          const int32_t iWidth = pParam->width;          Data->iMinSAD = OldData->iMinSAD + 1 + block;
1520          const int32_t iHeight = pParam->height;          Data->currentMV = OldData->currentMV + 1 + block;
1521          const int32_t iEdgedWidth = pParam->edged_width;          Data->currentQMV = OldData->currentQMV + 1 + block;
1522    
1523            if(Data->qpel) {
1524                    Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1525                    if (block != 0) i = d_mv_bits(  Data->currentQMV->x, Data->currentQMV->y,
1526                                                                                    Data->predMV, Data->iFcode, 0, 0);
1527            } else {
1528                    Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1529                    if (block != 0) i = d_mv_bits(  Data->currentMV->x, Data->currentMV->y,
1530                                                                                    Data->predMV, Data->iFcode, 0, Data->rrv);
1531            }
1532    
1533          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;          *(Data->iMinSAD) += (Data->lambda8 * i * (*Data->iMinSAD + NEIGH_8X8_BIAS))>>10;
1534    
1535          int32_t iDiamondSize;          if (MotionFlags & (XVID_ME_EXTSEARCH8|XVID_ME_HALFPELREFINE8|XVID_ME_QUARTERPELREFINE8)) {
1536    
1537          int32_t min_dx;                  if (Data->rrv) i = 16; else i = 8;
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
1538    
1539          VECTOR pmv[4];                  Data->RefP[0] = OldData->RefP[0] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1540          int32_t psad[4];                  Data->RefP[1] = OldData->RefP[1] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1541          VECTOR newMV;                  Data->RefP[2] = OldData->RefP[2] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1542          VECTOR backupMV;                  Data->RefP[3] = OldData->RefP[3] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
         VECTOR startMV;  
1543    
1544  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;                  Data->Cur = OldData->Cur + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1545          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;                  Data->qpel_precision = 0;
1546    
1547           int32_t threshA, threshB;                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1548          int32_t iFound, bPredEq;                                          pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
         int32_t iMinSAD, iSAD;  
1549    
1550          int32_t iSubBlock = (y & 1) + (y & 1) + (x & 1);                  if (!Data->rrv) CheckCandidate = CheckCandidate8;
1551                    else CheckCandidate = CheckCandidate16no4v;
1552    
1553          MainSearch8FuncPtr MainSearchPtr;                  if (MotionFlags & XVID_ME_EXTSEARCH8 && (!(MotionFlags & XVID_ME_EXTSEARCH_BITS))) {
1554                            int32_t temp_sad = *(Data->iMinSAD); /* store current MinSAD */
1555    
1556          /* Init variables */                          MainSearchFunc *MainSearchPtr;
1557          startMV.x = start_x;                          if (MotionFlags & XVID_ME_USESQUARES8) MainSearchPtr = SquareSearch;
1558          startMV.y = start_y;                                  else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1559                                            else MainSearchPtr = DiamondSearch;
1560    
1561          /* Get maximum range */                          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, 255);
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,  
                           iFcode);  
1562    
1563          if (!(MotionFlags & PMV_HALFPELDIAMOND8)) {                          if(*(Data->iMinSAD) < temp_sad) {
1564                  min_dx = EVEN(min_dx);                                          Data->currentQMV->x = 2 * Data->currentMV->x; /* update our qpel vector */
1565                  max_dx = EVEN(max_dx);                                          Data->currentQMV->y = 2 * Data->currentMV->y;
1566                  min_dy = EVEN(min_dy);                          }
1567                  max_dy = EVEN(max_dy);                  }
1568    
1569                    if (MotionFlags & XVID_ME_HALFPELREFINE8) {
1570                            int32_t temp_sad = *(Data->iMinSAD); /* store current MinSAD */
1571    
1572                            SubpelRefine(Data); /* perform halfpel refine of current best vector */
1573    
1574                            if(*(Data->iMinSAD) < temp_sad) { /* we have found a better match */
1575                                    Data->currentQMV->x = 2 * Data->currentMV->x; /* update our qpel vector */
1576                                    Data->currentQMV->y = 2 * Data->currentMV->y;
1577                            }
1578          }          }
1579    
1580          /* because we might use IF (dx>max_dx) THEN dx=max_dx; */                  if (Data->qpel && MotionFlags & XVID_ME_QUARTERPELREFINE8) {
1581          //bPredEq = get_pmvdata(pMBs, (x >> 1), (y >> 1), iWcount, iSubBlock, pmv, psad);                                  Data->qpel_precision = 1;
1582          bPredEq = get_pmvdata2(pMBs, iWcount, 0, (x >> 1), (y >> 1), iSubBlock, pmv, psad);                                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1583                                            pParam->width, pParam->height, Data->iFcode, 1, 0);
1584                                    SubpelRefine(Data);
1585                    }
1586            }
1587    
1588          if ((x == 0) && (y == 0)) {          if (Data->rrv) {
1589                  threshA = 512 / 4;                          Data->currentMV->x = RRV_MV_SCALEDOWN(Data->currentMV->x);
1590                  threshB = 1024 / 4;                          Data->currentMV->y = RRV_MV_SCALEDOWN(Data->currentMV->y);
1591            }
1592    
1593            if(Data->qpel) {
1594                    pMB->pmvs[block].x = Data->currentQMV->x - Data->predMV.x;
1595                    pMB->pmvs[block].y = Data->currentQMV->y - Data->predMV.y;
1596                    pMB->qmvs[block] = *Data->currentQMV;
1597          } else {          } else {
1598                  threshA = psad[0] / 4;  /* good estimate? */                  pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1599                  threshB = threshA + 256 / 4;                  pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
1600                  if (threshA < 512 / 4)          }
                         threshA = 512 / 4;  
                 if (threshA > 1024 / 4)  
                         threshA = 1024 / 4;  
                 if (threshB > 1792 / 4)  
                         threshB = 1792 / 4;  
         }  
   
         iFound = 0;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
1601    
1602            pMB->mvs[block] = *Data->currentMV;
1603            pMB->sad8[block] = 4 * *Data->iMinSAD;
1604    }
1605    
1606  // Prepare for main loop  /* motion estimation for B-frames */
1607    
1608    if (MotionFlags & PMV_USESQUARES8)  static __inline VECTOR
1609        MainSearchPtr = Square8_MainSearch;  ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1610    else  {
1611    /* the stupidiest function ever */
1612            return (mode == MODE_FORWARD ? pMB->mvs[0] : pMB->b_mvs[0]);
1613    }
1614    
1615          if (MotionFlags & PMV_ADVANCEDDIAMOND8)  static void __inline
1616                  MainSearchPtr = AdvDiamond8_MainSearch;  PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
1617          else                                                          const uint32_t iWcount,
1618                  MainSearchPtr = Diamond8_MainSearch;                                                          const MACROBLOCK * const pMB,
1619                                                            const uint32_t mode_curr)
1620    {
1621    
1622            /* [0] is prediction */
1623            pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
1624    
1625          *currMV = startMV;          pmv[1].x = pmv[1].y = 0; /* [1] is zero */
1626    
1627          iMinSAD =          pmv[2] = ChoosePred(pMB, mode_curr);
1628                  sad8(cur,          pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
                          get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  
                                                 iEdgedWidth), iEdgedWidth);  
         iMinSAD +=  
                 calc_delta_8(currMV->x - center_x, currMV->y - center_y,  
                                          (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256 / 4) || ((MVequal(*currMV, prevMB->mvs[iSubBlock]))  
                                                                 && ((int32_t) iMinSAD <  
                                                                         prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  
    vector of the median.  
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
1629    
1630          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[iSubBlock])))          if ((y != 0)&&(x != (int)(iWcount+1))) {                        /* [3] top-right neighbour */
1631                  iFound = 2;                  pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
1632                    pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
1633            } else pmv[3].x = pmv[3].y = 0;
1634    
1635  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          if (y != 0) {
1636     Otherwise select large Diamond Search.                  pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
1637  */                  pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
1638            } else pmv[4].x = pmv[4].y = 0;
1639    
1640          if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))          if (x != 0) {
1641                  iDiamondSize = 1;               // 1 halfpel!                  pmv[5] = ChoosePred(pMB-1, mode_curr);
1642          else                  pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1643                  iDiamondSize = 2;               // 2 halfpel = 1 full pixel!          } else pmv[5].x = pmv[5].y = 0;
1644    
1645          if (!(MotionFlags & PMV_HALFPELDIAMOND8))          if (x != 0 && y != 0) {
1646                  iDiamondSize *= 2;                  pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
1647                    pmv[6].x = EVEN(pmv[6].x); pmv[6].y = EVEN(pmv[6].y);
1648            } else pmv[6].x = pmv[6].y = 0;
1649    }
1650    
1651    
1652  /*  /* search backward or forward */
1653     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  static void
1654     Also calculate (0,0) but do not subtract offset.  SearchBF(       const IMAGE * const pRef,
1655     Let MinSAD be the smallest SAD up to this point.                          const uint8_t * const pRefH,
1656     If MV is (0,0) subtract offset.                          const uint8_t * const pRefV,
1657  */                          const uint8_t * const pRefHV,
1658                            const IMAGE * const pCur,
1659                            const int x, const int y,
1660                            const uint32_t MotionFlags,
1661                            const uint32_t iFcode,
1662                            const MBParam * const pParam,
1663                            MACROBLOCK * const pMB,
1664                            const VECTOR * const predMV,
1665                            int32_t * const best_sad,
1666                            const int32_t mode_current,
1667                            SearchData * const Data)
1668    {
1669    
1670  // the median prediction might be even better than mv16          int i, iDirection = 255, mask;
1671            VECTOR pmv[7];
1672            MainSearchFunc *MainSearchPtr;
1673            *Data->iMinSAD = MV_MAX_ERROR;
1674            Data->iFcode = iFcode;
1675            Data->qpel_precision = 0;
1676            Data->temp[5] = Data->temp[6] = Data->temp[7] = 256*4096; /* reset chroma-sad cache */
1677    
1678          if (!MVequal(pmv[0], startMV))          Data->RefP[0] = pRef->y + (x + Data->iEdgedWidth*y) * 16;
1679                  CHECK_MV8_CANDIDATE(center_x, center_y);          Data->RefP[2] = pRefH + (x + Data->iEdgedWidth*y) * 16;
1680            Data->RefP[1] = pRefV + (x + Data->iEdgedWidth*y) * 16;
1681            Data->RefP[3] = pRefHV + (x + Data->iEdgedWidth*y) * 16;
1682            Data->RefP[4] = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8;
1683            Data->RefP[5] = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8;
1684    
1685  // (0,0) if needed          Data->predMV = *predMV;
         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;  
1686    
1687            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1688                                    pParam->width, pParam->height, iFcode - Data->qpel, 0, 0);
1689    
1690  /* Step 6: If MinSAD <= thresa goto Step 10.          pmv[0] = Data->predMV;
1691     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.          if (Data->qpel) { pmv[0].x /= 2; pmv[0].y /= 2; }
1692  */  
1693            PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);
1694    
1695          if ((iMinSAD <= threshA) ||          Data->currentMV->x = Data->currentMV->y = 0;
1696                  (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&          CheckCandidate = CheckCandidate16no4v;
1697                   ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {  
1698                  if (MotionFlags & PMV_QUICKSTOP16)          /* main loop. checking all predictions */
1699                          goto PMVfast8_Terminate_without_Refine;          for (i = 0; i < 7; i++) {
1700                  if (MotionFlags & PMV_EARLYSTOP16)                  if (!(mask = make_mask(pmv, i)) ) continue;
1701                          goto PMVfast8_Terminate_with_Refine;                  CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1702          }          }
1703    
1704  /************ (Diamond Search)  **************/          if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1705  /*          else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1706     Step 7: Perform Diamond search, with either the small or large diamond.                  else MainSearchPtr = DiamondSearch;
    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.  
 */  
1707    
1708          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
1709    
1710  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          SubpelRefine(Data);
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  
                                                   currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
1711    
1712          if (iSAD < iMinSAD) {          if (Data->qpel && *Data->iMinSAD < *best_sad + 300) {
1713                  *currMV = newMV;                  Data->currentQMV->x = 2*Data->currentMV->x;
1714                  iMinSAD = iSAD;                  Data->currentQMV->y = 2*Data->currentMV->y;
1715                    Data->qpel_precision = 1;
1716                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1717                                            pParam->width, pParam->height, iFcode, 1, 0);
1718                    SubpelRefine(Data);
1719          }          }
1720    
1721          if (MotionFlags & PMV_EXTSEARCH8) {          /* three bits are needed to code backward mode. four for forward */
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
1722    
1723                  if (!(MVequal(pmv[0], backupMV))) {          if (mode_current == MODE_FORWARD) *Data->iMinSAD += 4 * Data->lambda16;
1724                          iSAD =          else *Data->iMinSAD += 3 * Data->lambda16;
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
1725    
1726                          if (iSAD < iMinSAD) {          if (*Data->iMinSAD < *best_sad) {
1727                                  *currMV = newMV;                  *best_sad = *Data->iMinSAD;
1728                                  iMinSAD = iSAD;                  pMB->mode = mode_current;
1729                    if (Data->qpel) {
1730                            pMB->pmvs[0].x = Data->currentQMV->x - predMV->x;
1731                            pMB->pmvs[0].y = Data->currentQMV->y - predMV->y;
1732                            if (mode_current == MODE_FORWARD)
1733                                    pMB->qmvs[0] = *Data->currentQMV;
1734                            else
1735                                    pMB->b_qmvs[0] = *Data->currentQMV;
1736                    } else {
1737                            pMB->pmvs[0].x = Data->currentMV->x - predMV->x;
1738                            pMB->pmvs[0].y = Data->currentMV->y - predMV->y;
1739                          }                          }
1740                    if (mode_current == MODE_FORWARD) pMB->mvs[0] = *Data->currentMV;
1741                    else pMB->b_mvs[0] = *Data->currentMV;
1742                  }                  }
1743    
1744                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          if (mode_current == MODE_FORWARD) *(Data->currentMV+2) = *Data->currentMV;
1745                          iSAD =          else *(Data->currentMV+1) = *Data->currentMV; /* we store currmv for interpolate search */
1746                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  }
1747                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  
1748                                                                    max_dy, iEdgedWidth, iDiamondSize, iFcode,  static void
1749                                                                    iQuant, iFound);  SkipDecisionB(const IMAGE * const pCur,
1750                                    const IMAGE * const f_Ref,
1751                                    const IMAGE * const b_Ref,
1752                                    MACROBLOCK * const pMB,
1753                                    const uint32_t x, const uint32_t y,
1754                                    const SearchData * const Data)
1755    {
1756            int dx = 0, dy = 0, b_dx = 0, b_dy = 0;
1757            int32_t sum;
1758            const int div = 1 + Data->qpel;
1759            int k;
1760            const uint32_t stride = Data->iEdgedWidth/2;
1761            /* this is not full chroma compensation, only it's fullpel approximation. should work though */
1762    
1763            for (k = 0; k < 4; k++) {
1764                    dy += Data->directmvF[k].y / div;
1765                    dx += Data->directmvF[k].x / div;
1766                    b_dy += Data->directmvB[k].y / div;
1767                    b_dx += Data->directmvB[k].x / div;
1768            }
1769    
1770            dy = (dy >> 3) + roundtab_76[dy & 0xf];
1771            dx = (dx >> 3) + roundtab_76[dx & 0xf];
1772            b_dy = (b_dy >> 3) + roundtab_76[b_dy & 0xf];
1773            b_dx = (b_dx >> 3) + roundtab_76[b_dx & 0xf];
1774    
1775            sum = sad8bi(pCur->u + 8 * x + 8 * y * stride,
1776                                            f_Ref->u + (y*8 + dy/2) * stride + x*8 + dx/2,
1777                                            b_Ref->u + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1778                                            stride);
1779    
1780            if (sum >= 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) return; /* no skip */
1781    
1782            sum += sad8bi(pCur->v + 8*x + 8 * y * stride,
1783                                            f_Ref->v + (y*8 + dy/2) * stride + x*8 + dx/2,
1784                                            b_Ref->v + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1785                                            stride);
1786    
1787                          if (iSAD < iMinSAD) {          if (sum < 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) {
1788                                  *currMV = newMV;                  pMB->mode = MODE_DIRECT_NONE_MV; /* skipped */
1789                                  iMinSAD = iSAD;                  for (k = 0; k < 4; k++) {
1790                            pMB->qmvs[k] = pMB->mvs[k];
1791                            pMB->b_qmvs[k] = pMB->b_mvs[k];
1792                          }                          }
1793                  }                  }
1794          }          }
1795    
1796  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.  static __inline uint32_t
1797     By performing an optional local half-pixel search, we can refine this result even further.  SearchDirect(const IMAGE * const f_Ref,
1798  */                                  const uint8_t * const f_RefH,
1799                                    const uint8_t * const f_RefV,
1800                                    const uint8_t * const f_RefHV,
1801                                    const IMAGE * const b_Ref,
1802                                    const uint8_t * const b_RefH,
1803                                    const uint8_t * const b_RefV,
1804                                    const uint8_t * const b_RefHV,
1805                                    const IMAGE * const pCur,
1806                                    const int x, const int y,
1807                                    const uint32_t MotionFlags,
1808                                    const int32_t TRB, const int32_t TRD,
1809                                    const MBParam * const pParam,
1810                                    MACROBLOCK * const pMB,
1811                                    const MACROBLOCK * const b_mb,
1812                                    int32_t * const best_sad,
1813                                    SearchData * const Data)
1814    
1815    {
1816            int32_t skip_sad;
1817            int k = (x + Data->iEdgedWidth*y) * 16;
1818            MainSearchFunc *MainSearchPtr;
1819    
1820            *Data->iMinSAD = 256*4096;
1821            Data->RefP[0] = f_Ref->y + k;
1822            Data->RefP[2] = f_RefH + k;
1823            Data->RefP[1] = f_RefV + k;
1824            Data->RefP[3] = f_RefHV + k;
1825            Data->b_RefP[0] = b_Ref->y + k;
1826            Data->b_RefP[2] = b_RefH + k;
1827            Data->b_RefP[1] = b_RefV + k;
1828            Data->b_RefP[3] = b_RefHV + k;
1829            Data->RefP[4] = f_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1830            Data->RefP[5] = f_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1831            Data->b_RefP[4] = b_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1832            Data->b_RefP[5] = b_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1833    
1834            k = Data->qpel ? 4 : 2;
1835            Data->max_dx = k * (pParam->width - x * 16);
1836            Data->max_dy = k * (pParam->height - y * 16);
1837            Data->min_dx = -k * (16 + x * 16);
1838            Data->min_dy = -k * (16 + y * 16);
1839    
1840    PMVfast8_Terminate_with_Refine:          Data->referencemv = Data->qpel ? b_mb->qmvs : b_mb->mvs;
1841          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step          Data->qpel_precision = 0;
                 iMinSAD =  
                         Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                         iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                         iFcode, iQuant, iEdgedWidth);  
1842    
1843            for (k = 0; k < 4; k++) {
1844                    pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);
1845                    pMB->b_mvs[k].x = Data->directmvB[k].x = ((TRB - TRD) * Data->referencemv[k].x) / TRD;
1846                    pMB->mvs[k].y = Data->directmvF[k].y = ((TRB * Data->referencemv[k].y) / TRD);
1847                    pMB->b_mvs[k].y = Data->directmvB[k].y = ((TRB - TRD) * Data->referencemv[k].y) / TRD;
1848    
1849    PMVfast8_Terminate_without_Refine:                  if ( (pMB->b_mvs[k].x > Data->max_dx) | (pMB->b_mvs[k].x < Data->min_dx)
1850          currPMV->x = currMV->x - center_x;                          | (pMB->b_mvs[k].y > Data->max_dy) | (pMB->b_mvs[k].y < Data->min_dy) ) {
         currPMV->y = currMV->y - center_y;  
1851    
1852          return iMinSAD;                          *best_sad = 256*4096; /* in that case, we won't use direct mode */
1853                            pMB->mode = MODE_DIRECT; /* just to make sure it doesn't say "MODE_DIRECT_NONE_MV" */
1854                            pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;
1855                            return 256*4096;
1856                    }
1857                    if (b_mb->mode != MODE_INTER4V) {
1858                            pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mvs[0];
1859                            pMB->b_mvs[1] = pMB->b_mvs[2] = pMB->b_mvs[3] = pMB->b_mvs[0];
1860                            Data->directmvF[1] = Data->directmvF[2] = Data->directmvF[3] = Data->directmvF[0];
1861                            Data->directmvB[1] = Data->directmvB[2] = Data->directmvB[3] = Data->directmvB[0];
1862                            break;
1863                    }
1864  }  }
1865    
1866  int32_t          CheckCandidate = b_mb->mode == MODE_INTER4V ? CheckCandidateDirect : CheckCandidateDirectno4v;
 EPZSSearch16(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,  
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
                          const uint32_t MotionFlags,  
                          const uint32_t iQuant,  
                          const uint32_t iFcode,  
                          const MBParam * const pParam,  
                          const MACROBLOCK * const pMBs,  
                          const MACROBLOCK * const prevMBs,  
                          VECTOR * const currMV,  
                          VECTOR * const currPMV)  
 {  
         const uint32_t iWcount = pParam->mb_width;  
         const uint32_t iHcount = pParam->mb_height;  
   
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
1867    
1868          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          CheckCandidate(0, 0, 255, &k, Data);
1869    
1870          int32_t min_dx;          /* initial (fast) skip decision */
1871          int32_t max_dx;          if (*Data->iMinSAD < pMB->quant * INITIAL_SKIP_THRESH * (Data->chroma?3:2)) {
1872          int32_t min_dy;                  /* possible skip */
1873          int32_t max_dy;                  if (Data->chroma) {
1874                            pMB->mode = MODE_DIRECT_NONE_MV;
1875                            return *Data->iMinSAD; /* skip. */
1876                    } else {
1877                            SkipDecisionB(pCur, f_Ref, b_Ref, pMB, x, y, Data);
1878                            if (pMB->mode == MODE_DIRECT_NONE_MV) return *Data->iMinSAD; /* skip. */
1879                    }
1880            }
1881    
1882          VECTOR newMV;          *Data->iMinSAD += Data->lambda16;
1883          VECTOR backupMV;          skip_sad = *Data->iMinSAD;
1884    
1885          VECTOR pmv[4];          /*
1886          int32_t psad[8];           * DIRECT MODE DELTA VECTOR SEARCH.
1887             * This has to be made more effective, but at the moment I'm happy it's running at all
1888             */
1889    
1890          static MACROBLOCK *oldMBs = NULL;          if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1891                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1892                            else MainSearchPtr = DiamondSearch;
1893    
1894  //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;          MainSearchPtr(0, 0, Data, 255);
         const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;  
         MACROBLOCK *oldMB = NULL;  
1895    
1896           int32_t thresh2;          SubpelRefine(Data);
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD = 9999;  
1897    
1898          MainSearch16FuncPtr MainSearchPtr;          *best_sad = *Data->iMinSAD;
1899    
1900          if (oldMBs == NULL) {          if (Data->qpel || b_mb->mode == MODE_INTER4V) pMB->mode = MODE_DIRECT;
1901                  oldMBs = (MACROBLOCK *) calloc(iWcount * iHcount, sizeof(MACROBLOCK));          else pMB->mode = MODE_DIRECT_NO4V; /* for faster compensation */
 //      fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));  
         }  
         oldMB = oldMBs + x + y * iWcount;  
1902    
1903  /* Get maximum range */          pMB->pmvs[3] = *Data->currentMV;
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
1904    
1905          if (!(MotionFlags & PMV_HALFPEL16)) {          for (k = 0; k < 4; k++) {
1906                  min_dx = EVEN(min_dx);                  pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
1907                  max_dx = EVEN(max_dx);                  pMB->b_mvs[k].x = (     (Data->currentMV->x == 0)
1908                  min_dy = EVEN(min_dy);                                                          ? Data->directmvB[k].x
1909                  max_dy = EVEN(max_dy);                                                          :pMB->mvs[k].x - Data->referencemv[k].x);
1910                    pMB->mvs[k].y = (Data->directmvF[k].y + Data->currentMV->y);
1911                    pMB->b_mvs[k].y = ((Data->currentMV->y == 0)
1912                                                            ? Data->directmvB[k].y
1913                                                            : pMB->mvs[k].y - Data->referencemv[k].y);
1914                    if (Data->qpel) {
1915                            pMB->qmvs[k].x = pMB->mvs[k].x; pMB->mvs[k].x /= 2;
1916                            pMB->b_qmvs[k].x = pMB->b_mvs[k].x; pMB->b_mvs[k].x /= 2;
1917                            pMB->qmvs[k].y = pMB->mvs[k].y; pMB->mvs[k].y /= 2;
1918                            pMB->b_qmvs[k].y = pMB->b_mvs[k].y; pMB->b_mvs[k].y /= 2;
1919                    }
1920    
1921                    if (b_mb->mode != MODE_INTER4V) {
1922                            pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1923                            pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1924                            pMB->qmvs[3] = pMB->qmvs[2] = pMB->qmvs[1] = pMB->qmvs[0];
1925                            pMB->b_qmvs[3] = pMB->b_qmvs[2] = pMB->b_qmvs[1] = pMB->b_qmvs[0];
1926                            break;
1927                    }
1928          }          }
1929          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */          return skip_sad;
1930          //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  }
1931          bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);  
1932    static void
1933    SearchInterpolate(const IMAGE * const f_Ref,
1934                                    const uint8_t * const f_RefH,
1935                                    const uint8_t * const f_RefV,
1936                                    const uint8_t * const f_RefHV,
1937                                    const IMAGE * const b_Ref,
1938                                    const uint8_t * const b_RefH,
1939                                    const uint8_t * const b_RefV,
1940                                    const uint8_t * const b_RefHV,
1941                                    const IMAGE * const pCur,
1942                                    const int x, const int y,
1943                                    const uint32_t fcode,
1944                                    const uint32_t bcode,
1945                                    const uint32_t MotionFlags,
1946                                    const MBParam * const pParam,
1947                                    const VECTOR * const f_predMV,
1948                                    const VECTOR * const b_predMV,
1949                                    MACROBLOCK * const pMB,
1950                                    int32_t * const best_sad,
1951                                    SearchData * const fData)
1952    
1953  /* 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.  
 */  
1954    
1955  // Prepare for main loop          int iDirection, i, j;
1956            SearchData bData;
1957    
1958            fData->qpel_precision = 0;
1959            memcpy(&bData, fData, sizeof(SearchData)); /* quick copy of common data */
1960            *fData->iMinSAD = 4096*256;
1961            bData.currentMV++; bData.currentQMV++;
1962            fData->iFcode = bData.bFcode = fcode; fData->bFcode = bData.iFcode = bcode;
1963    
1964            i = (x + y * fData->iEdgedWidth) * 16;
1965    
1966            bData.b_RefP[0] = fData->RefP[0] = f_Ref->y + i;
1967            bData.b_RefP[2] = fData->RefP[2] = f_RefH + i;
1968            bData.b_RefP[1] = fData->RefP[1] = f_RefV + i;
1969            bData.b_RefP[3] = fData->RefP[3] = f_RefHV + i;
1970            bData.RefP[0] = fData->b_RefP[0] = b_Ref->y + i;
1971            bData.RefP[2] = fData->b_RefP[2] = b_RefH + i;
1972            bData.RefP[1] = fData->b_RefP[1] = b_RefV + i;
1973            bData.RefP[3] = fData->b_RefP[3] = b_RefHV + i;
1974            bData.b_RefP[4] = fData->RefP[4] = f_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
1975            bData.b_RefP[5] = fData->RefP[5] = f_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
1976            bData.RefP[4] = fData->b_RefP[4] = b_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
1977            bData.RefP[5] = fData->b_RefP[5] = b_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
1978    
1979            bData.bpredMV = fData->predMV = *f_predMV;
1980            fData->bpredMV = bData.predMV = *b_predMV;
1981            fData->currentMV[0] = fData->currentMV[2];
1982    
1983            get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode - fData->qpel, 0, 0);
1984            get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode - fData->qpel, 0, 0);
1985    
1986            if (fData->currentMV[0].x > fData->max_dx) fData->currentMV[0].x = fData->max_dx;
1987            if (fData->currentMV[0].x < fData->min_dx) fData->currentMV[0].x = fData->min_dx;
1988            if (fData->currentMV[0].y > fData->max_dy) fData->currentMV[0].y = fData->max_dy;
1989            if (fData->currentMV[0].y < fData->min_dy) fData->currentMV[0].y = fData->min_dy;
1990    
1991            if (fData->currentMV[1].x > bData.max_dx) fData->currentMV[1].x = bData.max_dx;
1992            if (fData->currentMV[1].x < bData.min_dx) fData->currentMV[1].x = bData.min_dx;
1993            if (fData->currentMV[1].y > bData.max_dy) fData->currentMV[1].y = bData.max_dy;
1994            if (fData->currentMV[1].y < bData.min_dy) fData->currentMV[1].y = bData.min_dy;
1995    
1996          currMV->x = start_x;          CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, 255, &iDirection, fData);
1997          currMV->y = start_y;  
1998            /* diamond */
1999            do {
2000                    iDirection = 255;
2001                    /* forward MV moves */
2002                    i = fData->currentMV[0].x; j = fData->currentMV[0].y;
2003    
2004                    CheckCandidateInt(i + 1, j, 0, &iDirection, fData);
2005                    CheckCandidateInt(i, j + 1, 0, &iDirection, fData);
2006                    CheckCandidateInt(i - 1, j, 0, &iDirection, fData);
2007                    CheckCandidateInt(i, j - 1, 0, &iDirection, fData);
2008    
2009                    /* backward MV moves */
2010                    i = fData->currentMV[1].x; j = fData->currentMV[1].y;
2011                    fData->currentMV[2] = fData->currentMV[0];
2012                    CheckCandidateInt(i + 1, j, 0, &iDirection, &bData);
2013                    CheckCandidateInt(i, j + 1, 0, &iDirection, &bData);
2014                    CheckCandidateInt(i - 1, j, 0, &iDirection, &bData);
2015                    CheckCandidateInt(i, j - 1, 0, &iDirection, &bData);
2016    
2017            } while (!(iDirection));
2018    
2019            /* qpel refinement */
2020            if (fData->qpel) {
2021                    if (*fData->iMinSAD > *best_sad + 500) return;
2022                    CheckCandidate = CheckCandidateInt;
2023                    fData->qpel_precision = bData.qpel_precision = 1;
2024                    get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode, 1, 0);
2025                    get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode, 1, 0);
2026                    fData->currentQMV[2].x = fData->currentQMV[0].x = 2 * fData->currentMV[0].x;
2027                    fData->currentQMV[2].y = fData->currentQMV[0].y = 2 * fData->currentMV[0].y;
2028                    fData->currentQMV[1].x = 2 * fData->currentMV[1].x;
2029                    fData->currentQMV[1].y = 2 * fData->currentMV[1].y;
2030                    SubpelRefine(fData);
2031                    if (*fData->iMinSAD > *best_sad + 300) return;
2032                    fData->currentQMV[2] = fData->currentQMV[0];
2033                    SubpelRefine(&bData);
2034            }
2035    
2036            *fData->iMinSAD += (2+3) * fData->lambda16; /* two bits are needed to code interpolate mode. */
2037    
2038            if (*fData->iMinSAD < *best_sad) {
2039                    *best_sad = *fData->iMinSAD;
2040                    pMB->mvs[0] = fData->currentMV[0];
2041                    pMB->b_mvs[0] = fData->currentMV[1];
2042                    pMB->mode = MODE_INTERPOLATE;
2043                    if (fData->qpel) {
2044                            pMB->qmvs[0] = fData->currentQMV[0];
2045                            pMB->b_qmvs[0] = fData->currentQMV[1];
2046                            pMB->pmvs[1].x = pMB->qmvs[0].x - f_predMV->x;
2047                            pMB->pmvs[1].y = pMB->qmvs[0].y - f_predMV->y;
2048                            pMB->pmvs[0].x = pMB->b_qmvs[0].x - b_predMV->x;
2049                            pMB->pmvs[0].y = pMB->b_qmvs[0].y - b_predMV->y;
2050                    } else {
2051                            pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;
2052                            pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;
2053                            pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;
2054                            pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;
2055                    }
2056            }
2057    }
2058    
2059          if (!(MotionFlags & PMV_HALFPEL16)) {  void
2060                  currMV->x = EVEN(currMV->x);  MotionEstimationBVOP(MBParam * const pParam,
2061                  currMV->y = EVEN(currMV->y);                                           FRAMEINFO * const frame,
2062          }                                           const int32_t time_bp,
2063                                             const int32_t time_pp,
2064          if (currMV->x > max_dx)                                           /* forward (past) reference */
2065                  currMV->x = max_dx;                                           const MACROBLOCK * const f_mbs,
2066          if (currMV->x < min_dx)                                           const IMAGE * const f_ref,
2067                  currMV->x = min_dx;                                           const IMAGE * const f_refH,
2068          if (currMV->y > max_dy)                                           const IMAGE * const f_refV,
2069                  currMV->y = max_dy;                                           const IMAGE * const f_refHV,
2070          if (currMV->y < min_dy)                                           /* backward (future) reference */
2071                  currMV->y = min_dy;                                           const FRAMEINFO * const b_reference,
2072                                             const IMAGE * const b_ref,
2073  /***************** This is predictor SET A: only median prediction ******************/                                           const IMAGE * const b_refH,
2074                                             const IMAGE * const b_refV,
2075          iMinSAD =                                           const IMAGE * const b_refHV)
2076                  sad16(cur,  {
2077                            get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,          uint32_t i, j;
2078                                                   iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);          int32_t best_sad;
2079          iMinSAD +=          uint32_t skip_sad;
2080                  calc_delta_16(currMV->x - center_x, currMV->y - center_y,          int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;
2081                                            (uint8_t) iFcode, iQuant);          const MACROBLOCK * const b_mbs = b_reference->mbs;
   
 // thresh1 is fixed to 256  
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
         }  
   
 /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/  
2082    
2083  // previous frame MV          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
         CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);  
2084    
2085  // set threshhold based on Min of Prediction and SAD of collocated block          const int32_t TRB = time_pp - time_bp;
2086  // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want          const int32_t TRD = time_pp;
2087    
2088          if ((x == 0) && (y == 0)) {          /* some pre-inintialized data for the rest of the search */
                 thresh2 = 512;  
         } else {  
 /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */  
2089    
2090                  thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;          SearchData Data;
2091            int32_t iMinSAD;
2092            VECTOR currentMV[3];
2093            VECTOR currentQMV[3];
2094            int32_t temp[8];
2095            memset(&Data, 0, sizeof(SearchData));
2096            Data.iEdgedWidth = pParam->edged_width;
2097            Data.currentMV = currentMV; Data.currentQMV = currentQMV;
2098            Data.iMinSAD = &iMinSAD;
2099            Data.lambda16 = lambda_vec16[frame->quant];
2100            Data.qpel = pParam->vol_flags & XVID_VOL_QUARTERPEL;
2101            Data.rounding = 0;
2102            Data.chroma = frame->motion_flags & XVID_ME_CHROMA8;
2103            Data.temp = temp;
2104    
2105            Data.RefQ = f_refV->u; /* a good place, also used in MC (for similar purpose) */
2106    
2107            /* note: i==horizontal, j==vertical */
2108            for (j = 0; j < pParam->mb_height; j++) {
2109    
2110                    f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
2111    
2112                    for (i = 0; i < pParam->mb_width; i++) {
2113                            MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
2114                            const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
2115    
2116    /* special case, if collocated block is SKIPed in P-VOP: encoding is forward (0,0), cpb=0 without further ado */
2117                            if (b_reference->coding_type != S_VOP)
2118                                    if (b_mb->mode == MODE_NOT_CODED) {
2119                                            pMB->mode = MODE_NOT_CODED;
2120                                            continue;
2121          }          }
2122    
2123  // MV=(0,0) is often a good choice                          Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
2124                            Data.CurU = frame->image.u + (j * Data.iEdgedWidth/2 + i) * 8;
2125                            Data.CurV = frame->image.v + (j * Data.iEdgedWidth/2 + i) * 8;
2126                            pMB->quant = frame->quant;
2127    
2128    /* direct search comes first, because it (1) checks for SKIP-mode
2129            and (2) sets very good predictions for forward and backward search */
2130                            skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2131                                                                            b_ref, b_refH->y, b_refV->y, b_refHV->y,
2132                                                                            &frame->image,
2133                                                                            i, j,
2134                                                                            frame->motion_flags,
2135                                                                            TRB, TRD,
2136                                                                            pParam,
2137                                                                            pMB, b_mb,
2138                                                                            &best_sad,
2139                                                                            &Data);
2140    
2141          CHECK_MV16_ZERO;                          if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
2142    
2143                            /* forward search */
2144                            SearchBF(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2145                                                    &frame->image, i, j,
2146                                                    frame->motion_flags,
2147                                                    frame->fcode, pParam,
2148                                                    pMB, &f_predMV, &best_sad,
2149                                                    MODE_FORWARD, &Data);
2150    
2151  // left neighbour, if allowed                          /* backward search */
2152          if (x != 0) {                          SearchBF(b_ref, b_refH->y, b_refV->y, b_refHV->y,
2153                  if (!(MotionFlags & PMV_HALFPEL16)) {                                                  &frame->image, i, j,
2154                          pmv[1].x = EVEN(pmv[1].x);                                                  frame->motion_flags,
2155                          pmv[1].y = EVEN(pmv[1].y);                                                  frame->bcode, pParam,
2156                  }                                                  pMB, &b_predMV, &best_sad,
2157                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);                                                  MODE_BACKWARD, &Data);
2158          }  
2159  // top neighbour, if allowed                          /* interpolate search comes last, because it uses data from forward and backward as prediction */
2160          if (y != 0) {                          SearchInterpolate(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2161                  if (!(MotionFlags & PMV_HALFPEL16)) {                                                  b_ref, b_refH->y, b_refV->y, b_refHV->y,
2162                          pmv[2].x = EVEN(pmv[2].x);                                                  &frame->image,
2163                          pmv[2].y = EVEN(pmv[2].y);                                                  i, j,
2164                  }                                                  frame->fcode, frame->bcode,
2165                  CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);                                                  frame->motion_flags,
2166                                                    pParam,
2167                                                    &f_predMV, &b_predMV,
2168                                                    pMB, &best_sad,
2169                                                    &Data);
2170    
2171                            /* final skip decision */
2172                            if ( (skip_sad < frame->quant * MAX_SAD00_FOR_SKIP * 2)
2173                                            && ((100*best_sad)/(skip_sad+1) > FINAL_SKIP_THRESH) )
2174                                    SkipDecisionB(&frame->image, f_ref, b_ref, pMB, i, j, &Data);
2175    
2176  // top right neighbour, if allowed                          switch (pMB->mode) {
2177                  if ((uint32_t) x != (iWcount - 1)) {                                  case MODE_FORWARD:
2178                          if (!(MotionFlags & PMV_HALFPEL16)) {                                          f_count++;
2179                                  pmv[3].x = EVEN(pmv[3].x);                                          f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2180                                  pmv[3].y = EVEN(pmv[3].y);                                          break;
2181                                    case MODE_BACKWARD:
2182                                            b_count++;
2183                                            b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2184                                            break;
2185                                    case MODE_INTERPOLATE:
2186                                            i_count++;
2187                                            f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2188                                            b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2189                                            break;
2190                                    case MODE_DIRECT:
2191                                    case MODE_DIRECT_NO4V:
2192                                            d_count++;
2193                                    default:
2194                                            break;
2195                            }
2196                          }                          }
                         CHECK_MV16_CANDIDATE(pmv[3].x, pmv[3].y);  
2197                  }                  }
2198          }          }
2199    
2200  /* Terminate if MinSAD <= T_2  static __inline void
2201     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  MEanalyzeMB (   const uint8_t * const pRef,
2202  */                                  const uint8_t * const pCur,
2203                                    const int x,
2204                                    const int y,
2205                                    const MBParam * const pParam,
2206                                    MACROBLOCK * const pMBs,
2207                                    SearchData * const Data)
2208    {
2209    
2210          if ((iMinSAD <= thresh2)          int i, mask;
2211                  || (MVequal(*currMV, prevMB->mvs[0]) &&          int quarterpel = (pParam->vol_flags & XVID_VOL_QUARTERPEL)? 1: 0;
2212                          ((int32_t) iMinSAD <= prevMB->sad16))) {          VECTOR pmv[3];
2213                  if (MotionFlags & PMV_QUICKSTOP16)          MACROBLOCK * const pMB = &pMBs[x + y * pParam->mb_width];
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
         }  
2214    
2215  /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/          for (i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;
2216    
2217          backupMV = prevMB->mvs[0];      // collocated MV          /* median is only used as prediction. it doesn't have to be real */
2218          backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x);     // acceleration X          if (x == 1 && y == 1) Data->predMV.x = Data->predMV.y = 0;
2219          backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y);     // acceleration Y          else
2220                    if (x == 1) /* left macroblock does not have any vector now */
2221                            Data->predMV = (pMB - pParam->mb_width)->mvs[0]; /* top instead of median */
2222                    else if (y == 1) /* top macroblock doesn't have it's vector */
2223                            Data->predMV = (pMB - 1)->mvs[0]; /* left instead of median */
2224                            else Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); /* else median */
2225    
2226          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y);          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2227                            pParam->width, pParam->height, Data->iFcode - quarterpel, 0, 0);
2228    
2229  // left neighbour          Data->Cur = pCur + (x + y * pParam->edged_width) * 16;
2230          if (x != 0)          Data->RefP[0] = pRef + (x + y * pParam->edged_width) * 16;
                 CHECK_MV16_CANDIDATE((prevMB - 1)->mvs[0].x, (prevMB - 1)->mvs[0].y);  
2231    
2232  // top neighbour          pmv[1].x = EVEN(pMB->mvs[0].x);
2233          if (y != 0)          pmv[1].y = EVEN(pMB->mvs[0].y);
2234                  CHECK_MV16_CANDIDATE((prevMB - iWcount)->mvs[0].x,          pmv[2].x = EVEN(Data->predMV.x);
2235                                                           (prevMB - iWcount)->mvs[0].y);          pmv[2].y = EVEN(Data->predMV.y);
2236            pmv[0].x = pmv[0].y = 0;
2237    
2238  // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs          CheckCandidate32I(0, 0, 255, &i, Data);
2239    
2240          if ((uint32_t) x != iWcount - 1)          if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP) {
                 CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);  
2241    
2242  // bottom neighbour, dito                  if (!(mask = make_mask(pmv, 1)))
2243          if ((uint32_t) y != iHcount - 1)                          CheckCandidate32I(pmv[1].x, pmv[1].y, mask, &i, Data);
2244                  CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,                  if (!(mask = make_mask(pmv, 2)))
2245                                                           (prevMB + iWcount)->mvs[0].y);                          CheckCandidate32I(pmv[2].x, pmv[2].y, mask, &i, Data);
2246    
2247  /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */                  if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP) /* diamond only if needed */
2248          if (iMinSAD <= thresh2) {                          DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, i);
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
2249          }          }
2250    
2251  /************ (if Diamond Search)  **************/          for (i = 0; i < 4; i++) {
2252                    MACROBLOCK * MB = &pMBs[x + (i&1) + (y+(i>>1)) * pParam->mb_width];
2253                    MB->mvs[0] = MB->mvs[1] = MB->mvs[2] = MB->mvs[3] = Data->currentMV[i];
2254                    MB->mode = MODE_INTER;
2255                    MB->sad16 = Data->iMinSAD[i+1];
2256            }
2257    }
2258    
2259          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  #define INTRA_THRESH    2200
2260    #define INTER_THRESH    50
2261    #define INTRA_THRESH2   95
2262    
2263          if (MotionFlags & PMV_USESQUARES16)  int
2264                  MainSearchPtr = Square16_MainSearch;  MEanalysis(     const IMAGE * const pRef,
2265          else                          const FRAMEINFO * const Current,
2266           if (MotionFlags & PMV_ADVANCEDDIAMOND16)                          const MBParam * const pParam,
2267                  MainSearchPtr = AdvDiamond16_MainSearch;                          const int maxIntra, //maximum number if non-I frames
2268                            const int intraCount, //number of non-I frames after last I frame; 0 if we force P/B frame
2269                            const int bCount, // number of B frames in a row
2270                            const int b_thresh)
2271    {
2272            uint32_t x, y, intra = 0;
2273            int sSAD = 0;
2274            MACROBLOCK * const pMBs = Current->mbs;
2275            const IMAGE * const pCurrent = &Current->image;
2276            int IntraThresh = INTRA_THRESH, InterThresh = INTER_THRESH + b_thresh;
2277            int blocks = 0;
2278            int complexity = 0;
2279    
2280            int32_t iMinSAD[5], temp[5];
2281            VECTOR currentMV[5];
2282            SearchData Data;
2283            Data.iEdgedWidth = pParam->edged_width;
2284            Data.currentMV = currentMV;
2285            Data.iMinSAD = iMinSAD;
2286            Data.iFcode = Current->fcode;
2287            Data.temp = temp;
2288            CheckCandidate = CheckCandidate32I;
2289    
2290            if (intraCount != 0) {
2291                    if (intraCount < 10) // we're right after an I frame
2292                            IntraThresh += 15* (intraCount - 10) * (intraCount - 10);
2293          else          else
2294                  MainSearchPtr = Diamond16_MainSearch;                          if ( 5*(maxIntra - intraCount) < maxIntra) // we're close to maximum. 2 sec when max is 10 sec
2295                                    IntraThresh -= (IntraThresh * (maxIntra - 8*(maxIntra - intraCount)))/maxIntra;
2296            }
2297    
2298  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          InterThresh -= 12 * bCount;
2299            if (InterThresh < 15 + b_thresh) InterThresh = 15 + b_thresh;
2300    
2301          iSAD =          if (sadInit) (*sadInit) ();
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  
                                                   currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);  
2302    
2303          if (iSAD < iMinSAD) {          for (y = 1; y < pParam->mb_height-1; y += 2) {
2304                  *currMV = newMV;                  for (x = 1; x < pParam->mb_width-1; x += 2) {
2305                  iMinSAD = iSAD;                          int i;
2306          }                          blocks += 10;
2307    
2308                            if (bCount == 0) pMBs[x + y * pParam->mb_width].mvs[0] = zeroMV;
2309                            else { //extrapolation of the vector found for last frame
2310                                    pMBs[x + y * pParam->mb_width].mvs[0].x =
2311                                            (pMBs[x + y * pParam->mb_width].mvs[0].x * (bCount+1) ) / bCount;
2312                                    pMBs[x + y * pParam->mb_width].mvs[0].y =
2313                                            (pMBs[x + y * pParam->mb_width].mvs[0].y * (bCount+1) ) / bCount;
2314                            }
2315    
2316          if (MotionFlags & PMV_EXTSEARCH16) {                          MEanalyzeMB(pRef->y, pCurrent->y, x, y, pParam, pMBs, &Data);
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
2317    
2318                  if (!(MVequal(pmv[0], backupMV))) {                          for (i = 0; i < 4; i++) {
2319                          iSAD =                                  int dev;
2320                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                  MACROBLOCK *pMB = &pMBs[x+(i&1) + (y+(i>>1)) * pParam->mb_width];
2321                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,                                  dev = dev16(pCurrent->y + (x + (i&1) + (y + (i>>1)) * pParam->edged_width) * 16,
2322                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,                                                                  pParam->edged_width);
                                                                   2, iFcode, iQuant, 0);  
                 }  
2323    
2324                  if (iSAD < iMinSAD) {                                  complexity += dev;
2325                          *currMV = newMV;                                  if (dev + IntraThresh < pMB->sad16) {
2326                          iMinSAD = iSAD;                                          pMB->mode = MODE_INTRA;
2327                                            if (++intra > ((pParam->mb_height-2)*(pParam->mb_width-2))/2) return I_VOP;
2328                  }                  }
2329    
2330                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                                  if (pMB->mvs[0].x == 0 && pMB->mvs[0].y == 0)
2331                          iSAD =                                          if (dev > 500 && pMB->sad16 < 1000)
2332                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                                                  sSAD += 1000;
                                                                   iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);  
2333    
2334                          if (iSAD < iMinSAD) {                                  sSAD += pMB->sad16;
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
2335                          }                          }
2336                  }                  }
2337          }          }
2338            complexity >>= 7;
2339    
2340  /***************        Choose best MV found     **************/          sSAD /= complexity + 4*blocks;
   
   EPZS16_Terminate_with_Refine:  
         if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step  
                 iMinSAD =  
                         Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
   
   EPZS16_Terminate_without_Refine:  
   
         *oldMB = *prevMB;  
2341    
2342          currPMV->x = currMV->x - center_x;          if (intraCount > 12 && sSAD > INTRA_THRESH2 ) return I_VOP;
2343          currPMV->y = currMV->y - center_y;          if (sSAD > InterThresh ) return P_VOP;
2344          return iMinSAD;          emms();
2345            return B_VOP;
2346  }  }
2347    
2348    
2349  int32_t  /* functions which perform BITS-based search/bitcount */
2350  EPZSSearch8(const uint8_t * const pRef,  
2351                          const uint8_t * const pRefH,  static int
2352                          const uint8_t * const pRefV,  CountMBBitsInter(SearchData * const Data,
2353                          const uint8_t * const pRefHV,                                  const MACROBLOCK * const pMBs, const int x, const int y,
                         const IMAGE * const pCur,  
                         const int x,  
                         const int y,  
                         const int start_x,  
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
                         const uint32_t MotionFlags,  
                         const uint32_t iQuant,  
                         const uint32_t iFcode,  
2354                          const MBParam * const pParam,                          const MBParam * const pParam,
2355                          const MACROBLOCK * const pMBs,                                  const uint32_t MotionFlags)
                         const MACROBLOCK * const prevMBs,  
                         VECTOR * const currMV,  
                         VECTOR * const currPMV)  
2356  {  {
2357  /* Please not that EPZS might not be a good choice for 8x8-block motion search ! */          int i, iDirection;
2358            int32_t bsad[5];
         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;  
2359    
2360          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;          CheckCandidate = CheckCandidateBits16;
2361    
2362          int32_t iDiamondSize = 1;          if (Data->qpel) {
2363                    for(i = 0; i < 5; i++) {
2364          int32_t min_dx;                          Data->currentMV[i].x = Data->currentQMV[i].x/2;
2365          int32_t max_dx;                          Data->currentMV[i].y = Data->currentQMV[i].y/2;
2366          int32_t min_dy;                  }
2367          int32_t max_dy;                  Data->qpel_precision = 1;
2368                    CheckCandidateBits16(Data->currentQMV[0].x, Data->currentQMV[0].y, 255, &iDirection, Data);
         VECTOR newMV;  
         VECTOR backupMV;  
2369    
2370          VECTOR pmv[4];                  if (MotionFlags & (XVID_ME_HALFPELREFINE16_BITS | XVID_ME_EXTSEARCH_BITS)) { /* we have to prepare for halfpixel-precision search */
2371          int32_t psad[8];                          for(i = 0; i < 5; i++) bsad[i] = Data->iMinSAD[i];
2372                            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2373                                                    pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
2374                            Data->qpel_precision = 0;
2375                            if (Data->currentQMV->x & 1 || Data->currentQMV->y & 1)
2376                                    CheckCandidateBits16(Data->currentMV[0].x, Data->currentMV[0].y, 255, &iDirection, Data);
2377                    }
2378    
2379          const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);          } else { /* not qpel */
2380    
2381  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;                  CheckCandidateBits16(Data->currentMV[0].x, Data->currentMV[0].y, 255, &iDirection, Data);
2382          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;          }
2383    
2384          int32_t bPredEq;          if (MotionFlags&XVID_ME_EXTSEARCH_BITS) SquareSearch(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
         int32_t iMinSAD, iSAD = 9999;  
2385    
2386          MainSearch8FuncPtr MainSearchPtr;          if (MotionFlags&XVID_ME_HALFPELREFINE16_BITS) SubpelRefine(Data);
2387    
2388  /* Get maximum range */          if (Data->qpel) {
2389          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,                  if (MotionFlags&(XVID_ME_EXTSEARCH_BITS | XVID_ME_HALFPELREFINE16_BITS)) { /* there was halfpel-precision search */
2390                            iFcode);                          for(i = 0; i < 5; i++) if (bsad[i] > Data->iMinSAD[i]) {
2391                                    Data->currentQMV[i].x = 2 * Data->currentMV[i].x; /* we have found a better match */
2392                                    Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
2393                            }
2394    
2395  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */                          /* preparing for qpel-precision search */
2396                            Data->qpel_precision = 1;
2397                            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2398                                            pParam->width, pParam->height, Data->iFcode, 1, 0);
2399                    }
2400                    if (MotionFlags&XVID_ME_QUARTERPELREFINE16_BITS) SubpelRefine(Data);
2401            }
2402    
2403          if (!(MotionFlags & PMV_HALFPEL8)) {          if (MotionFlags&XVID_ME_CHECKPREDICTION_BITS) { /* let's check vector equal to prediction */
2404                  min_dx = EVEN(min_dx);                  VECTOR * v = Data->qpel ? Data->currentQMV : Data->currentMV;
2405                  max_dx = EVEN(max_dx);                  if (!(Data->predMV.x == v->x && Data->predMV.y == v->y))
2406                  min_dy = EVEN(min_dy);                          CheckCandidateBits16(Data->predMV.x, Data->predMV.y, 255, &iDirection, Data);
2407                  max_dy = EVEN(max_dy);          }
2408            return Data->iMinSAD[0];
2409          }          }
         /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
         //bPredEq = get_pmvdata(pMBs, x >> 1, y >> 1, iWcount, iSubBlock, pmv[0].x, pmv[0].y, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, x >> 1, y >> 1, iSubBlock, pmv, psad);  
2410    
2411    static int
2412    CountMBBitsInter4v(const SearchData * const Data,
2413                                            MACROBLOCK * const pMB, const MACROBLOCK * const pMBs,
2414                                            const int x, const int y,
2415                                            const MBParam * const pParam, const uint32_t MotionFlags,
2416                                            const VECTOR * const backup)
2417    {
2418    
2419  /* Step 4: Calculate SAD around the Median prediction.          int cbp = 0, bits = 0, t = 0, i, iDirection;
2420          MinSAD=SAD          SearchData Data2, *Data8 = &Data2;
2421          If Motion Vector equal to Previous frame motion vector          int sumx = 0, sumy = 0;
2422                  and MinSAD<PrevFrmSAD goto Step 10.          int16_t *in = Data->dctSpace, *coeff = Data->dctSpace + 64;
2423          If SAD<=256 goto Step 10.          uint8_t * ptr;
2424  */  
2425            memcpy(Data8, Data, sizeof(SearchData));
2426            CheckCandidate = CheckCandidateBits8;
2427    
2428            for (i = 0; i < 4; i++) { /* for all luma blocks */
2429    
2430                    Data8->iMinSAD = Data->iMinSAD + i + 1;
2431                    Data8->currentMV = Data->currentMV + i + 1;
2432                    Data8->currentQMV = Data->currentQMV + i + 1;
2433                    Data8->Cur = Data->Cur + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2434                    Data8->RefP[0] = Data->RefP[0] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2435                    Data8->RefP[2] = Data->RefP[2] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2436                    Data8->RefP[1] = Data->RefP[1] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2437                    Data8->RefP[3] = Data->RefP[3] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2438                    *Data8->cbp = (Data->cbp[1] & (1<<(5-i))) ? 1:0; // copy corresponding cbp bit
2439    //              *Data8->cbp = 1;
2440    
2441                    if(Data->qpel) {
2442                            Data8->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, i);
2443                            if (i != 0)     t = d_mv_bits(  Data8->currentQMV->x, Data8->currentQMV->y,
2444                                                                                    Data8->predMV, Data8->iFcode, 0, 0);
2445                    } else {
2446                            Data8->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, i);
2447                            if (i != 0)     t = d_mv_bits(  Data8->currentMV->x, Data8->currentMV->y,
2448                                                                                    Data8->predMV, Data8->iFcode, 0, 0);
2449                    }
2450    
2451  // Prepare for main loop                  get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 8,
2452                                            pParam->width, pParam->height, Data8->iFcode, Data8->qpel, 0);
2453    
2454                    *Data8->iMinSAD += BITS_MULT*t;
2455    
2456          if (!(MotionFlags & PMV_HALFPEL8)) {                  Data8->qpel_precision = Data8->qpel;
2457                  currMV->x = EVEN(currMV->x);                  /* checking the vector which has been found by SAD-based 8x8 search (if it's different than the one found so far) */
2458                  currMV->y = EVEN(currMV->y);                  {
2459                            VECTOR *v = Data8->qpel ? Data8->currentQMV : Data8->currentMV;
2460                            if (!MVequal (*v, backup[i+1]) )
2461                                    CheckCandidateBits8(backup[i+1].x, backup[i+1].y, 255, &iDirection, Data8);
2462          }          }
2463    
2464          if (currMV->x > max_dx)                  if (Data8->qpel) {
2465                  currMV->x = max_dx;                          if (MotionFlags&XVID_ME_HALFPELREFINE8_BITS || (MotionFlags&XVID_ME_EXTSEARCH8 && MotionFlags&XVID_ME_EXTSEARCH_BITS)) { /* halfpixel motion search follows */
2466          if (currMV->x < min_dx)                                  int32_t s = *Data8->iMinSAD;
2467                  currMV->x = min_dx;                                  Data8->currentMV->x = Data8->currentQMV->x/2;
2468          if (currMV->y > max_dy)                                  Data8->currentMV->y = Data8->currentQMV->y/2;
2469                  currMV->y = max_dy;                                  Data8->qpel_precision = 0;
2470          if (currMV->y < min_dy)                                  get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 8,
2471                  currMV->y = min_dy;                                                          pParam->width, pParam->height, Data8->iFcode - 1, 0, 0);
   
 /***************** This is predictor SET A: only median prediction ******************/  
2472    
2473                                    if (Data8->currentQMV->x & 1 || Data8->currentQMV->y & 1)
2474                                            CheckCandidateBits8(Data8->currentMV->x, Data8->currentMV->y, 255, &iDirection, Data8);
2475    
2476          iMinSAD =                                  if (MotionFlags & XVID_ME_EXTSEARCH8 && MotionFlags & XVID_ME_EXTSEARCH_BITS)
2477                  sad8(cur,                                          SquareSearch(Data8->currentMV->x, Data8->currentMV->x, Data8, 255);
                          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);  
2478    
2479                                    if (MotionFlags & XVID_ME_HALFPELREFINE8_BITS)
2480                                            SubpelRefine(Data8);
2481    
2482  // thresh1 is fixed to 256                                  if(s > *Data8->iMinSAD) { /* we have found a better match */
2483          if (iMinSAD < 256 / 4) {                                          Data8->currentQMV->x = 2*Data8->currentMV->x;
2484                  if (MotionFlags & PMV_QUICKSTOP8)                                          Data8->currentQMV->y = 2*Data8->currentMV->y;
                         goto EPZS8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
2485          }          }
2486    
2487  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/                                  Data8->qpel_precision = 1;
2488                                    get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 8,
2489                                                            pParam->width, pParam->height, Data8->iFcode, 1, 0);
2490    
2491                            }
2492                            if (MotionFlags & XVID_ME_QUARTERPELREFINE8_BITS) SubpelRefine(Data8);
2493    
2494  // MV=(0,0) is often a good choice                  } else { /* not qpel */
         CHECK_MV8_ZERO;  
2495    
2496  // previous frame MV                          if (MotionFlags & XVID_ME_EXTSEARCH8 && MotionFlags & XVID_ME_EXTSEARCH_BITS) /* extsearch */
2497          CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x, prevMB->mvs[iSubBlock].y);                                  SquareSearch(Data8->currentMV->x, Data8->currentMV->x, Data8, 255);
2498    
2499  // left neighbour, if allowed                          if (MotionFlags & XVID_ME_HALFPELREFINE8_BITS)
2500          if (psad[1] != MV_MAX_ERROR) {                                  SubpelRefine(Data8); /* halfpel refinement */
                 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);  
2501          }          }
 // top neighbour, if allowed  
         if (psad[2] != MV_MAX_ERROR) {  
                 if (!(MotionFlags & PMV_HALFPEL8)) {  
                         pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
                 }  
                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
2502    
2503  // top right neighbour, if allowed                  /* checking vector equal to predicion */
2504                  if (psad[3] != MV_MAX_ERROR) {                  if (i != 0 && MotionFlags & XVID_ME_CHECKPREDICTION_BITS) {
2505                          if (!(MotionFlags & PMV_HALFPEL8)) {                          const VECTOR * v = Data->qpel ? Data8->currentQMV : Data8->currentMV;
2506                                  pmv[3].x = EVEN(pmv[3].x);                          if (!MVequal(*v, Data8->predMV))
2507                                  pmv[3].y = EVEN(pmv[3].y);                                  CheckCandidateBits8(Data8->predMV.x, Data8->predMV.y, 255, &iDirection, Data8);
                         }  
                         CHECK_MV8_CANDIDATE(pmv[3].x, pmv[3].y);  
                 }  
2508          }          }
2509    
2510  /*  // this bias is zero anyway, at the moment!                  bits += *Data8->iMinSAD;
2511                    if (bits >= Data->iMinSAD[0]) return bits; /* no chances for INTER4V */
2512    
2513          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)                  /* MB structures for INTER4V mode; we have to set them here, we don't have predictor anywhere else */
2514                  iMinSAD -= MV8_00_BIAS;                  if(Data->qpel) {
2515                            pMB->pmvs[i].x = Data8->currentQMV->x - Data8->predMV.x;
2516                            pMB->pmvs[i].y = Data8->currentQMV->y - Data8->predMV.y;
2517                            pMB->qmvs[i] = *Data8->currentQMV;
2518                            sumx += Data8->currentQMV->x/2;
2519                            sumy += Data8->currentQMV->y/2;
2520                    } else {
2521                            pMB->pmvs[i].x = Data8->currentMV->x - Data8->predMV.x;
2522                            pMB->pmvs[i].y = Data8->currentMV->y - Data8->predMV.y;
2523                            sumx += Data8->currentMV->x;
2524                            sumy += Data8->currentMV->y;
2525                    }
2526                    pMB->mvs[i] = *Data8->currentMV;
2527                    pMB->sad8[i] = 4 * *Data8->iMinSAD;
2528                    if (Data8->cbp[0]) cbp |= 1 << (5 - i);
2529    
2530  */          } /* end - for all luma blocks */
2531    
2532  /* Terminate if MinSAD <= T_2          bits += BITS_MULT*xvid_cbpy_tab[15-(cbp>>2)].len;
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
2533    
2534          if (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */          /* let's check chroma */
2535                  if (MotionFlags & PMV_QUICKSTOP8)          sumx = (sumx >> 3) + roundtab_76[sumx & 0xf];
2536                          goto EPZS8_Terminate_without_Refine;          sumy = (sumy >> 3) + roundtab_76[sumy & 0xf];
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
         }  
2537    
2538  /************ (Diamond Search)  **************/          /* chroma U */
2539            ptr = interpolate8x8_switch2(Data->RefQ + 64, Data->RefP[4], 0, 0, sumx, sumy, Data->iEdgedWidth/2, Data->rounding);
2540            transfer_8to16subro(in, Data->CurU, ptr, Data->iEdgedWidth/2);
2541            bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 4);
2542    
2543          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          if (bits >= *Data->iMinSAD) return bits;
2544    
2545          if (!(MotionFlags & PMV_HALFPELDIAMOND8))          /* chroma V */
2546                  iDiamondSize *= 2;          ptr = interpolate8x8_switch2(Data->RefQ + 64, Data->RefP[5], 0, 0, sumx, sumy, Data->iEdgedWidth/2, Data->rounding);
2547            transfer_8to16subro(in, Data->CurV, ptr, Data->iEdgedWidth/2);
2548            bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 5);
2549    
2550  /* default: use best prediction as starting point for one call of EPZS_MainSearch */          bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTER4V & 7) | ((cbp & 3) << 3)].len;
2551    
2552  // there is no EPZS^2 for inter4v at the moment          *Data->cbp = cbp;
2553            return bits;
2554    }
2555    
2556    if (MotionFlags & PMV_USESQUARES8)  static int
2557        MainSearchPtr = Square8_MainSearch;  CountMBBitsIntra(const SearchData * const Data)
2558    else  {
2559            int bits = BITS_MULT*1; /* this one is ac/dc prediction flag bit */
2560            int cbp = 0, i, dc = 0;
2561            int16_t *in = Data->dctSpace, * coeff = Data->dctSpace + 64;
2562    
2563          if (MotionFlags & PMV_ADVANCEDDIAMOND8)          for(i = 0; i < 4; i++) {
2564                  MainSearchPtr = AdvDiamond8_MainSearch;                  int s = 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2565          else                  transfer_8to16copy(in, Data->Cur + s, Data->iEdgedWidth);
2566                  MainSearchPtr = Diamond8_MainSearch;                  bits += Block_CalcBitsIntra(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, i, &dc);
2567    
2568          iSAD =                  if (bits >= Data->iMinSAD[0]) return bits;
2569                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,          }
                                                   currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, 0);  
2570    
2571            bits += BITS_MULT*xvid_cbpy_tab[cbp>>2].len;
2572    
2573          if (iSAD < iMinSAD) {          /*chroma U */
2574                  *currMV = newMV;          transfer_8to16copy(in, Data->CurU, Data->iEdgedWidth/2);
2575                  iMinSAD = iSAD;          bits += Block_CalcBitsIntra(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 4, &dc);
         }  
2576    
2577          if (MotionFlags & PMV_EXTSEARCH8) {          if (bits >= Data->iMinSAD[0]) return bits;
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
2578    
2579                  if (!(MVequal(pmv[0], backupMV))) {          /* chroma V */
2580                          iSAD =          transfer_8to16copy(in, Data->CurV, Data->iEdgedWidth/2);
2581                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,          bits += Block_CalcBitsIntra(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 5, &dc);
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, 0);  
2582    
2583                          if (iSAD < iMinSAD) {          bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTRA & 7) | ((cbp & 3) << 3)].len;
2584                                  *currMV = newMV;  
2585                                  iMinSAD = iSAD;          return bits;
                         }  
2586                  }                  }
2587    
2588                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {  static int
2589                          iSAD =  CountMBBitsGMC(const SearchData * const Data, const IMAGE * const vGMC, const int x, const int y)
2590                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  {
2591                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,          int bits = BITS_MULT*1; /* this one is mcsel */
2592                                                                    max_dy, iEdgedWidth, iDiamondSize, iFcode,          int cbp = 0, i;
2593                                                                    iQuant, 0);          int16_t *in = Data->dctSpace, * coeff = Data->dctSpace + 64;
2594    
2595                          if (iSAD < iMinSAD) {          for(i = 0; i < 4; i++) {
2596                                  *currMV = newMV;                  int s = 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2597                                  iMinSAD = iSAD;                  transfer_8to16subro(in, Data->Cur + s, vGMC->y + s + 16*(x+y*Data->iEdgedWidth), Data->iEdgedWidth);
2598                          }                  bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, i);
2599                  }                  if (bits >= Data->iMinSAD[0]) return bits;
2600          }          }
2601    
2602  /***************        Choose best MV found     **************/          bits += BITS_MULT*xvid_cbpy_tab[15-(cbp>>2)].len;
2603    
2604            /*chroma U */
2605            transfer_8to16subro(in, Data->CurU, vGMC->u + 8*(x+y*(Data->iEdgedWidth/2)), Data->iEdgedWidth/2);
2606            bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 4);
2607    
2608            if (bits >= Data->iMinSAD[0]) return bits;
2609    
2610            /* chroma V */
2611            transfer_8to16subro(in, Data->CurV , vGMC->v + 8*(x+y*(Data->iEdgedWidth/2)), Data->iEdgedWidth/2);
2612            bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 5);
2613    
2614    EPZS8_Terminate_with_Refine:          bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTER & 7) | ((cbp & 3) << 3)].len;
         if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step  
                 iMinSAD =  
                         Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                         iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                         iFcode, iQuant, iEdgedWidth);  
2615    
2616    EPZS8_Terminate_without_Refine:          *Data->cbp = cbp;
2617    
2618          currPMV->x = currMV->x - center_x;          return bits;
         currPMV->y = currMV->y - center_y;  
         return iMinSAD;  
2619  }  }
2620    
2621    
2622    
2623  int32_t  
2624  PMVfastIntSearch16(const uint8_t * const pRef,  static __inline void
2625    GMEanalyzeMB (  const uint8_t * const pCur,
2626                                    const uint8_t * const pRef,
2627                                  const uint8_t * const pRefH,                                  const uint8_t * const pRefH,
2628                                  const uint8_t * const pRefV,                                  const uint8_t * const pRefV,
2629                                  const uint8_t * const pRefHV,                                  const uint8_t * const pRefHV,
                                 const IMAGE * const pCur,  
2630                                  const int x,                                  const int x,
2631                                  const int y,                                  const int y,
                                 const int start_x,              /* start should be most likely vector */  
                                 const int start_y,  
                                 const int center_x,             /* center is from where length of MVs is measured */  
                                 const int center_y,  
                                 const uint32_t MotionFlags,  
                                 const uint32_t iQuant,  
                                 const uint32_t iFcode,  
2632                                  const MBParam * const pParam,                                  const MBParam * const pParam,
2633                                  const MACROBLOCK * const pMBs,                                  MACROBLOCK * const pMBs,
2634                                  const MACROBLOCK * const prevMBs,                                  SearchData * const Data)
                                 VECTOR * const currMV,  
                                 VECTOR * const currPMV)  
2635  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
   
         const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;  
         const VECTOR zeroMV = { 0, 0 };  
2636    
2637          int32_t iDiamondSize;          int i=0;
2638            MACROBLOCK * const pMB = &pMBs[x + y * pParam->mb_width];
2639    
2640          int32_t min_dx;          Data->iMinSAD[0] = MV_MAX_ERROR;
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
2641    
2642          int32_t iFound;          Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
2643    
2644          VECTOR newMV;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2645          VECTOR backupMV;                                  pParam->width, pParam->height, 16, 0, 0);
2646    
2647          VECTOR pmv[4];          Data->Cur = pCur + 16*(x + y * pParam->edged_width);
2648          int32_t psad[4];          Data->RefP[0] = pRef + 16*(x + y * pParam->edged_width);
2649            Data->RefP[1] = pRefV + 16*(x + y * pParam->edged_width);
2650            Data->RefP[2] = pRefH + 16*(x + y * pParam->edged_width);
2651            Data->RefP[3] = pRefHV + 16*(x + y * pParam->edged_width);
2652    
2653          MainSearch16FuncPtr MainSearchPtr;          Data->currentMV[0].x = Data->currentMV[0].y = 0;
2654            CheckCandidate16I(0, 0, 255, &i, Data);
2655    
2656          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;          if ( (Data->predMV.x !=0) || (Data->predMV.y != 0) )
2657          MACROBLOCK *const pMB = pMBs + x + y * iWcount;                  CheckCandidate16I(Data->predMV.x, Data->predMV.y, 255, &i, Data);
2658    
2659          int32_t threshA, threshB;          AdvDiamondSearch(Data->currentMV[0].x, Data->currentMV[0].y, Data, 255);
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD;  
2660    
2661            SubpelRefine(Data);
2662    
 /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
2663    
2664  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          /* for QPel halfpel positions are worse than in halfpel mode :( */
2665    /*      if (Data->qpel) {
2666                    Data->currentQMV->x = 2*Data->currentMV->x;
2667                    Data->currentQMV->y = 2*Data->currentMV->y;
2668                    Data->qpel_precision = 1;
2669                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2670                                            pParam->width, pParam->height, iFcode, 1, 0);
2671                    SubpelRefine(Data);
2672            }
2673    */
2674    
2675          if ((x == 0) && (y == 0)) {          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
2676                  threshA = 512;          pMB->sad16 = Data->iMinSAD[0];
2677                  threshB = 1024;          pMB->mode = MODE_INTER;
2678            pMB->sad16 += 10*d_mv_bits(pMB->mvs[0].x, pMB->mvs[0].y, Data->predMV, Data->iFcode, 0, 0);
2679            return;
2680    }
2681    
2682                  bPredEq = 0;  void
2683                  psad[0] = psad[1] = psad[2] = psad[3] = 0;  GMEanalysis(const MBParam * const pParam,
2684                  *currMV = pmv[0] = pmv[1] = pmv[2] = pmv[3] = zeroMV;                          const FRAMEINFO * const current,
2685                            const FRAMEINFO * const reference,
2686                            const IMAGE * const pRefH,
2687                            const IMAGE * const pRefV,
2688                            const IMAGE * const pRefHV)
2689    {
2690            uint32_t x, y;
2691            MACROBLOCK * const pMBs = current->mbs;
2692            const IMAGE * const pCurrent = &current->image;
2693            const IMAGE * const pReference = &reference->image;
2694    
2695          } else {          int32_t iMinSAD[5], temp[5];
2696            VECTOR currentMV[5];
2697            SearchData Data;
2698            memset(&Data, 0, sizeof(SearchData));
2699    
2700                  bPredEq = get_ipmvdata(pMBs, iWcount, 0, x, y, 0, pmv, psad);          Data.iEdgedWidth = pParam->edged_width;
2701            Data.rounding = pParam->m_rounding_type;
2702    
2703                  threshA = psad[0];          Data.currentMV = &currentMV[0];
2704                  threshB = threshA + 256;          Data.iMinSAD = &iMinSAD[0];
2705                  if (threshA < 512)          Data.iFcode = current->fcode;
2706                          threshA = 512;          Data.temp = temp;
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
2707    
2708                  *currMV = pmv[0];                       /* current best := prediction */          CheckCandidate = CheckCandidate16I;
         }  
2709    
2710          iFound = 0;          if (sadInit) (*sadInit) ();
2711    
2712  /* Step 4: Calculate SAD around the Median prediction.          for (y = 0; y < pParam->mb_height; y ++) {
2713     MinSAD=SAD                  for (x = 0; x < pParam->mb_width; x ++) {
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
2714    
2715          if (currMV->x > max_dx) {                          GMEanalyzeMB(pCurrent->y, pReference->y, pRefH->y, pRefV->y, pRefHV->y, x, y, pParam, pMBs, &Data);
                 currMV->x = EVEN(max_dx);  
         }  
         if (currMV->x < min_dx) {  
                 currMV->x = EVEN(min_dx);  
2716          }          }
         if (currMV->y > max_dy) {  
                 currMV->y = EVEN(max_dy);  
2717          }          }
2718          if (currMV->y < min_dy) {          return;
                 currMV->y = EVEN(min_dy);  
2719          }          }
2720    
         iMinSAD =  
                 sad16(cur,  
                           get_iref_mv(pRef, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
2721    
2722          if ((iMinSAD < 256) ||  WARPPOINTS
2723                  ((MVequal(*currMV, prevMB->i_mvs[0])) &&  GlobalMotionEst(MACROBLOCK * const pMBs,
2724                   ((int32_t) iMinSAD < prevMB->i_sad16))) {                                  const MBParam * const pParam,
2725                  if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode                                  const FRAMEINFO * const current,
2726                                    const FRAMEINFO * const reference,
2727                                    const IMAGE * const pRefH,
2728                                    const IMAGE * const pRefV,
2729                                    const IMAGE * const pRefHV)
2730                  {                  {
                         if (!MVzero(*currMV)) {  
                                 iMinSAD += MV16_00_BIAS;  
                                 CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures  
                                 iMinSAD -= MV16_00_BIAS;  
                         }  
                 }  
   
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfastInt16_Terminate_with_Refine;  
         }  
   
2731    
2732  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion          const int deltax=8;             // upper bound for difference between a MV and it's neighbour MVs
2733     vector of the median.          const int deltay=8;
2734     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2          const unsigned int gradx=512;           // lower bound for gradient in MB (ignore "flat" blocks)
2735  */          const unsigned int grady=512;
   
         if ((bPredEq) && (MVequal(pmv[0], prevMB->i_mvs[0])))  
                 iFound = 2;  
   
 /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.  
    Otherwise select large Diamond Search.  
 */  
2736    
2737          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))          double sol[4] = { 0., 0., 0., 0. };
                 iDiamondSize = 2;               // halfpel units!  
         else  
                 iDiamondSize = 4;               // halfpel units!  
2738    
2739  /*          WARPPOINTS gmc;
    Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  
    Also calculate (0,0) but do not subtract offset.  
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset.  
 */  
2740    
2741  // (0,0) is often a good choice          uint32_t mx, my;
2742    
2743          if (!MVzero(pmv[0]))          int MBh = pParam->mb_height;
2744                  CHECK_MV16_ZERO;          int MBw = pParam->mb_width;
2745            const int minblocks = 9; //MBh*MBw/32+3;                /* just some reasonable number 3% + 3 */
2746            const int maxblocks = MBh*MBw/4;                /* just some reasonable number 3% + 3 */
2747    
2748  // previous frame MV is always possible          int num=0;
2749            int oldnum;
2750    
2751          if (!MVzero(prevMB->i_mvs[0]))          gmc.duv[0].x = gmc.duv[0].y = gmc.duv[1].x = gmc.duv[1].y = gmc.duv[2].x = gmc.duv[2].y = 0;
                 if (!MVequal(prevMB->i_mvs[0], pmv[0]))  
                         CHECK_MV16_CANDIDATE(prevMB->i_mvs[0].x, prevMB->i_mvs[0].y);  
   
 // left neighbour, if allowed  
   
         if (!MVzero(pmv[1]))  
                 if (!MVequal(pmv[1], prevMB->i_mvs[0]))  
                         if (!MVequal(pmv[1], pmv[0]))  
                                 CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
   
 // top neighbour, if allowed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], prevMB->i_mvs[0]))  
                         if (!MVequal(pmv[2], pmv[0]))  
                                 if (!MVequal(pmv[2], pmv[1]))  
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed  
                                         if (!MVzero(pmv[3]))  
                                                 if (!MVequal(pmv[3], prevMB->i_mvs[0]))  
                                                         if (!MVequal(pmv[3], pmv[0]))  
                                                                 if (!MVequal(pmv[3], pmv[1]))  
                                                                         if (!MVequal(pmv[3], pmv[2]))  
                                                                                 CHECK_MV16_CANDIDATE(pmv[3].x,  
                                                                                                                          pmv[3].y);  
   
         if ((MVzero(*currMV)) &&  
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV16_00_BIAS;  
2752    
2753            GMEanalysis(pParam,current, reference, pRefH, pRefV, pRefHV);
2754    
2755  /* Step 6: If MinSAD <= thresa goto Step 10.          /* block based ME isn't done, yet, so do a quick presearch */
    If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
 */  
2756    
2757          if ((iMinSAD <= threshA) ||  // filter mask of all blocks
                 (MVequal(*currMV, prevMB->i_mvs[0]) &&  
                  ((int32_t) iMinSAD < prevMB->i_sad16))) {  
2758    
2759                  if (MotionFlags & PMV_EARLYSTOP16)          for (my = 0; my < (uint32_t)MBh; my++)
2760                          goto PMVfastInt16_Terminate_with_Refine;          for (mx = 0; mx < (uint32_t)MBw; mx++)
2761            {
2762                    const int mbnum = mx + my * MBw;
2763                            pMBs[mbnum].mcsel = 0;
2764          }          }
2765    
2766    
2767  /************ (Diamond Search)  **************/          for (my = 1; my < (uint32_t)MBh-1; my++) /* ignore boundary blocks */
2768  /*          for (mx = 1; mx < (uint32_t)MBw-1; mx++) /* theirs MVs are often wrong */
2769     Step 7: Perform Diamond search, with either the small or large diamond.          {
2770     If Found=2 only examine one Diamond pattern, and afterwards goto step 10                  const int mbnum = mx + my * MBw;
2771     Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.                  MACROBLOCK *const pMB = &pMBs[mbnum];
2772     If center then goto step 10.                  const VECTOR mv = pMB->mvs[0];
    Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
    Refine by using small diamond and goto step 10.  
 */  
2773    
2774          if (MotionFlags & PMV_USESQUARES16)                  /* don't use object boundaries */
2775                  MainSearchPtr = Square16_MainSearch;                  if   ( (abs(mv.x -   (pMB-1)->mvs[0].x) < deltax)
2776          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)                          && (abs(mv.y -   (pMB-1)->mvs[0].y) < deltay)
2777                  MainSearchPtr = AdvDiamond16_MainSearch;                          && (abs(mv.x -   (pMB+1)->mvs[0].x) < deltax)
2778          else                          && (abs(mv.y -   (pMB+1)->mvs[0].y) < deltay)
2779                  MainSearchPtr = Diamond16_MainSearch;                          && (abs(mv.x - (pMB-MBw)->mvs[0].x) < deltax)
2780                            && (abs(mv.y - (pMB-MBw)->mvs[0].y) < deltay)
2781                            && (abs(mv.x - (pMB+MBw)->mvs[0].x) < deltax)
2782                            && (abs(mv.y - (pMB+MBw)->mvs[0].y) < deltay) )
2783                    {       const int iEdgedWidth = pParam->edged_width;
2784                            const uint8_t *const pCur = current->image.y + 16*(my*iEdgedWidth + mx);
2785                            if ( (sad16 ( pCur, pCur+1 , iEdgedWidth, 65536) >= gradx )
2786                             &&  (sad16 ( pCur, pCur+iEdgedWidth, iEdgedWidth, 65536) >= grady ) )
2787                             {      pMB->mcsel = 1;
2788                                    num++;
2789                             }
2790    
2791          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                  /* only use "structured" blocks */
2792                    }
2793            }
2794            emms();
2795    
2796            /*      further filtering would be possible, but during iteration, remaining
2797                    outliers usually are removed, too */
2798    
2799  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          if (num>= minblocks)
2800          iSAD =          do {            /* until convergence */
2801                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,                  double DtimesF[4];
2802                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,                  double a,b,c,n,invdenom;
2803                                                    min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,                  double meanx,meany;
                                                   iQuant, iFound);  
2804    
2805          if (iSAD < iMinSAD) {                  a = b = c = n = 0;
2806                  *currMV = newMV;                  DtimesF[0] = DtimesF[1] = DtimesF[2] = DtimesF[3] = 0.;
2807                  iMinSAD = iSAD;                  for (my = 1; my < (uint32_t)MBh-1; my++)
2808          }                  for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2809                    {
2810                            const int mbnum = mx + my * MBw;
2811                            const VECTOR mv = pMBs[mbnum].mvs[0];
2812    
2813          if (MotionFlags & PMV_EXTSEARCH16) {                          if (!pMBs[mbnum].mcsel)
2814  /* extended: search (up to) two more times: orignal prediction and (0,0) */                                  continue;
2815    
2816                  if (!(MVequal(pmv[0], backupMV))) {                          n++;
2817                          iSAD =                          a += 16*mx+8;
2818                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                          b += 16*my+8;
2819                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,                          c += (16*mx+8)*(16*mx+8)+(16*my+8)*(16*my+8);
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
2820    
2821                          if (iSAD < iMinSAD) {                          DtimesF[0] += (double)mv.x;
2822                                  *currMV = newMV;                          DtimesF[1] += (double)mv.x*(16*mx+8) + (double)mv.y*(16*my+8);
2823                                  iMinSAD = iSAD;                          DtimesF[2] += (double)mv.x*(16*my+8) - (double)mv.y*(16*mx+8);
2824                          }                          DtimesF[3] += (double)mv.y;
2825                  }                  }
2826    
2827                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          invdenom = a*a+b*b-c*n;
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
                 }  
         }  
2828    
2829  /*  /* Solve the system:    sol = (D'*E*D)^{-1} D'*E*F   */
2830     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  /* D'*E*F has been calculated in the same loop as matrix */
 */  
2831    
2832  PMVfastInt16_Terminate_with_Refine:          sol[0] = -c*DtimesF[0] + a*DtimesF[1] + b*DtimesF[2];
2833            sol[1] =  a*DtimesF[0] - n*DtimesF[1]                           + b*DtimesF[3];
2834            sol[2] =  b*DtimesF[0]                          - n*DtimesF[2] - a*DtimesF[3];
2835            sol[3] =                                 b*DtimesF[1] - a*DtimesF[2] - c*DtimesF[3];
2836    
2837          pMB->i_mvs[0] = pMB->i_mvs[1] = pMB->i_mvs[2] = pMB->i_mvs[3] = pMB->i_mv16 = *currMV;          sol[0] /= invdenom;
2838          pMB->i_sad8[0] = pMB->i_sad8[1] = pMB->i_sad8[2] = pMB->i_sad8[3] = pMB->i_sad16 = iMinSAD;          sol[1] /= invdenom;
2839            sol[2] /= invdenom;
2840            sol[3] /= invdenom;
2841    
2842          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step          meanx = meany = 0.;
2843                  iMinSAD =          oldnum = 0;
2844                          Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,          for (my = 1; my < (uint32_t)MBh-1; my++)
2845                                                           iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,                  for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2846                                                           iFcode, iQuant, iEdgedWidth);                  {
2847                            const int mbnum = mx + my * MBw;
2848                            const VECTOR mv = pMBs[mbnum].mvs[0];
2849    
2850          pmv[0] = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          // get _REAL_ prediction (halfpel possible)                          if (!pMBs[mbnum].mcsel)
2851                                    continue;
2852    
2853  PMVfastInt16_Terminate_without_Refine:                          oldnum++;
2854          currPMV->x = currMV->x - center_x;                          meanx += fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - (double)mv.x );
2855          currPMV->y = currMV->y - center_y;                          meany += fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - (double)mv.y );
         return iMinSAD;  
2856  }  }
2857    
2858            if (4*meanx > oldnum)   /* better fit than 0.25 (=1/4pel) is useless */
2859                    meanx /= oldnum;
2860            else
2861                    meanx = 0.25;
2862    
2863            if (4*meany > oldnum)
2864                    meany /= oldnum;
2865            else
2866                    meany = 0.25;
2867    
2868  /* ***********************************************************          num = 0;
2869          bvop motion estimation          for (my = 0; my < (uint32_t)MBh; my++)
2870  ***************************************************************/                  for (mx = 0; mx < (uint32_t)MBw; mx++)
   
 void  
 MotionEstimationBVOP(MBParam * const pParam,  
                                          FRAMEINFO * const frame,  
                                          const int32_t time_bp,  
                                          const int32_t time_pp,  
                                          // forward (past) reference  
                                          const MACROBLOCK * const f_mbs,  
                                          const IMAGE * const f_ref,  
                                          const IMAGE * const f_refH,  
                                          const IMAGE * const f_refV,  
                                          const IMAGE * const f_refHV,  
                                          // backward (future) reference  
                                          const MACROBLOCK * const b_mbs,  
                                          const IMAGE * const b_ref,  
                                          const IMAGE * const b_refH,  
                                          const IMAGE * const b_refV,  
                                          const IMAGE * const b_refHV)  
2871  {  {
2872          const int mb_width = pParam->mb_width;                          const int mbnum = mx + my * MBw;
2873          const int mb_height = pParam->mb_height;                          const VECTOR mv = pMBs[mbnum].mvs[0];
         const int edged_width = pParam->edged_width;  
   
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
2874    
2875          int i, j, k;                          if (!pMBs[mbnum].mcsel)
2876                                    continue;
         static const VECTOR zeroMV={0,0};  
2877    
2878          int f_sad16;    /* forward (as usual) search */                          if  ( ( fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - (double)mv.x ) > meanx )
2879          int b_sad16;    /* backward (only in b-frames) search */                                  || ( fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - (double)mv.y ) > meany ) )
2880          int i_sad16;    /* interpolated (both direction, b-frames only) */                                  pMBs[mbnum].mcsel=0;
2881          int d_sad16;    /* direct mode (assume almost linear motion) */                          else
2882                                    num++;
2883                    }
2884    
2885          int best_sad;          } while ( (oldnum != num) && (num>= minblocks) );
2886    
2887          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/          if (num < minblocks)
2888          VECTOR f_interpolMV, b_interpolMV;          {
2889          VECTOR pmv_dontcare;                  const int iEdgedWidth = pParam->edged_width;
2890                    num = 0;
2891    
2892          int min_dx, max_dx, min_dy, max_dy;  /*              fprintf(stderr,"Warning! Unreliable GME (%d/%d blocks), falling back to translation.\n",num,MBh*MBw);
2893          int f_min_dx, f_max_dx, f_min_dy, f_max_dy;  */
2894          int b_min_dx, b_max_dx, b_min_dy, b_max_dy;                  gmc.duv[0].x= gmc.duv[0].y= gmc.duv[1].x= gmc.duv[1].y= gmc.duv[2].x= gmc.duv[2].y=0;
2895    
2896          int f_count=0;                  if (!(current->motion_flags & XVID_GME_REFINE))
2897          int b_count=0;                          return gmc;
         int i_count=0;  
         int d_count=0;  
2898    
2899          const int64_t TRB = (int32_t)time_pp - (int32_t)time_bp;                  for (my = 1; my < (uint32_t)MBh-1; my++) /* ignore boundary blocks */
2900      const int64_t TRD = (int32_t)time_pp;                  for (mx = 1; mx < (uint32_t)MBw-1; mx++) /* theirs MVs are often wrong */
2901                    {
2902                            const int mbnum = mx + my * MBw;
2903                            MACROBLOCK *const pMB = &pMBs[mbnum];
2904                            const uint8_t *const pCur = current->image.y + 16*(my*iEdgedWidth + mx);
2905                            if ( (sad16 ( pCur, pCur+1 , iEdgedWidth, 65536) >= gradx )
2906                             &&  (sad16 ( pCur, pCur+iEdgedWidth, iEdgedWidth, 65536) >= grady ) )
2907                             {      pMB->mcsel = 1;
2908                                    gmc.duv[0].x += pMB->mvs[0].x;
2909                                    gmc.duv[0].y += pMB->mvs[0].y;
2910                                    num++;
2911                             }
2912                    }
2913    
2914          // fprintf(stderr,"TRB = %lld  TRD = %lld  time_bp =%d time_pp =%d\n\n",TRB,TRD,time_bp,time_pp);                  if (gmc.duv[0].x)
2915          // note: i==horizontal, j==vertical                          gmc.duv[0].x /= num;
2916          for (j = 0; j < mb_height; j++) {                  if (gmc.duv[0].y)
2917                            gmc.duv[0].y /= num;
2918            } else {
2919    
2920                  f_predMV = zeroMV;      /* prediction is reset at left boundary */                  gmc.duv[0].x=(int)(sol[0]+0.5);
2921                  b_predMV = zeroMV;                  gmc.duv[0].y=(int)(sol[3]+0.5);
2922    
2923                  for (i = 0; i < mb_width; i++) {                  gmc.duv[1].x=(int)(sol[1]*pParam->width+0.5);
2924                          MACROBLOCK *mb = &frame->mbs[i + j * mb_width];                  gmc.duv[1].y=(int)(-sol[2]*pParam->width+0.5);
                         const MACROBLOCK *f_mb = &f_mbs[i + j * mb_width];  
                         const MACROBLOCK *b_mb = &b_mbs[i + j * mb_width];  
2925    
2926                          mb->deltamv=zeroMV;                  gmc.duv[2].x=-gmc.duv[1].y;             /* two warp points only */
2927                    gmc.duv[2].y=gmc.duv[1].x;
2928            }
2929            if (num>maxblocks)
2930            {       for (my = 1; my < (uint32_t)MBh-1; my++)
2931                    for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2932                    {
2933                            const int mbnum = mx + my * MBw;
2934                            if (pMBs[mbnum-1].mcsel)
2935                                    pMBs[mbnum].mcsel=0;
2936                            else
2937                                    if (pMBs[mbnum-MBw].mcsel)
2938                                            pMBs[mbnum].mcsel=0;
2939                    }
2940            }
2941            return gmc;
2942    }
2943    
2944  /* special case, if collocated block is SKIPed: encoding is forward (0,0), cpb=0 without further ado */  int
2945    GlobalMotionEstRefine(
2946                                    WARPPOINTS *const startwp,
2947                                    MACROBLOCK * const pMBs,
2948                                    const MBParam * const pParam,
2949                                    const FRAMEINFO * const current,
2950                                    const FRAMEINFO * const reference,
2951                                    const IMAGE * const pCurr,
2952                                    const IMAGE * const pRef,
2953                                    const IMAGE * const pRefH,
2954                                    const IMAGE * const pRefV,
2955                                    const IMAGE * const pRefHV)
2956    {
2957            uint8_t* GMCblock = (uint8_t*)malloc(16*pParam->edged_width);
2958            WARPPOINTS bestwp=*startwp;
2959            WARPPOINTS centerwp,currwp;
2960            int gmcminSAD=0;
2961            int gmcSAD=0;
2962            int direction;
2963    //      int mx,my;
2964    
2965                          if (b_mb->mode == MODE_INTER && b_mb->cbp == 0 &&  /* use many blocks... */
2966                                  b_mb->mvs[0].x == 0 && b_mb->mvs[0].y == 0) {  /*              for (my = 0; my < (uint32_t)pParam->mb_height; my++)
2967                                  mb->mode = MODE_NOT_CODED;                  for (mx = 0; mx < (uint32_t)pParam->mb_width; mx++)
2968                                  mb->b_mvs[0] = mb->mvs[0] = zeroMV;                  {
2969                                  continue;                          const int mbnum = mx + my * pParam->mb_width;
2970                            pMBs[mbnum].mcsel=1;
2971                          }                          }
2972    */
2973    
2974                          if (b_mb->mode == MODE_INTER4V)  /* or rather don't use too many blocks... */
2975    /*
2976                    for (my = 1; my < (uint32_t)MBh-1; my++)
2977                    for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2978                          {                          {
2979                                  d_sad16 = 0;                          const int mbnum = mx + my * MBw;
2980                          /* same method of scaling as in decoder.c, so we copy from there */                          if (MBmask[mbnum-1])
2981                      for (k = 0; k < 4; k++) {                                  MBmask[mbnum-1]=0;
2982                            else
2983                                          mb->directmv[k] = b_mb->mvs[k];                                  if (MBmask[mbnum-MBw])
2984                                            MBmask[mbnum-1]=0;
2985    
                                         mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);  
                     mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)  
                                                                                 ? ((TRB - TRD) * mb->directmv[k].x) / TRD  
                                             : mb->mvs[k].x - mb->directmv[k].x);  
   
                     mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);  
                         mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)  
                                                                                 ? ((TRB - TRD) * mb->directmv[k].y) / TRD  
                                             : mb->mvs[k].y - mb->directmv[k].y);  
   
                                         d_sad16 +=  
                                                 sad8bi(frame->image.y + (2*i+(k&1))*8 + (2*j+(k>>1))*8*edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 (2*i+(k&1)), (2*j+(k>>1)), 8, &mb->mvs[k], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 (2*i+(k&1)), (2*j+(k>>1)), 8, &mb->b_mvs[k], edged_width),  
                                                   edged_width);  
                                 }  
2986                          }                          }
2987                          else  */
2988                          {                  gmcminSAD = globalSAD(&bestwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
                                 mb->directmv[3] = mb->directmv[2] = mb->directmv[1] =  
                                         mb->directmv[0] = b_mb->mvs[0];  
2989    
2990                                  mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);                  if ( (reference->coding_type == S_VOP)
2991                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)                          && ( (reference->warp.duv[1].x != bestwp.duv[1].x)
2992                                                                          ? ((TRB - TRD) * mb->directmv[0].x) / TRD                            || (reference->warp.duv[1].y != bestwp.duv[1].y)
2993                                      : mb->mvs[0].x - mb->directmv[0].x);                            || (reference->warp.duv[0].x != bestwp.duv[0].x)
2994                              || (reference->warp.duv[0].y != bestwp.duv[0].y)
2995                      mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);                            || (reference->warp.duv[2].x != bestwp.duv[2].x)
2996                  mb->b_mvs[0].y = (int32_t) ((mb->directmv[0].y == 0)                            || (reference->warp.duv[2].y != bestwp.duv[2].y) ) )
2997                                                                          ? ((TRB - TRD) * mb->directmv[0].y) / TRD                  {
2998                                      : mb->mvs[0].y - mb->directmv[0].y);                          gmcSAD = globalSAD(&reference->warp, pParam, pMBs,
2999                                                                    current, pRef, pCurr, GMCblock);
                                 d_sad16 = sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 i, j, 16, &mb->mvs[0], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 i, j, 16, &mb->b_mvs[0], edged_width),  
                                                   edged_width);  
3000    
3001                            if (gmcSAD < gmcminSAD)
3002                            {       bestwp = reference->warp;
3003                                    gmcminSAD = gmcSAD;
3004                            }
3005              }              }
                     d_sad16 += calc_delta_16(mb->deltamv.x, mb->deltamv.y, 1, frame->quant);  
3006    
3007                          // forward search          do {
3008                          f_sad16 = SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,                  direction = 0;
3009                                                  &frame->image, i, j,                  centerwp = bestwp;
                                                 mb->mvs[0].x, mb->mvs[0].y,                     /* start point f_directMV */  
                                                 f_predMV.x, f_predMV.y,                         /* center is f-prediction */  
                                                 frame->motion_flags,  
                                                 frame->quant, frame->fcode, pParam,  
                                                 f_mbs, f_mbs,  
                                                 &mb->mvs[0], &pmv_dontcare);  
3010    
3011                    currwp = centerwp;
3012    
3013                          // backward search                  currwp.duv[0].x--;
3014                          b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,                  gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3015                                                  &frame->image, i, j,                  if (gmcSAD < gmcminSAD)
3016                                                  mb->b_mvs[0].x, mb->b_mvs[0].y,         /* start point b_directMV */                  {       bestwp = currwp;
3017                                                  b_predMV.x, b_predMV.y,                         /* center is b-prediction */                          gmcminSAD = gmcSAD;
3018                                                  frame->motion_flags,                          direction = 1;
                                                 frame->quant, frame->bcode, pParam,  
                                                 b_mbs, b_mbs,  
                                                 &mb->b_mvs[0], &pmv_dontcare);  
   
                         i_sad16 =  
                                 sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 i, j, 16, &mb->mvs[0], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 i, j, 16, &mb->b_mvs[0], edged_width),  
                                                   edged_width);  
                     i_sad16 += calc_delta_16(mb->mvs[0].x-f_predMV.x, mb->mvs[0].y-f_predMV.y,  
                                                                 frame->fcode, frame->quant);  
                     i_sad16 += calc_delta_16(mb->b_mvs[0].x-b_predMV.x, mb->b_mvs[0].y-b_predMV.y,  
                                                                 frame->bcode, frame->quant);  
   
                         get_range(&f_min_dx, &f_max_dx, &f_min_dy, &f_max_dy, i, j, 16, iWidth, iHeight,  
                           frame->fcode);  
                         get_range(&b_min_dx, &b_max_dx, &b_min_dy, &b_max_dy, i, j, 16, iWidth, iHeight,  
                           frame->bcode);  
   
 /* Interpolated MC motion vector search, this is tedious and more complicated because there are  
    two values for everything, always one for backward and one for forward ME. Still, we don't gain  
    much from this search, maybe it should simply be skipped and simply current i_sad16 value used  
    as "optimal". */  
   
                         i_sad16 = Diamond16_InterpolMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i * 16 + j * 16 * edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 mb->mvs[0].x, mb->mvs[0].y,  
                                                 mb->b_mvs[0].x, mb->b_mvs[0].y,  
                                                 i_sad16,  
                                                 &f_interpolMV, &b_interpolMV,  
                                                 f_predMV.x, f_predMV.y, b_predMV.x, b_predMV.y,  
                                                 f_min_dx, f_max_dx, f_min_dy, f_max_dy,  
                                                 b_min_dx, b_max_dx, b_min_dy, b_max_dy,  
                                                 edged_width,  2,  
                                                 frame->fcode, frame->bcode,frame->quant,0);  
   
                         i_sad16 = Diamond16_InterpolMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i * 16 + j * 16 * edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 f_interpolMV.x, f_interpolMV.y,  
                                                 b_interpolMV.x, b_interpolMV.y,  
                                                 i_sad16,  
                                                 &f_interpolMV, &b_interpolMV,  
                                                 f_predMV.x, f_predMV.y, b_predMV.x, b_predMV.y,  
                                                 f_min_dx, f_max_dx, f_min_dy, f_max_dy,  
                                                 b_min_dx, b_max_dx, b_min_dy, b_max_dy,  
                                                 edged_width,  1,  
                                                 frame->fcode, frame->bcode,frame->quant,0);             // equiv to halfpel refine  
   
   
 /*  DIRECT MODE DELTA VECTOR SEARCH.  
     This has to be made more effective, but at the moment I'm happy it's running at all */  
   
 /* There are two range restrictions for direct mode: deltaMV is limited to [-32,31] in halfpel units, and  
    absolute vector must not lie outside of image dimensions. Constraint one is dealt with by CHECK_MV16_DIRECT  
    and for constraint two we need distance to boundary. This is done by get_range very large fcode (hack!) */  
   
                         get_range(&min_dx, &max_dx, &min_dy, &max_dy, i, j, 16, iWidth, iHeight, 19);  
   
                         d_sad16 = Diamond16_DirectMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i*16 + j*16*edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 TRB,TRD,  
                                                 0,0,  
                                                 d_sad16,  
                                                 &mb->deltamv,  
                                                 mb->directmv, // this has to be pre-initialized with b_mb->mvs[]  
                                         min_dx, max_dx, min_dy, max_dy,  
                                                 edged_width, 2, frame->quant, 0);  
   
                         d_sad16 = Diamond16_DirectMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i*16 + j*16*edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 TRB,TRD,  
                                                 mb->deltamv.x, mb->deltamv.y,  
                                                 d_sad16,  
                                                 &mb->deltamv,  
                                                 mb->directmv, // this has to be pre-initialized with b_mb->mvs[]  
                                         min_dx, max_dx, min_dy, max_dy,  
                                                 edged_width, 1, frame->quant, 0);               // equiv to halfpel refine  
   
   
 //                      i_sad16 = 65535;                /* remove the comment to disable any of the MODEs */  
 //                      f_sad16 = 65535;  
 //                      b_sad16 = 65535;  
 //                      d_sad16 = 65535;  
   
                         if (f_sad16 < b_sad16) {  
                                 best_sad = f_sad16;  
                                 mb->mode = MODE_FORWARD;  
                         } else {  
                                 best_sad = b_sad16;  
                                 mb->mode = MODE_BACKWARD;  
3019                          }                          }
3020                    else
3021                          if (i_sad16 < best_sad) {                  {
3022                                  best_sad = i_sad16;                  currwp = centerwp; currwp.duv[0].x++;
3023                                  mb->mode = MODE_INTERPOLATE;                  gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3024                    if (gmcSAD < gmcminSAD)
3025                    {       bestwp = currwp;
3026                            gmcminSAD = gmcSAD;
3027                            direction = 2;
3028                    }
3029                    }
3030                    if (direction) continue;
3031    
3032                    currwp = centerwp; currwp.duv[0].y--;
3033                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3034                    if (gmcSAD < gmcminSAD)
3035                    {       bestwp = currwp;
3036                            gmcminSAD = gmcSAD;
3037                            direction = 4;
3038                          }                          }
3039                    else
                         if (d_sad16 < best_sad) {  
   
                                 if (b_mb->mode == MODE_INTER4V)  
3040                                  {                                  {
3041                    currwp = centerwp; currwp.duv[0].y++;
3042                                  /* how to calc vectors is defined in standard. mvs[] and b_mvs[] are only for motion compensation */                  gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3043                                  /* for the bitstream, the value mb->deltamv is read directly */                  if (gmcSAD < gmcminSAD)
3044                    {       bestwp = currwp;
3045                              for (k = 0; k < 4; k++) {                          gmcminSAD = gmcSAD;
3046                            direction = 8;
3047                                                  mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);                  }
3048                              mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)                  }
3049                                                                                          ? ((TRB - TRD) * mb->directmv[k].x) / TRD                  if (direction) continue;
3050                                                      : mb->mvs[k].x - mb->directmv[k].x);  
3051                    currwp = centerwp; currwp.duv[1].x++;
3052                              mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);                  gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3053                          mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)                  if (gmcSAD < gmcminSAD)
3054                                                                                          ? ((TRB - TRD) * mb->directmv[k].y) / TRD                  {       bestwp = currwp;
3055                                              : mb->mvs[k].y - mb->directmv[k].y);                          gmcminSAD = gmcSAD;
3056                            direction = 32;
3057                    }
3058                    currwp.duv[2].y++;
3059                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3060                    if (gmcSAD < gmcminSAD)
3061                    {       bestwp = currwp;
3062                            gmcminSAD = gmcSAD;
3063                            direction = 1024;
3064                    }
3065    
3066                    currwp = centerwp; currwp.duv[1].x--;
3067                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3068                    if (gmcSAD < gmcminSAD)
3069                    {       bestwp = currwp;
3070                            gmcminSAD = gmcSAD;
3071                            direction = 16;
3072                    }
3073                    else
3074                    {
3075                    currwp = centerwp; currwp.duv[1].x++;
3076                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3077                    if (gmcSAD < gmcminSAD)
3078                    {       bestwp = currwp;
3079                            gmcminSAD = gmcSAD;
3080                            direction = 32;
3081                    }
3082                    }
3083                    if (direction) continue;
3084    
3085    
3086                    currwp = centerwp; currwp.duv[1].y--;
3087                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3088                    if (gmcSAD < gmcminSAD)
3089                    {       bestwp = currwp;
3090                            gmcminSAD = gmcSAD;
3091                            direction = 64;
3092                                          }                                          }
3093                    else
3094                    {
3095                    currwp = centerwp; currwp.duv[1].y++;
3096                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3097                    if (gmcSAD < gmcminSAD)
3098                    {       bestwp = currwp;
3099                            gmcminSAD = gmcSAD;
3100                            direction = 128;
3101                    }
3102                    }
3103                    if (direction) continue;
3104    
3105                    currwp = centerwp; currwp.duv[2].x--;
3106                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3107                    if (gmcSAD < gmcminSAD)
3108                    {       bestwp = currwp;
3109                            gmcminSAD = gmcSAD;
3110                            direction = 256;
3111                    }
3112                    else
3113                    {
3114                    currwp = centerwp; currwp.duv[2].x++;
3115                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3116                    if (gmcSAD < gmcminSAD)
3117                    {       bestwp = currwp;
3118                            gmcminSAD = gmcSAD;
3119                            direction = 512;
3120                    }
3121                    }
3122                    if (direction) continue;
3123    
3124                    currwp = centerwp; currwp.duv[2].y--;
3125                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3126                    if (gmcSAD < gmcminSAD)
3127                    {       bestwp = currwp;
3128                            gmcminSAD = gmcSAD;
3129                            direction = 1024;
3130                                  }                                  }
3131                                  else                                  else
3132                                  {                                  {
3133                                          mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);                  currwp = centerwp; currwp.duv[2].y++;
3134                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3135                    if (gmcSAD < gmcminSAD)
3136                    {       bestwp = currwp;
3137                            gmcminSAD = gmcSAD;
3138                            direction = 2048;
3139                    }
3140                    }
3141            } while (direction);
3142            free(GMCblock);
3143    
3144                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)          *startwp = bestwp;
                                                                                 ? ((TRB - TRD) * mb->directmv[0].x) / TRD  
                                         : mb->mvs[0].x - mb->directmv[0].x);  
3145    
3146                              mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);          return gmcminSAD;
3147    }
3148    
3149                          mb->b_mvs[0].y = (int32_t) ((mb->deltamv.y == 0)  int
3150                                                                                  ? ((TRB - TRD) * mb->directmv[0].y) / TRD  globalSAD(const WARPPOINTS *const wp,
3151                                              : mb->mvs[0].y - mb->directmv[0].y);                    const MBParam * const pParam,
3152                      const MACROBLOCK * const pMBs,
3153                      const FRAMEINFO * const current,
3154                      const IMAGE * const pRef,
3155                      const IMAGE * const pCurr,
3156                      uint8_t *const GMCblock)
3157    {
3158            NEW_GMC_DATA gmc_data;
3159            int iSAD, gmcSAD=0;
3160            int num=0;
3161            unsigned int mx, my;
3162    
3163                                          mb->mvs[3] = mb->mvs[2] = mb->mvs[1] = mb->mvs[0];          generate_GMCparameters( 3, 3, wp, pParam->width, pParam->height, &gmc_data);
                                         mb->b_mvs[3] = mb->b_mvs[2] = mb->b_mvs[1] = mb->b_mvs[0];  
                 }  
3164    
3165                                  best_sad = d_sad16;          for (my = 0; my < (uint32_t)pParam->mb_height; my++)
3166                                  mb->mode = MODE_DIRECT;                  for (mx = 0; mx < (uint32_t)pParam->mb_width; mx++) {
                         }  
3167    
3168                          switch (mb->mode)                  const int mbnum = mx + my * pParam->mb_width;
3169                          {                  const int iEdgedWidth = pParam->edged_width;
                                 case MODE_FORWARD:  
                                         f_count++;  
                                         f_predMV = mb->mvs[0];  
                                         break;  
                                 case MODE_BACKWARD:  
                                         b_count++;  
                                         b_predMV = mb->b_mvs[0];  
3170    
3171                                          break;                  if (!pMBs[mbnum].mcsel)
3172                                  case MODE_INTERPOLATE:                          continue;
                                         i_count++;  
                                         mb->mvs[0] = f_interpolMV;  
                                         mb->b_mvs[0] = b_interpolMV;  
                                         f_predMV = mb->mvs[0];  
                                         b_predMV = mb->b_mvs[0];  
                                         break;  
                                 case MODE_DIRECT:  
                                         d_count++;  
                                         break;  
                                 default:  
                                         break;  
                         }  
3173    
3174                    gmc_data.predict_16x16(&gmc_data, GMCblock,
3175                                                    pRef->y,
3176                                                    iEdgedWidth,
3177                                                    iEdgedWidth,
3178                                                    mx, my,
3179                                                    pParam->m_rounding_type);
3180    
3181                    iSAD = sad16 ( pCurr->y + 16*(my*iEdgedWidth + mx),
3182                                                    GMCblock , iEdgedWidth, 65536);
3183                    iSAD -= pMBs[mbnum].sad16;
3184    
3185                    if (iSAD<0)
3186                            gmcSAD += iSAD;
3187                    num++;
3188                  }                  }
3189            return gmcSAD;
3190          }          }
3191    
 #ifdef _DEBUG_BFRAME_STAT  
         fprintf(stderr,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d\n",  
                                 f_count,b_count,i_count,d_count);  
 #endif  
   
 }  

Legend:
Removed from v.370  
changed lines
  Added in v.1084

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