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

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