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

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

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

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

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

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