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

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

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

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

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

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