[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 347, Sun Jul 28 13:06:46 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.  
  *  
  *  Michael Militzer <isibaar@videocoding.de>  
25   *   *
26   **************************************************************************/   ****************************************************************************/
27    
28  #include <assert.h>  #include <assert.h>
29  #include <stdio.h>  #include <stdio.h>
30  #include <stdlib.h>  #include <stdlib.h>
31    #include <string.h>     /* memcpy */
32    #include <math.h>       /* lrint */
33    
34  #include "../encoder.h"  #include "../encoder.h"
35  #include "../utils/mbfunctions.h"  #include "../utils/mbfunctions.h"
36  #include "../prediction/mbprediction.h"  #include "../prediction/mbprediction.h"
37  #include "../global.h"  #include "../global.h"
38  #include "../utils/timer.h"  #include "../utils/timer.h"
39    #include "../image/interpolate8x8.h"
40    #include "motion_est.h"
41  #include "motion.h"  #include "motion.h"
42  #include "sad.h"  #include "sad.h"
43    #include "gmc.h"
44    #include "../utils/emms.h"
45    #include "../dct/fdct.h"
46    
47    /*****************************************************************************
48     * Modified rounding tables -- declared in motion.h
49     * Original tables see ISO spec tables 7-6 -> 7-9
50     ****************************************************************************/
51    
52    const uint32_t roundtab[16] =
53    {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2 };
54    
55    /* K = 4 */
56    const uint32_t roundtab_76[16] =
57    { 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1 };
58    
59    /* K = 2 */
60    const uint32_t roundtab_78[8] =
61    { 0, 0, 1, 1, 0, 0, 0, 1  };
62    
63    /* K = 1 */
64    const uint32_t roundtab_79[4] =
65    { 0, 1, 0, 0 };
66    
67    #define INITIAL_SKIP_THRESH     (10)
68    #define FINAL_SKIP_THRESH       (50)
69    #define MAX_SAD00_FOR_SKIP      (20)
70    #define MAX_CHROMA_SAD_FOR_SKIP (22)
71    
72    #define CHECK_CANDIDATE(X,Y,D) { \
73    CheckCandidate((X),(Y), (D), &iDirection, data ); }
74    
75    
76    /*****************************************************************************
77     * Code
78     ****************************************************************************/
79    
80    static __inline uint32_t
81    d_mv_bits(int x, int y, const VECTOR pred, const uint32_t iFcode, const int qpel, const int rrv)
82    {
83            int bits;
84            const int q = (1 << (iFcode - 1)) - 1;
85    
86            x <<= qpel;
87  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;
217    
218          static const VECTOR zeroMV = { 0, 0 };          ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
219          VECTOR predMV;          ref1 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
220            switch( ((x&1)<<1) + (y&1) ) {
221          int32_t x, y;          case 3: /* x and y in qpel resolution - the "corners" (top left/right and */
222          int32_t iIntra = 0;                          /* bottom left/right) during qpel refinement */
223          VECTOR pmv;                  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          if (sadInit)          case 1: /* x halfpel, y qpel - top or bottom during qpel refinement */
233                  (*sadInit) ();                  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          for (y = 0; y < iHcount; y++)   {          case 2: /* x qpel, y halfpel - left or right during qpel refinement */
239                  for (x = 0; x < iWcount; x ++)  {                  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                          MACROBLOCK *const pMB = &pMBs[x + y * iWcount];          default: /* pure halfpel position */
245                    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                  CHECK_MV16_DIRECT_FOUND(backupMV.x - iDiamondSize, backupMV.y);          if ( (x > data->max_dx) || (x < data->min_dx)
750                  CHECK_MV16_DIRECT_FOUND(backupMV.x + iDiamondSize, backupMV.y);                  || (y > data->max_dy) || (y < data->min_dy) ) return;
                 CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y - iDiamondSize);  
                 CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y + iDiamondSize);  
751    
752          } while (!iFound);          if (!data->qpel_precision) {
753                    ptr = GetReference(x, y, data);
754                    current = data->currentMV;
755            } else { /* x and y are in 1/4 precision */
756                    ptr = Interpolate8x8qpel(x, y, 0, 0, data);
757                    current = data->currentQMV;
758            }
759    
760            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                          }                          }
859                  }                  }
                 while (1);                              //forever  
         }  
         return iMinSAD;  
 }  
860    
861    static void
862    SquareSearch(int x, int y, const SearchData * const data, int bDirection)
863    {
864            int iDirection;
865    
866  int32_t          do {
867  Full8_MainSearch(const uint8_t * const pRef,                  iDirection = 0;
868                                   const uint8_t * const pRefH,                  if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);
869                                   const uint8_t * const pRefV,                  if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);
870                                   const uint8_t * const pRefHV,                  if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);
871                                   const uint8_t * const cur,                  if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128);
872                                   const int x,                  if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64);
873                                   const int y,                  if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128);
874                             const int start_x,                  if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128);
875                             const int start_y,                  if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128);
                            int iMinSAD,  
                            VECTOR * const currMV,  
                            const int center_x,  
                            const int center_y,  
                                  const int32_t min_dx,  
                                  const int32_t max_dx,  
                                  const int32_t min_dy,  
                                  const int32_t max_dy,  
                                  const int32_t iEdgedWidth,  
                                  const int32_t iDiamondSize,  
                                  const int32_t iFcode,  
                                  const int32_t iQuant,  
                                  int iFound)  
 {  
         int32_t iSAD;  
         int32_t dx, dy;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV8_CANDIDATE(dx, dy);  
876    
877          return iMinSAD;                  bDirection = iDirection;
878                    x = data->currentMV->x; y = data->currentMV->y;
879            } while (iDirection);
880  }  }
881    
882  Halfpel8_RefineFuncPtr Halfpel8_Refine;  static void
883    DiamondSearch(int x, int y, const SearchData * const data, int bDirection)
 int32_t  
 Halfpel16_Refine(const uint8_t * const pRef,  
                                  const uint8_t * const pRefH,  
                                  const uint8_t * const pRefV,  
                                  const uint8_t * const pRefHV,  
                                  const uint8_t * const cur,  
                                  const int x,  
                                  const int y,  
                                  VECTOR * const currMV,  
                                  int32_t iMinSAD,  
                            const int center_x,  
                            const int center_y,  
                                  const int32_t min_dx,  
                                  const int32_t max_dx,  
                                  const int32_t min_dy,  
                                  const int32_t max_dy,  
                                  const int32_t iFcode,  
                                  const int32_t iQuant,  
                                  const int32_t iEdgedWidth)  
884  {  {
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
885    
886          int32_t iSAD;  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
887          VECTOR backupMV = *currMV;  
888            int iDirection;
889    
890            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          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y - 1);                  /* now we're doing diagonal checks near our candidate */
         CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y - 1);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y - 1);  
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y + 1);  
         CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y + 1);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y + 1);  
898    
899          return iMinSAD;                  if (iDirection) {               /* checking if anything found */
900                            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  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)  /* MAINSEARCH FUNCTIONS END */
918    
919    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            CHECK_CANDIDATE(centerMV.x, centerMV.y - 1, 0);
927            CHECK_CANDIDATE(centerMV.x + 1, centerMV.y - 1, 0);
928            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    static __inline int
937    SkipDecisionP(const IMAGE * current, const IMAGE * reference,
938                                                            const int x, const int y,
939                                                            const uint32_t stride, const uint32_t iQuant, int rrv)
940    
 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)  
941  {  {
942          const uint32_t iWcount = pParam->mb_width;          int offset = (x + y*stride)*8;
943          const int32_t iWidth = pParam->width;          if(!rrv) {
944          const int32_t iHeight = pParam->height;                  uint32_t sadC = sad8(current->u + offset,
945          const int32_t iEdgedWidth = pParam->edged_width;                                                  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          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          } else {
953                    uint32_t sadC = sad16(current->u + 2*offset,
954                                                    reference->u + 2*offset, stride, 256*4096);
955                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
956                    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          int32_t iDiamondSize;  static __inline void
964    ZeroMacroblockP(MACROBLOCK *pMB, const int32_t sad)
965    {
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          int32_t min_dx;  static __inline void
973          int32_t max_dx;  ModeDecision(SearchData * const Data,
974          int32_t min_dy;                          MACROBLOCK * const pMB,
975          int32_t max_dy;                          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 {
1003                            mode = MODE_INTER4V;
1004                            sad = Data->iMinSAD[1] + Data->iMinSAD[2] +
1005                                                    Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant;
1006                            Data->iMinSAD[0] = sad;
1007                    }
1008    
1009          int32_t iFound;                  /* 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                            if ( (100*sad)/(pMB->sad16+1) > FINAL_SKIP_THRESH)
1012                                    if (Data->chroma || SkipDecisionP(pCurrent, pRef, x, y, Data->iEdgedWidth/2, iQuant, Data->rrv)) {
1013                                            mode = MODE_NOT_CODED;
1014                                            sad = 0;
1015                                    }
1016    
1017          VECTOR newMV;                  /* mcsel */
1018          VECTOR backupMV;                        /* just for PMVFAST */                  if (coding_type == S_VOP) {
1019    
1020          VECTOR pmv[4];                          int32_t iSAD = sad16(Data->Cur,
1021          int32_t psad[4];                                  vGMC->y + 16*y*Data->iEdgedWidth + 16*x, Data->iEdgedWidth, 65536);
1022    
1023          MainSearch16FuncPtr MainSearchPtr;                          if (Data->chroma) {
1024                                    iSAD += sad8(Data->CurU, vGMC->u + 8*y*(Data->iEdgedWidth/2) + 8*x, Data->iEdgedWidth/2);
1025                                    iSAD += sad8(Data->CurV, vGMC->v + 8*y*(Data->iEdgedWidth/2) + 8*x, Data->iEdgedWidth/2);
1026                            }
1027    
1028          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;                          if (iSAD <= sad) {              /* mode decision GMC */
1029                                    mode = MODE_INTER;
1030                                    mcsel = 1;
1031                                    sad = iSAD;
1032                            }
1033    
1034          int32_t threshA, threshB;                  }
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD;  
1035    
1036  /* Get maximum range */                  /* intra decision */
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
1037    
1038  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */                  if (iQuant > 8) InterBias += 100 * (iQuant - 8); /* to make high quants work */
1039                    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          if (!(MotionFlags & PMV_HALFPEL16)) {                  if (Data->chroma) InterBias += 50; /* dev8(chroma) ??? <-- yes, we need dev8 (no big difference though) */
1045                  min_dx = EVEN(min_dx);                  if (Data->rrv) InterBias *= 4;
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
         }  
1046    
1047          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */                  if (InterBias < sad) {
1048          //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);                          int32_t deviation;
1049          bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);                          if (!Data->rrv)
1050                                    deviation = dev16(Data->Cur, Data->iEdgedWidth);
1051                            else
1052                                    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 ((x == 0) && (y == 0)) {                          if (deviation < (sad - InterBias)) mode = MODE_INTRA;
                 threshA = 512;  
                 threshB = 1024;  
         } else {  
                 threshA = psad[0];  
                 threshB = threshA + 256;  
                 if (threshA < 512)  
                         threshA = 512;  
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
1058          }          }
1059    
1060          iFound = 0;                  pMB->cbp = 63;
1061                    pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
 /* 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.  
 */  
1062    
1063          currMV->x = start_x;          } else { /* Rate-Distortion */
         currMV->y = start_y;  
1064    
1065          if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */                  int min_rd, intra_rd, i, cbp, c[2] = {0, 0};
1066                  currMV->x = EVEN(currMV->x);                  VECTOR backup[5], *v;
1067                  currMV->y = EVEN(currMV->y);                  Data->iQuant = iQuant;
1068          }                  Data->cbp = c;
1069    
1070          if (currMV->x > max_dx) {                  v = Data->qpel ? Data->currentQMV : Data->currentMV;
1071                  currMV->x = max_dx;                  for (i = 0; i < 5; i++) {
1072          }                          Data->iMinSAD[i] = 256*4096;
1073          if (currMV->x < min_dx) {                          backup[i] = v[i];
                 currMV->x = min_dx;  
         }  
         if (currMV->y > max_dy) {  
                 currMV->y = max_dy;  
         }  
         if (currMV->y < min_dy) {  
                 currMV->y = min_dy;  
1074          }          }
1075    
1076          iMinSAD =                  min_rd = findRDinter(Data, pMBs, x, y, pParam, MotionFlags);
1077                  sad16(cur,                  cbp = *Data->cbp;
                           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);  
1078    
1079          if ((iMinSAD < 256) ||                  if (coding_type == S_VOP) {
1080                  ((MVequal(*currMV, prevMB->mvs[0])) &&                          int gmc_rd;
1081                   ((int32_t) iMinSAD < prevMB->sad16))) {                          *Data->iMinSAD = min_rd += BITS_MULT*1; /* mcsel */
1082                  if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode                          gmc_rd = findRDgmc(Data, vGMC, x, y);
1083                  {                          if (gmc_rd < min_rd) {
1084                          if (!MVzero(*currMV)) {                                  mcsel = 1;
1085                                  iMinSAD += MV16_00_BIAS;                                  *Data->iMinSAD = min_rd = gmc_rd;
1086                                  CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures                                  mode = MODE_INTER;
1087                                  iMinSAD -= MV16_00_BIAS;                                  cbp = *Data->cbp;
1088                          }                          }
1089                  }                  }
1090    
1091                  if (MotionFlags & PMV_QUICKSTOP16)                  if (inter4v) {
1092                          goto PMVfast16_Terminate_without_Refine;                          int v4_rd;
1093                  if (MotionFlags & PMV_EARLYSTOP16)                          v4_rd = findRDinter4v(Data, pMB, pMBs, x, y, pParam, MotionFlags, backup);
1094                          goto PMVfast16_Terminate_with_Refine;                          if (v4_rd < min_rd) {
1095                                    Data->iMinSAD[0] = min_rd = v4_rd;
1096                                    mode = MODE_INTER4V;
1097                                    cbp = *Data->cbp;
1098                            }
1099          }          }
1100    
1101                    intra_rd = findRDintra(Data);
1102                    if (intra_rd < min_rd) {
1103                            *Data->iMinSAD = min_rd = intra_rd;
1104                            mode = MODE_INTRA;
1105                    }
1106    
1107  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = 0;
1108     vector of the median.                  pMB->cbp = cbp;
1109     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2          }
 */  
1110    
1111          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[0])))          if (Data->rrv) {
1112                  iFound = 2;                          Data->currentMV[0].x = RRV_MV_SCALEDOWN(Data->currentMV[0].x);
1113                            Data->currentMV[0].y = RRV_MV_SCALEDOWN(Data->currentMV[0].y);
1114            }
1115    
1116  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          if (mode == MODE_INTER && mcsel == 0) {
1117     Otherwise select large Diamond Search.                  pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
 */  
1118    
1119          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))                  if(Data->qpel) {
1120                  iDiamondSize = 1;               // halfpel!                          pMB->qmvs[0] = pMB->qmvs[1]
1121          else                                  = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1122                  iDiamondSize = 2;               // halfpel!                          pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1123                            pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;
1124                    } else {
1125                            pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1126                            pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
1127                    }
1128    
1129          if (!(MotionFlags & PMV_HALFPELDIAMOND16))          } else if (mode == MODE_INTER ) { // but mcsel == 1
                 iDiamondSize *= 2;  
1130    
1131  /*                  pMB->mcsel = 1;
1132     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.                  if (Data->qpel) {
1133     Also calculate (0,0) but do not subtract offset.                          pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] = pMB->qmvs[3] = pMB->amv;
1134     Let MinSAD be the smallest SAD up to this point.                          pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = pMB->amv.x/2;
1135     If MV is (0,0) subtract offset.                          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  // (0,0) is always possible          pMB->mode = mode;
1145    }
1146    
1147          if (!MVzero(pmv[0]))  bool
1148                  CHECK_MV16_ZERO;  MotionEstimation(MBParam * const pParam,
1149                                     FRAMEINFO * const current,
1150                                     FRAMEINFO * const reference,
1151                                     const IMAGE * const pRefH,
1152                                     const IMAGE * const pRefV,
1153                                     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  // previous frame MV is always possible          uint32_t mb_width = pParam->mb_width;
1162            uint32_t mb_height = pParam->mb_height;
1163            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 (!MVzero(prevMB->mvs[0]))                          if ((current->vop_flags & XVID_VOP_CARTOON) &&
1239                  if (!MVequal(prevMB->mvs[0], pmv[0]))                                  (sad00 < pMB->quant * 4 * skip_thresh)) { /* favorize (0,0) vector for cartoons */
1240                          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);                                  ZeroMacroblockP(pMB, sad00);
1241                                    continue;
1242                            }
1243    
1244  // left neighbour, if allowed                          SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1245                                            y, MotionFlags, current->vop_flags, current->vol_flags,
1246                                            &Data, pParam, pMBs, reference->mbs, pMB);
1247    
1248                            ModeDecision(&Data, pMB, pMBs, x, y, pParam,
1249                                                     MotionFlags, current->vop_flags, current->vol_flags,
1250                                                     pCurrent, pRef, pGMC, current->coding_type);
1251    
1252          if (!MVzero(pmv[1]))                          if (pMB->mode == MODE_INTRA)
1253                  if (!MVequal(pmv[1], prevMB->mvs[0]))                                  if (++iIntra > iLimit) return 1;
                         if (!MVequal(pmv[1], pmv[0])) {  
                                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                                         pmv[1].x = EVEN(pmv[1].x);  
                                         pmv[1].y = EVEN(pmv[1].y);  
1254                                  }                                  }
   
                                 CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
1255                          }                          }
1256  // top neighbour, if allowed  
1257          if (!MVzero(pmv[2]))          return 0;
                 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);  
1258                                          }                                          }
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
1259    
1260  // top right neighbour, if allowed  
1261                                          if (!MVzero(pmv[3]))  static __inline int
1262                                                  if (!MVequal(pmv[3], prevMB->mvs[0]))  make_mask(const VECTOR * const pmv, const int i)
1263                                                          if (!MVequal(pmv[3], pmv[0]))  {
1264                                                                  if (!MVequal(pmv[3], pmv[1]))          int mask = 255, j;
1265                                                                          if (!MVequal(pmv[3], pmv[2])) {          for (j = 0; j < i; j++) {
1266                                                                                  if (!(MotionFlags & PMV_HALFPEL16)) {                  if (MVequal(pmv[i], pmv[j])) return 0; /* same vector has been checked already */
1267                                                                                          pmv[3].x = EVEN(pmv[3].x);                  if (pmv[i].x == pmv[j].x) {
1268                                                                                          pmv[3].y = EVEN(pmv[3].y);                          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                                                                                  }                                                                                  }
                                                                                 CHECK_MV16_CANDIDATE(pmv[3].x,  
                                                                                                                          pmv[3].y);  
1275                                                                          }                                                                          }
1276            return mask;
1277                                  }                                  }
1278    
1279          if ((MVzero(*currMV)) &&  static __inline void
1280                  (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  PreparePredictionsP(VECTOR * const pmv, int x, int y, int iWcount,
1281                  iMinSAD -= MV16_00_BIAS;                          int iHcount, const MACROBLOCK * const prevMB, int rrv)
1282    {
1283            /* this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself */
1284            if (rrv) { iWcount /= 2; iHcount /= 2; }
1285    
1286            if ( (y != 0) && (x < (iWcount-1)) ) {          /* [5] top-right neighbour */
1287                    pmv[5].x = EVEN(pmv[3].x);
1288                    pmv[5].y = EVEN(pmv[3].y);
1289            } else pmv[5].x = pmv[5].y = 0;
1290    
1291  /* Step 6: If MinSAD <= thresa goto Step 10.          if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }/* pmv[3] is left neighbour */
1292     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.          else pmv[3].x = pmv[3].y = 0;
 */  
1293    
1294          if ((iMinSAD <= threshA) ||          if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }/* [4] top neighbour */
1295                  (MVequal(*currMV, prevMB->mvs[0]) &&          else pmv[4].x = pmv[4].y = 0;
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
         }  
1296    
1297            /* [1] median prediction */
1298            pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
1299    
1300  /************ (Diamond Search)  **************/          pmv[0].x = pmv[0].y = 0; /* [0] is zero; not used in the loop (checked before) but needed here for make_mask */
 /*  
    Step 7: Perform Diamond search, with either the small or large diamond.  
    If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
    Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
    If center then goto step 10.  
    Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
    Refine by using small diamond and goto step 10.  
 */  
1301    
1302          if (MotionFlags & PMV_USESQUARES16)          pmv[2].x = EVEN(prevMB->mvs[0].x); /* [2] is last frame */
1303                  MainSearchPtr = Square16_MainSearch;          pmv[2].y = EVEN(prevMB->mvs[0].y);
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
1304    
1305          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          if ((x < iWcount-1) && (y < iHcount-1)) {
1306                    pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); /* [6] right-down neighbour in last frame */
1307                    pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
1308            } else pmv[6].x = pmv[6].y = 0;
1309    
1310            if (rrv) {
1311                    int i;
1312                    for (i = 0; i < 7; i++) {
1313                            pmv[i].x = RRV_MV_SCALEUP(pmv[i].x);
1314                            pmv[i].y = RRV_MV_SCALEUP(pmv[i].y);
1315                    }
1316            }
1317    }
1318    
1319  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  static void
1320          iSAD =  SearchP(const IMAGE * const pRef,
1321                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                  const uint8_t * const pRefH,
1322                                                    currMV->x, currMV->y, iMinSAD, &newMV, center_x, center_y,                  const uint8_t * const pRefV,
1323                                                    min_dx, max_dx,                  const uint8_t * const pRefHV,
1324                                                    min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,                  const IMAGE * const pCur,
1325                                                    iQuant, iFound);                  const int x,
1326                    const int y,
1327                    const uint32_t MotionFlags,
1328                    const uint32_t VopFlags,
1329                    const uint32_t VolFlags,
1330                    SearchData * const Data,
1331                    const MBParam * const pParam,
1332                    const MACROBLOCK * const pMBs,
1333                    const MACROBLOCK * const prevMBs,
1334                    MACROBLOCK * const pMB)
1335    {
1336    
1337          if (iSAD < iMinSAD) {          int i, iDirection = 255, mask, threshA;
1338                  *currMV = newMV;          VECTOR pmv[7];
1339                  iMinSAD = iSAD;          int inter4v = (VopFlags & XVID_VOP_INTER4V) && (pMB->dquant == 0);
1340          }  
1341            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
1342                                                    pParam->width, pParam->height, Data->iFcode - Data->qpel, 1, Data->rrv);
1343    
1344            get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);
1345    
1346            Data->temp[5] = Data->temp[6] = 0; /* chroma-sad cache */
1347            i = Data->rrv ? 2 : 1;
1348            Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16*i;
1349            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 (!Data->rrv) {
1386                    if (inter4v | Data->chroma) CheckCandidate = CheckCandidate16;
1387                            else CheckCandidate = CheckCandidate16no4v; /* for extra speed */
1388            } 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                    MainSearchFunc * MainSearchPtr;
1405                    if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1406                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1407                            else MainSearchPtr = DiamondSearch;
1408    
1409          if (MotionFlags & PMV_EXTSEARCH16) {                  MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
1410    
1411                  if (!(MVequal(pmv[0], backupMV))) {  /* extended search, diamond starting in 0,0 and in prediction.
1412                          iSAD =          note that this search is/might be done in halfpel positions,
1413                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,          which makes it more different than the diamond above */
                                                                   center_x, center_y, iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
1414    
1415                          if (iSAD < iMinSAD) {                  if (MotionFlags & XVID_ME_EXTSEARCH16) {
1416                                  *currMV = newMV;                          int32_t bSAD;
1417                                  iMinSAD = iSAD;                          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                                    CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1426                                    MainSearchPtr(startMV.x, startMV.y, Data, 255);
1427                                    if (bSAD < Data->iMinSAD[0]) {
1428                                            Data->currentMV[0] = backupMV;
1429                                            Data->iMinSAD[0] = bSAD; }
1430                  }                  }
1431    
1432                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                          backupMV = Data->currentMV[0];
1433                          iSAD =                          startMV.x = startMV.y = 1;
1434                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                          if (!(MVequal(startMV, backupMV))) {
1435                                                                    iMinSAD, &newMV, center_x, center_y,                                  bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
                                                                   min_dx, max_dx, min_dy, max_dy,  
                                                                   iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
1436    
1437                          if (iSAD < iMinSAD) {                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1438                                  *currMV = newMV;                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1439                                  iMinSAD = iSAD;                                  if (bSAD < Data->iMinSAD[0]) {
1440                                            Data->currentMV[0] = backupMV;
1441                                            Data->iMinSAD[0] = bSAD; }
1442                          }                          }
1443                  }                  }
1444          }          }
1445    
1446  /*          if (MotionFlags & XVID_ME_HALFPELREFINE16)
1447     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.                          SubpelRefine(Data);
 */  
1448    
1449    PMVfast16_Terminate_with_Refine:          for(i = 0; i < 5; i++) {
1450          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; /* initialize qpel vectors */
1451                  iMinSAD =                  Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
                         Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
   
   PMVfast16_Terminate_without_Refine:  
         currPMV->x = currMV->x - center_x;  
         currPMV->y = currMV->y - center_y;  
         return iMinSAD;  
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                    if ((Data->chroma) && (!(VopFlags & XVID_VOP_MODEDECISION_RD))) {
1475                            /* chroma is only used for comparsion to INTER. if the comparsion will be done in BITS domain, it will not be used */
1476                            int sumx = 0, sumy = 0;
1477    
1478  int32_t                          if (Data->qpel)
1479  Diamond8_MainSearch(const uint8_t * const pRef,                                  for (i = 1; i < 5; i++) {
1480                                          const uint8_t * const pRefH,                                          sumx += Data->currentQMV[i].x/2;
1481                                          const uint8_t * const pRefV,                                          sumy += Data->currentQMV[i].y/2;
1482                                          const uint8_t * const pRefHV,                                  }
1483                                          const uint8_t * const cur,                          else
1484                                          const int x,                                  for (i = 1; i < 5; i++) {
1485                                          const int y,                                          sumx += Data->currentMV[i].x;
1486                                          int32_t start_x,                                          sumy += Data->currentMV[i].y;
1487                                          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);  
1488    
1489          if (iDirection) {                          Data->iMinSAD[1] += ChromaSAD(  (sumx >> 3) + roundtab_76[sumx & 0xf],
1490                  while (!iFound) {                                                                                          (sumy >> 3) + roundtab_76[sumy & 0xf], Data);
                         iFound = 1;  
                         backupMV = *currMV;     // since iDirection!=0, this is well defined!  
                         iDirectionBackup = iDirection;  
   
                         if (iDirectionBackup != 2)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                   backupMV.y, 1);  
                         if (iDirectionBackup != 1)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                   backupMV.y, 2);  
                         if (iDirectionBackup != 4)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y - iDiamondSize, 3);  
                         if (iDirectionBackup != 3)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y + iDiamondSize, 4);  
1491                  }                  }
1492          } else {          } else Data->iMinSAD[1] = 4096*256;
                 currMV->x = start_x;  
                 currMV->y = start_y;  
1493          }          }
1494          return iMinSAD;  
1495    static void
1496    Search8(const SearchData * const OldData,
1497                    const int x, const int y,
1498                    const uint32_t MotionFlags,
1499                    const MBParam * const pParam,
1500                    MACROBLOCK * const pMB,
1501                    const MACROBLOCK * const pMBs,
1502                    const int block,
1503                    SearchData * const Data)
1504    {
1505            int i = 0;
1506            Data->iMinSAD = OldData->iMinSAD + 1 + block;
1507            Data->currentMV = OldData->currentMV + 1 + block;
1508            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            *(Data->iMinSAD) += (Data->lambda8 * i * (*Data->iMinSAD + NEIGH_8X8_BIAS))>>10;
1521    
1522            if (MotionFlags & (XVID_ME_EXTSEARCH8|XVID_ME_HALFPELREFINE8|XVID_ME_QUARTERPELREFINE8)) {
1523    
1524                    if (Data->rrv) i = 16; else i = 8;
1525    
1526  int32_t                  Data->RefP[0] = OldData->RefP[0] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1527  Square8_MainSearch(const uint8_t * const pRef,                  Data->RefP[1] = OldData->RefP[1] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1528                                          const uint8_t * const pRefH,                  Data->RefP[2] = OldData->RefP[2] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1529                                          const uint8_t * const pRefV,                  Data->RefP[3] = OldData->RefP[3] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x,  
                                         const int y,  
                                         int32_t start_x,  
                                         int32_t start_y,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a square search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* It's one search with full square pattern, and new parts for all following diamonds */  
   
 /*   new direction are extra, so 1-4 is normal diamond  
       537  
       1*2  
       648  
 */  
1530    
1531          CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);                  Data->Cur = OldData->Cur + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1532          CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);                  Data->qpel_precision = 0;
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
   
         CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 5);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 6);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 7);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 8);  
1533    
1534                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 3,
1535                                            pParam->width, pParam->height, Data->iFcode - Data->qpel, 1, Data->rrv);
1536    
1537          if (iDirection) {                  if (!Data->rrv) CheckCandidate = CheckCandidate8;
1538                  while (!iFound) {                  else CheckCandidate = CheckCandidate16no4v;
                         iFound = 1;  
                         backupMV = *currMV;  
1539    
1540                          switch (iDirection) {                  if (MotionFlags & XVID_ME_EXTSEARCH8 && (!(MotionFlags & XVID_ME_EXTSEARCH_RD))) {
1541                          case 1:                          int32_t temp_sad = *(Data->iMinSAD); /* store current MinSAD */
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                    backupMV.y, 1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
                         case 2:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
1542    
1543                          case 3:                          MainSearchFunc *MainSearchPtr;
1544                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                          if (MotionFlags & XVID_ME_USESQUARES8) MainSearchPtr = SquareSearch;
1545                                                                                   4);                                  else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1546                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                                          else MainSearchPtr = DiamondSearch;
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
1547    
1548                          case 4:                          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, 255);
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 break;  
   
                         case 5:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
   
                         case 6:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
   
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
1549    
1550                                  break;                          if(*(Data->iMinSAD) < temp_sad) {
1551                                            Data->currentQMV->x = 2 * Data->currentMV->x; /* update our qpel vector */
1552                                            Data->currentQMV->y = 2 * Data->currentMV->y;
1553                            }
1554                    }
1555    
1556                          case 7:                  if (MotionFlags & XVID_ME_HALFPELREFINE8) {
1557                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          int32_t temp_sad = *(Data->iMinSAD); /* store current MinSAD */
                                                                                    backupMV.y, 1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
1558    
1559                          case 8:                          SubpelRefine(Data); /* perform halfpel refine of current best vector */
1560                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
1561                                                                                   2);                          if(*(Data->iMinSAD) < temp_sad) { /* we have found a better match */
1562                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                                  Data->currentQMV->x = 2 * Data->currentMV->x; /* update our qpel vector */
1563                                                                                   4);                                  Data->currentQMV->y = 2 * Data->currentMV->y;
1564                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          }
1565                                                                                   backupMV.y + iDiamondSize, 6);                  }
1566                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
1567                                                                                   backupMV.y - iDiamondSize, 7);                  if (Data->qpel && MotionFlags & XVID_ME_QUARTERPELREFINE8) {
1568                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                                  Data->qpel_precision = 1;
1569                                                                                   backupMV.y + iDiamondSize, 8);                                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 3,
1570                                  break;                                          pParam->width, pParam->height, Data->iFcode, 2, 0);
1571                          default:                                  SubpelRefine(Data);
                                 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;  
1572                          }                          }
1573                  }                  }
1574    
1575            if (Data->rrv) {
1576                            Data->currentMV->x = RRV_MV_SCALEDOWN(Data->currentMV->x);
1577                            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                  currMV->x = start_x;                  pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1586                  currMV->y = start_y;                  pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
1587          }          }
1588          return iMinSAD;  
1589            pMB->mvs[block] = *Data->currentMV;
1590            pMB->sad8[block] = 4 * *Data->iMinSAD;
1591  }  }
1592    
1593    /* motion estimation for B-frames */
1594    
1595    static __inline VECTOR
1596    ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1597    {
1598    /* the stupidiest function ever */
1599            return (mode == MODE_FORWARD ? pMB->mvs[0] : pMB->b_mvs[0]);
1600    }
1601    
1602    static void __inline
1603    PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
1604                                                            const uint32_t iWcount,
1605                                                            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  int32_t          pmv[1].x = pmv[1].y = 0; /* [1] is zero */
 Halfpel8_Refine_c(const uint8_t * const pRef,  
                                 const uint8_t * const pRefH,  
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const uint8_t * const cur,  
                                 const int x,  
                                 const int y,  
                                 VECTOR * const currMV,  
                                 int32_t iMinSAD,  
                            const int center_x,  
                            const int center_y,  
                                 const int32_t min_dx,  
                                 const int32_t max_dx,  
                                 const int32_t min_dy,  
                                 const int32_t max_dy,  
                                 const int32_t iFcode,  
                                 const int32_t iQuant,  
                                 const int32_t iEdgedWidth)  
 {  
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
   
         int32_t iSAD;  
         VECTOR backupMV = *currMV;  
   
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y + 1);  
         CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y + 1);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y + 1);  
1613    
1614          return iMinSAD;          pmv[2] = ChoosePred(pMB, mode_curr);
1615  }          pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
1616    
1617            if ((y != 0)&&(x != (int)(iWcount+1))) {                        /* [3] top-right neighbour */
1618                    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            if (y != 0) {
1623                    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 (x != 0) {
1628                    pmv[5] = ChoosePred(pMB-1, mode_curr);
1629                    pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1630            } else pmv[5].x = pmv[5].y = 0;
1631    
1632            if (x != 0 && y != 0) {
1633                    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    
 #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)  
1638    
1639  int32_t  /* search backward or forward */
1640  PMVfastSearch8(const uint8_t * const pRef,  static void
1641    SearchBF(       const IMAGE * const pRef,
1642                             const uint8_t * const pRefH,                             const uint8_t * const pRefH,
1643                             const uint8_t * const pRefV,                             const uint8_t * const pRefV,
1644                             const uint8_t * const pRefHV,                             const uint8_t * const pRefHV,
1645                             const IMAGE * const pCur,                             const IMAGE * const pCur,
1646                             const int x,                          const int x, const int y,
                            const int y,  
                            const int start_x,  
                            const int start_y,  
                                 const int center_x,  
                                 const int center_y,  
1647                             const uint32_t MotionFlags,                             const uint32_t MotionFlags,
                            const uint32_t iQuant,  
1648                             const uint32_t iFcode,                             const uint32_t iFcode,
1649                             const MBParam * const pParam,                             const MBParam * const pParam,
1650                             const MACROBLOCK * const pMBs,                          MACROBLOCK * const pMB,
1651                             const MACROBLOCK * const prevMBs,                          const VECTOR * const predMV,
1652                             VECTOR * const currMV,                          int32_t * const best_sad,
1653                             VECTOR * const currPMV)                          const int32_t mode_current,
1654                            SearchData * const Data)
1655  {  {
         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;  
1656    
1657          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;          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          int32_t iDiamondSize;          Data->RefP[0] = pRef->y + (x + Data->iEdgedWidth*y) * 16;
1666            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          int32_t min_dx;          Data->predMV = *predMV;
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
1673    
1674          VECTOR pmv[4];          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
1675          int32_t psad[4];                                  pParam->width, pParam->height, iFcode - Data->qpel, 1, 0);
         VECTOR newMV;  
         VECTOR backupMV;  
         VECTOR startMV;  
1676    
1677  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          pmv[0] = Data->predMV;
1678          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;          if (Data->qpel) { pmv[0].x /= 2; pmv[0].y /= 2; }
1679    
1680           int32_t threshA, threshB;          PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);
         int32_t iFound, bPredEq;  
         int32_t iMinSAD, iSAD;  
1681    
1682          int32_t iSubBlock = (y & 1) + (y & 1) + (x & 1);          Data->currentMV->x = Data->currentMV->y = 0;
1683            CheckCandidate = CheckCandidate16no4v;
1684    
1685            /* main loop. checking all predictions */
1686            for (i = 0; i < 7; i++) {
1687                    if (!(mask = make_mask(pmv, i)) ) continue;
1688                    CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1689            }
1690    
1691          MainSearch8FuncPtr MainSearchPtr;          if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1692            else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1693                    else MainSearchPtr = DiamondSearch;
1694    
1695          /* Init variables */          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
         startMV.x = start_x;  
         startMV.y = start_y;  
1696    
1697          /* Get maximum range */          SubpelRefine(Data);
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,  
                           iFcode);  
1698    
1699          if (!(MotionFlags & PMV_HALFPELDIAMOND8)) {          if (Data->qpel && *Data->iMinSAD < *best_sad + 300) {
1700                  min_dx = EVEN(min_dx);                  Data->currentQMV->x = 2*Data->currentMV->x;
1701                  max_dx = EVEN(max_dx);                  Data->currentQMV->y = 2*Data->currentMV->y;
1702                  min_dy = EVEN(min_dy);                  Data->qpel_precision = 1;
1703                  max_dy = EVEN(max_dy);                  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          /* because we might use IF (dx>max_dx) THEN dx=max_dx; */          /* three bits are needed to code backward mode. four for forward */
         //bPredEq = get_pmvdata(pMBs, (x >> 1), (y >> 1), iWcount, iSubBlock, pmv, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, (x >> 1), (y >> 1), iSubBlock, pmv, psad);  
1709    
1710          if ((x == 0) && (y == 0)) {          if (mode_current == MODE_FORWARD) *Data->iMinSAD += 4 * Data->lambda16;
1711                  threshA = 512 / 4;          else *Data->iMinSAD += 3 * Data->lambda16;
                 threshB = 1024 / 4;  
1712    
1713            if (*Data->iMinSAD < *best_sad) {
1714                    *best_sad = *Data->iMinSAD;
1715                    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 {          } else {
1724                  threshA = psad[0] / 4;  /* good estimate? */                          pMB->pmvs[0].x = Data->currentMV->x - predMV->x;
1725                  threshB = threshA + 256 / 4;                          pMB->pmvs[0].y = Data->currentMV->y - predMV->y;
1726                  if (threshA < 512 / 4)                  }
1727                          threshA = 512 / 4;                  if (mode_current == MODE_FORWARD) pMB->mvs[0] = *Data->currentMV;
1728                  if (threshA > 1024 / 4)                  else pMB->b_mvs[0] = *Data->currentMV;
1729                          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.  
 */  
1730    
1731            if (mode_current == MODE_FORWARD) *(Data->currentMV+2) = *Data->currentMV;
1732            else *(Data->currentMV+1) = *Data->currentMV; /* we store currmv for interpolate search */
1733    }
1734    
1735    static void
1736    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  // Prepare for main loop          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 (MotionFlags & PMV_USESQUARES8)          if (sum < MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) {
1775        MainSearchPtr = Square8_MainSearch;                  pMB->mode = MODE_DIRECT_NONE_MV; /* skipped */
1776    else                  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          if (MotionFlags & PMV_ADVANCEDDIAMOND8)  static __inline uint32_t
1784                  MainSearchPtr = AdvDiamond8_MainSearch;  SearchDirect(const IMAGE * const f_Ref,
1785          else                                  const uint8_t * const f_RefH,
1786                  MainSearchPtr = Diamond8_MainSearch;                                  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            Data->referencemv = Data->qpel ? b_mb->qmvs : b_mb->mvs;
1828            Data->qpel_precision = 0;
1829    
1830          *currMV = startMV;          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          iMinSAD =                  if ( (pMB->b_mvs[k].x > Data->max_dx) | (pMB->b_mvs[k].x < Data->min_dx)
1837                  sad8(cur,                          | (pMB->b_mvs[k].y > Data->max_dy) | (pMB->b_mvs[k].y < Data->min_dy) ) {
                          get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  
                                                 iEdgedWidth), iEdgedWidth);  
         iMinSAD +=  
                 calc_delta_8(currMV->x - center_x, currMV->y - center_y,  
                                          (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256 / 4) || ((MVequal(*currMV, prevMB->mvs[iSubBlock]))  
                                                                 && ((int32_t) iMinSAD <  
                                                                         prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  
    vector of the median.  
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
1838    
1839          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[iSubBlock])))                          *best_sad = 256*4096; /* in that case, we won't use direct mode */
1840                  iFound = 2;                          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  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          CheckCandidate = b_mb->mode == MODE_INTER4V ? CheckCandidateDirect : CheckCandidateDirectno4v;
    Otherwise select large Diamond Search.  
 */  
1854    
1855          if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))          CheckCandidate(0, 0, 255, &k, Data);
                 iDiamondSize = 1;               // 1 halfpel!  
         else  
                 iDiamondSize = 2;               // 2 halfpel = 1 full pixel!  
1856    
1857          if (!(MotionFlags & PMV_HALFPELDIAMOND8))          /* initial (fast) skip decision */
1858                  iDiamondSize *= 2;          if (*Data->iMinSAD < pMB->quant * INITIAL_SKIP_THRESH * (Data->chroma?3:2)) {
1859                    /* possible skip */
1860                    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            *Data->iMinSAD += Data->lambda16;
1870            skip_sad = *Data->iMinSAD;
1871    
1872  /*  /*
1873     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.           * DIRECT MODE DELTA VECTOR SEARCH.
1874     Also calculate (0,0) but do not subtract offset.           * This has to be made more effective, but at the moment I'm happy it's running at all
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset.  
1875  */  */
1876    
1877  // the median prediction might be even better than mv16          if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1878                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1879                            else MainSearchPtr = DiamondSearch;
1880    
1881          if (!MVequal(pmv[0], startMV))          MainSearchPtr(0, 0, Data, 255);
                 CHECK_MV8_CANDIDATE(center_x, center_y);  
1882    
1883  // (0,0) if needed          SubpelRefine(Data);
         if (!MVzero(pmv[0]))  
                 if (!MVzero(startMV))  
                         CHECK_MV8_ZERO;  
   
 // previous frame MV if needed  
         if (!MVzero(prevMB->mvs[iSubBlock]))  
                 if (!MVequal(prevMB->mvs[iSubBlock], startMV))  
                         if (!MVequal(prevMB->mvs[iSubBlock], pmv[0]))  
                                 CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x,  
                                                                         prevMB->mvs[iSubBlock].y);  
   
         if ((iMinSAD <= threshA) ||  
                 (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&  
                  ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 // left neighbour, if allowed and needed  
         if (!MVzero(pmv[1]))  
                 if (!MVequal(pmv[1], startMV))  
                         if (!MVequal(pmv[1], prevMB->mvs[iSubBlock]))  
                                 if (!MVequal(pmv[1], pmv[0])) {  
                                         if (!(MotionFlags & PMV_HALFPEL8)) {  
                                                 pmv[1].x = EVEN(pmv[1].x);  
                                                 pmv[1].y = EVEN(pmv[1].y);  
                                         }  
                                         CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);  
                                 }  
 // top neighbour, if allowed and needed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], startMV))  
                         if (!MVequal(pmv[2], prevMB->mvs[iSubBlock]))  
                                 if (!MVequal(pmv[2], pmv[0]))  
                                         if (!MVequal(pmv[2], pmv[1])) {  
                                                 if (!(MotionFlags & PMV_HALFPEL8)) {  
                                                         pmv[2].x = EVEN(pmv[2].x);  
                                                         pmv[2].y = EVEN(pmv[2].y);  
                                                 }  
                                                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed and needed  
                                                 if (!MVzero(pmv[3]))  
                                                         if (!MVequal(pmv[3], startMV))  
                                                                 if (!MVequal(pmv[3], prevMB->mvs[iSubBlock]))  
                                                                         if (!MVequal(pmv[3], pmv[0]))  
                                                                                 if (!MVequal(pmv[3], pmv[1]))  
                                                                                         if (!MVequal(pmv[3], pmv[2])) {  
                                                                                                 if (!  
                                                                                                         (MotionFlags &  
                                                                                                          PMV_HALFPEL8)) {  
                                                                                                         pmv[3].x = EVEN(pmv[3].x);  
                                                                                                         pmv[3].y = EVEN(pmv[3].y);  
                                                                                                 }  
                                                                                                 CHECK_MV8_CANDIDATE(pmv[3].x,  
                                                                                                                                         pmv[3].y);  
                                                                                         }  
                                         }  
   
         if ((MVzero(*currMV)) &&  
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV8_00_BIAS;  
1884    
1885            *best_sad = *Data->iMinSAD;
1886    
1887  /* Step 6: If MinSAD <= thresa goto Step 10.          if (Data->qpel || b_mb->mode == MODE_INTER4V) pMB->mode = MODE_DIRECT;
1888     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.          else pMB->mode = MODE_DIRECT_NO4V; /* for faster compensation */
1889  */  
1890            pMB->pmvs[3] = *Data->currentMV;
1891    
1892          if ((iMinSAD <= threshA) ||          for (k = 0; k < 4; k++) {
1893                  (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&                  pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
1894                   ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {                  pMB->b_mvs[k].x = (     (Data->currentMV->x == 0)
1895                  if (MotionFlags & PMV_QUICKSTOP16)                                                          ? Data->directmvB[k].x
1896                          goto PMVfast8_Terminate_without_Refine;                                                          :pMB->mvs[k].x - Data->referencemv[k].x);
1897                  if (MotionFlags & PMV_EARLYSTOP16)                  pMB->mvs[k].y = (Data->directmvF[k].y + Data->currentMV->y);
1898                          goto PMVfast8_Terminate_with_Refine;                  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            return skip_sad;
1917    }
1918    
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  /************ (Diamond Search)  **************/  {
 /*  
    Step 7: Perform Diamond search, with either the small or large diamond.  
    If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
    Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
    If center then goto step 10.  
    Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
    Refine by using small diamond and goto step 10.  
 */  
1941    
1942          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          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  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, 255, &iDirection, fData);
         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);  
1984    
1985          if (iSAD < iMinSAD) {          /* diamond */
1986                  *currMV = newMV;          do {
1987                  iMinSAD = iSAD;                  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_EXTSEARCH8) {  void
2047  /* extended: search (up to) two more times: orignal prediction and (0,0) */  MotionEstimationBVOP(MBParam * const pParam,
2048                                             FRAMEINFO * const frame,
2049                                             const int32_t time_bp,
2050                                             const int32_t time_pp,
2051                                             /* forward (past) reference */
2052                                             const MACROBLOCK * const f_mbs,
2053                                             const IMAGE * const f_ref,
2054                                             const IMAGE * const f_refH,
2055                                             const IMAGE * const f_refV,
2056                                             const IMAGE * const f_refHV,
2057                                             /* backward (future) reference */
2058                                             const FRAMEINFO * const b_reference,
2059                                             const IMAGE * const b_ref,
2060                                             const IMAGE * const b_refH,
2061                                             const IMAGE * const b_refV,
2062                                             const IMAGE * const b_refHV)
2063    {
2064            uint32_t i, j;
2065            int32_t best_sad;
2066            uint32_t skip_sad;
2067            int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;
2068            const MACROBLOCK * const b_mbs = b_reference->mbs;
2069    
2070                  if (!(MVequal(pmv[0], backupMV))) {          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
                         iSAD =  
                                 (*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);  
2071    
2072                          if (iSAD < iMinSAD) {          const int32_t TRB = time_pp - time_bp;
2073                                  *currMV = newMV;          const int32_t TRD = time_pp;
                                 iMinSAD = iSAD;  
                         }  
                 }  
2074    
2075                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          /* some pre-inintialized data for the rest of the search */
                         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);  
2076    
2077                          if (iSAD < iMinSAD) {          SearchData Data;
2078                                  *currMV = newMV;          int32_t iMinSAD;
2079                                  iMinSAD = iSAD;          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  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.                          Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
2111     By performing an optional local half-pixel search, we can refine this result even further.                          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    PMVfast8_Terminate_with_Refine:                          if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
         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);  
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    PMVfast8_Terminate_without_Refine:                          /* backward search */
2139          currPMV->x = currMV->x - center_x;                          SearchBF(b_ref, b_refH->y, b_refV->y, b_refHV->y,
2140          currPMV->y = currMV->y - center_y;                                                  &frame->image, i, j,
2141                                                    frame->motion_flags,
2142                                                    frame->bcode, pParam,
2143                                                    pMB, &b_predMV, &best_sad,
2144                                                    MODE_BACKWARD, &Data);
2145    
2146                            /* interpolate search comes last, because it uses data from forward and backward as prediction */
2147                            SearchInterpolate(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2148                                                    b_ref, b_refH->y, b_refV->y, b_refHV->y,
2149                                                    &frame->image,
2150                                                    i, j,
2151                                                    frame->fcode, frame->bcode,
2152                                                    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          return iMinSAD;                          switch (pMB->mode) {
2164                                    case MODE_FORWARD:
2165                                            f_count++;
2166                                            f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2167                                            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                    }
2184            }
2185  }  }
2186    
2187  int32_t  static __inline void
2188  EPZSSearch16(const uint8_t * const pRef,  MEanalyzeMB (   const uint8_t * const pRef,
2189                           const uint8_t * const pRefH,                                  const uint8_t * const pCur,
                          const uint8_t * const pRefV,  
                          const uint8_t * const pRefHV,  
                          const IMAGE * const pCur,  
2190                           const int x,                           const int x,
2191                           const int y,                           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,  
2192                           const MBParam * const pParam,                           const MBParam * const pParam,
2193                           const MACROBLOCK * const pMBs,                                  MACROBLOCK * const pMBs,
2194                           const MACROBLOCK * const prevMBs,                                  SearchData * const Data)
                          VECTOR * const currMV,  
                          VECTOR * const currPMV)  
2195  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const uint32_t iHcount = pParam->mb_height;  
2196    
2197          const int32_t iWidth = pParam->width;          int i, mask;
2198          const int32_t iHeight = pParam->height;          int quarterpel = (pParam->vol_flags & XVID_VOL_QUARTERPEL)? 1: 0;
2199          const int32_t iEdgedWidth = pParam->edged_width;          VECTOR pmv[3];
2200            MACROBLOCK * const pMB = &pMBs[x + y * pParam->mb_width];
2201    
2202          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          for (i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;
2203    
2204          int32_t min_dx;          /* median is only used as prediction. it doesn't have to be real */
2205          int32_t max_dx;          if (x == 1 && y == 1) Data->predMV.x = Data->predMV.y = 0;
2206          int32_t min_dy;          else
2207          int32_t max_dy;                  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          VECTOR newMV;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
2214          VECTOR backupMV;                          pParam->width, pParam->height, Data->iFcode - quarterpel, 1, 0);
2215    
2216          VECTOR pmv[4];          Data->Cur = pCur + (x + y * pParam->edged_width) * 16;
2217          int32_t psad[8];          Data->RefP[0] = pRef + (x + y * pParam->edged_width) * 16;
2218    
2219          static MACROBLOCK *oldMBs = NULL;          pmv[1].x = EVEN(pMB->mvs[0].x);
2220            pmv[1].y = EVEN(pMB->mvs[0].y);
2221            pmv[2].x = EVEN(Data->predMV.x);
2222            pmv[2].y = EVEN(Data->predMV.y);
2223            pmv[0].x = pmv[0].y = 0;
2224    
2225  //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;          CheckCandidate32I(0, 0, 255, &i, Data);
         const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;  
         MACROBLOCK *oldMB = NULL;  
2226    
2227           int32_t thresh2;          if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP) {
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD = 9999;  
2228    
2229          MainSearch16FuncPtr MainSearchPtr;                  if (!(mask = make_mask(pmv, 1)))
2230                            CheckCandidate32I(pmv[1].x, pmv[1].y, mask, &i, Data);
2231                    if (!(mask = make_mask(pmv, 2)))
2232                            CheckCandidate32I(pmv[2].x, pmv[2].y, mask, &i, Data);
2233    
2234          if (oldMBs == NULL) {                  if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP) /* diamond only if needed */
2235                  oldMBs = (MACROBLOCK *) calloc(iWcount * iHcount, sizeof(MACROBLOCK));                          DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, i);
 //      fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));  
2236          }          }
         oldMB = oldMBs + x + y * iWcount;  
   
 /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
2237    
2238          if (!(MotionFlags & PMV_HALFPEL16)) {          for (i = 0; i < 4; i++) {
2239                  min_dx = EVEN(min_dx);                  MACROBLOCK * MB = &pMBs[x + (i&1) + (y+(i>>1)) * pParam->mb_width];
2240                  max_dx = EVEN(max_dx);                  MB->mvs[0] = MB->mvs[1] = MB->mvs[2] = MB->mvs[3] = Data->currentMV[i];
2241                  min_dy = EVEN(min_dy);                  MB->mode = MODE_INTER;
2242                  max_dy = EVEN(max_dy);                  MB->sad16 = Data->iMinSAD[i+1];
2243            }
2244          }          }
         /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
         //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);  
   
 /* 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.  
 */  
   
 // Prepare for main loop  
2245    
2246          currMV->x = start_x;  #define INTRA_THRESH    2200
2247          currMV->y = start_y;  #define INTER_THRESH    50
2248    #define INTRA_THRESH2   95
2249    
2250          if (!(MotionFlags & PMV_HALFPEL16)) {  int
2251                  currMV->x = EVEN(currMV->x);  MEanalysis(     const IMAGE * const pRef,
2252                  currMV->y = EVEN(currMV->y);                          const FRAMEINFO * const Current,
2253          }                          const MBParam * const pParam,
2254                            const int maxIntra, //maximum number if non-I frames
2255          if (currMV->x > max_dx)                          const int intraCount, //number of non-I frames after last I frame; 0 if we force P/B frame
2256                  currMV->x = max_dx;                          const int bCount, // number of B frames in a row
2257          if (currMV->x < min_dx)                          const int b_thresh)
2258                  currMV->x = min_dx;  {
2259          if (currMV->y > max_dy)          uint32_t x, y, intra = 0;
2260                  currMV->y = max_dy;          int sSAD = 0;
2261          if (currMV->y < min_dy)          MACROBLOCK * const pMBs = Current->mbs;
2262                  currMV->y = min_dy;          const IMAGE * const pCurrent = &Current->image;
2263            int IntraThresh = INTRA_THRESH, InterThresh = INTER_THRESH + b_thresh;
2264  /***************** This is predictor SET A: only median prediction ******************/          int blocks = 0;
2265            int complexity = 0;
2266          iMinSAD =  
2267                  sad16(cur,          int32_t iMinSAD[5], temp[5];
2268                            get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,          VECTOR currentMV[5];
2269                                                   iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);          SearchData Data;
2270          iMinSAD +=          Data.iEdgedWidth = pParam->edged_width;
2271                  calc_delta_16(currMV->x - center_x, currMV->y - center_y,          Data.currentMV = currentMV;
2272                                            (uint8_t) iFcode, iQuant);          Data.iMinSAD = iMinSAD;
2273            Data.iFcode = Current->fcode;
2274  // thresh1 is fixed to 256          Data.temp = temp;
2275          if ((iMinSAD < 256) ||          CheckCandidate = CheckCandidate32I;
2276                  ((MVequal(*currMV, prevMB->mvs[0])) &&  
2277                   ((int32_t) iMinSAD < prevMB->sad16))) {          if (intraCount != 0) {
2278                  if (MotionFlags & PMV_QUICKSTOP16)                  if (intraCount < 10) // we're right after an I frame
2279                          goto EPZS16_Terminate_without_Refine;                          IntraThresh += 15* (intraCount - 10) * (intraCount - 10);
2280                  if (MotionFlags & PMV_EARLYSTOP16)                  else
2281                          goto EPZS16_Terminate_with_Refine;                          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            }
 /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/  
2284    
2285  // previous frame MV          InterThresh -= 12 * bCount;
2286          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);          if (InterThresh < 15 + b_thresh) InterThresh = 15 + b_thresh;
2287    
2288  // set threshhold based on Min of Prediction and SAD of collocated block          if (sadInit) (*sadInit) ();
 // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want  
2289    
2290          if ((x == 0) && (y == 0)) {          for (y = 1; y < pParam->mb_height-1; y += 2) {
2291                  thresh2 = 512;                  for (x = 1; x < pParam->mb_width-1; x += 2) {
2292          } else {                          int i;
2293  /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */                          blocks += 10;
2294    
2295                  thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;                          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  // MV=(0,0) is often a good choice                          MEanalyzeMB(pRef->y, pCurrent->y, x, y, pParam, pMBs, &Data);
   
         CHECK_MV16_ZERO;  
2304    
2305                            for (i = 0; i < 4; i++) {
2306                                    int dev;
2307                                    MACROBLOCK *pMB = &pMBs[x+(i&1) + (y+(i>>1)) * pParam->mb_width];
2308                                    dev = dev16(pCurrent->y + (x + (i&1) + (y + (i>>1)) * pParam->edged_width) * 16,
2309                                                                    pParam->edged_width);
2310    
2311  // left neighbour, if allowed                                  complexity += MAX(dev, 300);
2312          if (x != 0) {                                  if (dev + IntraThresh < pMB->sad16) {
2313                  if (!(MotionFlags & PMV_HALFPEL16)) {                                          pMB->mode = MODE_INTRA;
2314                          pmv[1].x = EVEN(pmv[1].x);                                          if (++intra > ((pParam->mb_height-2)*(pParam->mb_width-2))/2) return I_VOP;
                         pmv[1].y = EVEN(pmv[1].y);  
                 }  
                 CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
         }  
 // top neighbour, if allowed  
         if (y != 0) {  
                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                         pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
2315                  }                  }
                 CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
2316    
2317  // top right neighbour, if allowed                                  if (pMB->mvs[0].x == 0 && pMB->mvs[0].y == 0)
2318                  if ((uint32_t) x != (iWcount - 1)) {                                          if (dev > 500 && pMB->sad16 < 1000)
2319                          if (!(MotionFlags & PMV_HALFPEL16)) {                                                  sSAD += 1000;
2320                                  pmv[3].x = EVEN(pmv[3].x);  
2321                                  pmv[3].y = EVEN(pmv[3].y);                                  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 */
2322                          }                          }
                         CHECK_MV16_CANDIDATE(pmv[3].x, pmv[3].y);  
2323                  }                  }
2324          }          }
2325            complexity >>= 7;
2326    
2327  /* Terminate if MinSAD <= T_2          sSAD /= complexity + 4*blocks;
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
2328    
2329          if ((iMinSAD <= thresh2)          if (intraCount > 80 && sSAD > INTRA_THRESH2 ) return I_VOP;
2330                  || (MVequal(*currMV, prevMB->mvs[0]) &&          if (sSAD > InterThresh ) return P_VOP;
2331                          ((int32_t) iMinSAD <= prevMB->sad16))) {          emms();
2332                  if (MotionFlags & PMV_QUICKSTOP16)          return B_VOP;
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
2333          }          }
2334    
 /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/  
   
         backupMV = prevMB->mvs[0];      // collocated MV  
         backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x);     // acceleration X  
         backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y);     // acceleration Y  
   
         CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y);  
   
 // left neighbour  
         if (x != 0)  
                 CHECK_MV16_CANDIDATE((prevMB - 1)->mvs[0].x, (prevMB - 1)->mvs[0].y);  
   
 // top neighbour  
         if (y != 0)  
                 CHECK_MV16_CANDIDATE((prevMB - iWcount)->mvs[0].x,  
                                                          (prevMB - iWcount)->mvs[0].y);  
2335    
2336  // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs  /* functions which perform BITS-based search/bitcount */
2337    
2338          if ((uint32_t) x != iWcount - 1)  static int
2339                  CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);  findRDinter(SearchData * const Data,
2340                            const MACROBLOCK * const pMBs, const int x, const int y,
2341                            const MBParam * const pParam,
2342                            const uint32_t MotionFlags)
2343    {
2344            int i, iDirection;
2345            int32_t bsad[5];
2346    
2347  // bottom neighbour, dito          CheckCandidate = CheckCandidateRD16;
         if ((uint32_t) y != iHcount - 1)  
                 CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,  
                                                          (prevMB + iWcount)->mvs[0].y);  
2348    
2349  /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */          if (Data->qpel) {
2350          if (iMinSAD <= thresh2) {                  for(i = 0; i < 5; i++) {
2351                  if (MotionFlags & PMV_QUICKSTOP16)                          Data->currentMV[i].x = Data->currentQMV[i].x/2;
2352                          goto EPZS16_Terminate_without_Refine;                          Data->currentMV[i].y = Data->currentQMV[i].y/2;
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
2353          }          }
2354                    Data->qpel_precision = 1;
2355                    CheckCandidateRD16(Data->currentQMV[0].x, Data->currentQMV[0].y, 255, &iDirection, Data);
2356    
2357  /************ (if Diamond Search)  **************/                  if (MotionFlags & (XVID_ME_HALFPELREFINE16_RD | XVID_ME_EXTSEARCH_RD)) { /* we have to prepare for halfpixel-precision search */
2358                            for(i = 0; i < 5; i++) bsad[i] = Data->iMinSAD[i];
2359          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                          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          if (MotionFlags & PMV_USESQUARES16)                          Data->qpel_precision = 0;
2362                  MainSearchPtr = Square16_MainSearch;                          if (Data->currentQMV->x & 1 || Data->currentQMV->y & 1)
2363          else                                  CheckCandidateRD16(Data->currentMV[0].x, Data->currentMV[0].y, 255, &iDirection, Data);
          if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
   
 /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  
   
         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, 2, iFcode, iQuant, 0);  
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
2364          }          }
2365    
2366            } else { /* not qpel */
2367    
2368          if (MotionFlags & PMV_EXTSEARCH16) {                  CheckCandidateRD16(Data->currentMV[0].x, Data->currentMV[0].y, 255, &iDirection, Data);
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
   
                 if (!(MVequal(pmv[0], backupMV))) {  
                         iSAD =  
                                 (*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,  
                                                                   2, iFcode, iQuant, 0);  
2369                  }                  }
2370    
2371                  if (iSAD < iMinSAD) {          if (MotionFlags&XVID_ME_EXTSEARCH_RD) SquareSearch(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
                         *currMV = newMV;  
                         iMinSAD = iSAD;  
                 }  
2372    
2373                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          if (MotionFlags&XVID_ME_HALFPELREFINE16_RD) SubpelRefine(Data);
                         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, 2, iFcode, iQuant, 0);  
2374    
2375                          if (iSAD < iMinSAD) {          if (Data->qpel) {
2376                                  *currMV = newMV;                  if (MotionFlags&(XVID_ME_EXTSEARCH_RD | XVID_ME_HALFPELREFINE16_RD)) { /* there was halfpel-precision search */
2377                                  iMinSAD = iSAD;                          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                            /* 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  /***************        Choose best MV found     **************/          if (MotionFlags&XVID_ME_CHECKPREDICTION_RD) { /* let's check vector equal to prediction */
2391                    VECTOR * v = Data->qpel ? Data->currentQMV : Data->currentMV;
2392    EPZS16_Terminate_with_Refine:                  if (!(Data->predMV.x == v->x && Data->predMV.y == v->y))
2393          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step                          CheckCandidateRD16(Data->predMV.x, Data->predMV.y, 255, &iDirection, Data);
2394                  iMinSAD =          }
2395                          Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,          return Data->iMinSAD[0];
                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
   
   EPZS16_Terminate_without_Refine:  
   
         *oldMB = *prevMB;  
   
         currPMV->x = currMV->x - center_x;  
         currPMV->y = currMV->y - center_y;  
         return iMinSAD;  
2396  }  }
2397    
2398    static int
2399  int32_t  findRDinter4v(const SearchData * const Data,
2400  EPZSSearch8(const uint8_t * const pRef,                                  MACROBLOCK * const pMB, const MACROBLOCK * const pMBs,
2401                          const uint8_t * const pRefH,                                  const int x, const int y,
2402                          const uint8_t * const pRefV,                                  const MBParam * const pParam, const uint32_t MotionFlags,
2403                          const uint8_t * const pRefHV,                                  const VECTOR * const backup)
                         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)  
2404  {  {
 /* Please not that EPZS might not be a good choice for 8x8-block motion search ! */  
   
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
   
         const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;  
   
         int32_t iDiamondSize = 1;  
   
         int32_t min_dx;  
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
   
         VECTOR newMV;  
         VECTOR backupMV;  
   
         VECTOR pmv[4];  
         int32_t psad[8];  
   
         const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);  
   
 //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;  
         const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;  
   
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD = 9999;  
2405    
2406          MainSearch8FuncPtr MainSearchPtr;          int cbp = 0, bits = 0, t = 0, i, iDirection;
2407            SearchData Data2, *Data8 = &Data2;
2408            int sumx = 0, sumy = 0;
2409            int16_t *in = Data->dctSpace, *coeff = Data->dctSpace + 64;
2410            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  /* Get maximum range */                  get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 3,
2438          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,                                          pParam->width, pParam->height, Data8->iFcode, Data8->qpel+1, 0);
                           iFcode);  
2439    
2440  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */                  *Data8->iMinSAD += BITS_MULT*t;
2441    
2442          if (!(MotionFlags & PMV_HALFPEL8)) {                  Data8->qpel_precision = Data8->qpel;
2443                  min_dx = EVEN(min_dx);                  /* checking the vector which has been found by SAD-based 8x8 search (if it's different than the one found so far) */
2444                  max_dx = EVEN(max_dx);                  {
2445                  min_dy = EVEN(min_dy);                          VECTOR *v = Data8->qpel ? Data8->currentQMV : Data8->currentMV;
2446                  max_dy = EVEN(max_dy);                          if (!MVequal (*v, backup[i+1]) )
2447                                    CheckCandidateRD8(backup[i+1].x, backup[i+1].y, 255, &iDirection, Data8);
2448          }          }
         /* 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);  
2449    
2450                    if (Data8->qpel) {
2451                            if (MotionFlags&XVID_ME_HALFPELREFINE8_RD || (MotionFlags&XVID_ME_EXTSEARCH8 && MotionFlags&XVID_ME_EXTSEARCH_RD)) { /* halfpixel motion search follows */
2452                                    int32_t s = *Data8->iMinSAD;
2453                                    Data8->currentMV->x = Data8->currentQMV->x/2;
2454                                    Data8->currentMV->y = Data8->currentQMV->y/2;
2455                                    Data8->qpel_precision = 0;
2456                                    get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 3,
2457                                                            pParam->width, pParam->height, Data8->iFcode - 1, 1, 0);
2458    
2459  /* Step 4: Calculate SAD around the Median prediction.                                  if (Data8->currentQMV->x & 1 || Data8->currentQMV->y & 1)
2460          MinSAD=SAD                                          CheckCandidateRD8(Data8->currentMV->x, Data8->currentMV->y, 255, &iDirection, Data8);
         If Motion Vector equal to Previous frame motion vector  
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
 */  
2461    
2462  // Prepare for main loop                                  if (MotionFlags & XVID_ME_EXTSEARCH8 && MotionFlags & XVID_ME_EXTSEARCH_RD)
2463                                            SquareSearch(Data8->currentMV->x, Data8->currentMV->x, Data8, 255);
2464    
2465                                    if (MotionFlags & XVID_ME_HALFPELREFINE8_RD)
2466                                            SubpelRefine(Data8);
2467    
2468          if (!(MotionFlags & PMV_HALFPEL8)) {                                  if(s > *Data8->iMinSAD) { /* we have found a better match */
2469                  currMV->x = EVEN(currMV->x);                                          Data8->currentQMV->x = 2*Data8->currentMV->x;
2470                  currMV->y = EVEN(currMV->y);                                          Data8->currentQMV->y = 2*Data8->currentMV->y;
2471          }          }
2472    
2473          if (currMV->x > max_dx)                                  Data8->qpel_precision = 1;
2474                  currMV->x = max_dx;                                  get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 3,
2475          if (currMV->x < min_dx)                                                          pParam->width, pParam->height, Data8->iFcode, 2, 0);
                 currMV->x = min_dx;  
         if (currMV->y > max_dy)  
                 currMV->y = max_dy;  
         if (currMV->y < min_dy)  
                 currMV->y = min_dy;  
   
 /***************** This is predictor SET A: only median prediction ******************/  
2476    
2477                            }
2478                            if (MotionFlags & XVID_ME_QUARTERPELREFINE8_RD) SubpelRefine(Data8);
2479    
2480          iMinSAD =                  } else { /* not qpel */
                 sad8(cur,  
                          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);  
2481    
2482                            if (MotionFlags & XVID_ME_EXTSEARCH8 && MotionFlags & XVID_ME_EXTSEARCH_RD) /* extsearch */
2483                                    SquareSearch(Data8->currentMV->x, Data8->currentMV->x, Data8, 255);
2484    
2485  // thresh1 is fixed to 256                          if (MotionFlags & XVID_ME_HALFPELREFINE8_RD)
2486          if (iMinSAD < 256 / 4) {                                  SubpelRefine(Data8); /* halfpel refinement */
                 if (MotionFlags & PMV_QUICKSTOP8)  
                         goto EPZS8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
2487          }          }
2488    
2489  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/                  /* checking vector equal to predicion */
2490                    if (i != 0 && MotionFlags & XVID_ME_CHECKPREDICTION_RD) {
2491                            const VECTOR * v = Data->qpel ? Data8->currentQMV : Data8->currentMV;
2492                            if (!MVequal(*v, Data8->predMV))
2493                                    CheckCandidateRD8(Data8->predMV.x, Data8->predMV.y, 255, &iDirection, Data8);
2494                    }
2495    
2496                    bits += *Data8->iMinSAD;
2497                    if (bits >= Data->iMinSAD[0]) return bits; /* no chances for INTER4V */
2498    
2499  // MV=(0,0) is often a good choice                  /* MB structures for INTER4V mode; we have to set them here, we don't have predictor anywhere else */
2500          CHECK_MV8_ZERO;                  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  // previous frame MV          } /* end - for all luma blocks */
         CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x, prevMB->mvs[iSubBlock].y);  
2517    
2518  // left neighbour, if allowed          bits += BITS_MULT*xvid_cbpy_tab[15-(cbp>>2)].len;
         if (psad[1] != MV_MAX_ERROR) {  
                 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  
         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);  
2519    
2520  // top right neighbour, if allowed          /* let's check chroma */
2521                  if (psad[3] != MV_MAX_ERROR) {          sumx = (sumx >> 3) + roundtab_76[sumx & 0xf];
2522                          if (!(MotionFlags & PMV_HALFPEL8)) {          sumy = (sumy >> 3) + roundtab_76[sumy & 0xf];
                                 pmv[3].x = EVEN(pmv[3].x);  
                                 pmv[3].y = EVEN(pmv[3].y);  
                         }  
                         CHECK_MV8_CANDIDATE(pmv[3].x, pmv[3].y);  
                 }  
         }  
2523    
2524  /*  // this bias is zero anyway, at the moment!          /* 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          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)          if (bits >= *Data->iMinSAD) return bits;
                 iMinSAD -= MV8_00_BIAS;  
2530    
2531  */          /* chroma V */
2532            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  /* Terminate if MinSAD <= T_2          bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTER4V & 7) | ((cbp & 3) << 3)].len;
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
2537    
2538          if (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */          *Data->cbp = cbp;
2539                  if (MotionFlags & PMV_QUICKSTOP8)          return bits;
                         goto EPZS8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
2540          }          }
2541    
2542  /************ (Diamond Search)  **************/  static int
2543    findRDintra(const SearchData * const Data)
2544          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  {
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_HALFPELDIAMOND8))          for(i = 0; i < 4; i++) {
2550                  iDiamondSize *= 2;                  int s = 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2551                    transfer_8to16copy(in, Data->Cur + s, Data->iEdgedWidth);
2552                    bits += Block_CalcBitsIntra(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, i, &dc);
2553    
2554  /* default: use best prediction as starting point for one call of EPZS_MainSearch */                  if (bits >= Data->iMinSAD[0]) return bits;
2555            }
2556    
2557  // there is no EPZS^2 for inter4v at the moment          bits += BITS_MULT*xvid_cbpy_tab[cbp>>2].len;
2558    
2559    if (MotionFlags & PMV_USESQUARES8)          /*chroma U */
2560        MainSearchPtr = Square8_MainSearch;          transfer_8to16copy(in, Data->CurU, Data->iEdgedWidth/2);
2561    else          bits += Block_CalcBitsIntra(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 4, &dc);
2562    
2563          if (MotionFlags & PMV_ADVANCEDDIAMOND8)          if (bits >= Data->iMinSAD[0]) return bits;
                 MainSearchPtr = AdvDiamond8_MainSearch;  
         else  
                 MainSearchPtr = Diamond8_MainSearch;  
2564    
2565          iSAD =          /* chroma V */
2566                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,          transfer_8to16copy(in, Data->CurV, Data->iEdgedWidth/2);
2567                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,          bits += Block_CalcBitsIntra(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 5, &dc);
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, 0);  
2568    
2569            bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTRA & 7) | ((cbp & 3) << 3)].len;
2570    
2571          if (iSAD < iMinSAD) {          return bits;
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
2572          }          }
2573    
2574          if (MotionFlags & PMV_EXTSEARCH8) {  static int
2575  /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  findRDgmc(const SearchData * const Data, const IMAGE * const vGMC, const int x, const int y)
2576    {
2577                  if (!(MVequal(pmv[0], backupMV))) {          int bits = BITS_MULT*1; /* this one is mcsel */
2578                          iSAD =          int cbp = 0, i;
2579                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,          int16_t *in = Data->dctSpace, * coeff = Data->dctSpace + 64;
                                                                   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);  
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                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          bits += BITS_MULT*xvid_cbpy_tab[15-(cbp>>2)].len;
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, 0);  
2589    
2590                          if (iSAD < iMinSAD) {          /*chroma U */
2591                                  *currMV = newMV;          transfer_8to16subro(in, Data->CurU, vGMC->u + 8*(x+y*(Data->iEdgedWidth/2)), Data->iEdgedWidth/2);
2592                                  iMinSAD = iSAD;          bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 4);
                         }  
                 }  
         }  
2593    
2594  /***************        Choose best MV found     **************/          if (bits >= Data->iMinSAD[0]) return bits;
2595    
2596    EPZS8_Terminate_with_Refine:          /* chroma V */
2597          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step          transfer_8to16subro(in, Data->CurV , vGMC->v + 8*(x+y*(Data->iEdgedWidth/2)), Data->iEdgedWidth/2);
2598                  iMinSAD =          bits += Block_CalcBits(coeff, in, Data->dctSpace + 128, Data->iQuant, Data->quant_type, &cbp, 5);
                         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);  
2599    
2600    EPZS8_Terminate_without_Refine:          bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTER & 7) | ((cbp & 3) << 3)].len;
2601    
2602          currPMV->x = currMV->x - center_x;          *Data->cbp = cbp;
2603          currPMV->y = currMV->y - center_y;  
2604          return iMinSAD;          return bits;
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 };  
   
         int32_t iDiamondSize;  
   
         int32_t min_dx;  
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
   
         int32_t iFound;  
2622    
2623          VECTOR newMV;          int i=0;
2624          VECTOR backupMV;          MACROBLOCK * const pMB = &pMBs[x + y * pParam->mb_width];
2625    
2626          VECTOR pmv[4];          Data->iMinSAD[0] = MV_MAX_ERROR;
         int32_t psad[4];  
2627    
2628          MainSearch16FuncPtr MainSearchPtr;          Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
2629    
2630          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
2631          MACROBLOCK *const pMB = pMBs + x + y * iWcount;                                  pParam->width, pParam->height, 16, 1, 0);
2632    
2633          int32_t threshA, threshB;          Data->Cur = pCur + 16*(x + y * pParam->edged_width);
2634          int32_t bPredEq;          Data->RefP[0] = pRef + 16*(x + y * pParam->edged_width);
2635          int32_t iMinSAD, iSAD;          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            Data->currentMV[0].x = Data->currentMV[0].y = 0;
2640            CheckCandidate16I(0, 0, 255, &i, Data);
2641    
2642  /* Get maximum range */          if ( (Data->predMV.x !=0) || (Data->predMV.y != 0) )
2643          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,                  CheckCandidate16I(Data->predMV.x, Data->predMV.y, 255, &i, Data);
                           iFcode);  
2644    
2645  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          AdvDiamondSearch(Data->currentMV[0].x, Data->currentMV[0].y, Data, 255);
2646    
2647          if ((x == 0) && (y == 0)) {          SubpelRefine(Data);
                 threshA = 512;  
                 threshB = 1024;  
2648    
                 bPredEq = 0;  
                 psad[0] = psad[1] = psad[2] = psad[3] = 0;  
                 *currMV = pmv[0] = pmv[1] = pmv[2] = pmv[3] = zeroMV;  
2649    
2650          } else {          /* for QPel halfpel positions are worse than in halfpel mode :( */
2651                  threshA = psad[0];  /*      if (Data->qpel) {
2652                  threshB = threshA + 256;                  Data->currentQMV->x = 2*Data->currentMV->x;
2653                  if (threshA < 512)                  Data->currentQMV->y = 2*Data->currentMV->y;
2654                          threshA = 512;                  Data->qpel_precision = 1;
2655                  if (threshA > 1024)                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 4,
2656                          threshA = 1024;                                          pParam->width, pParam->height, iFcode, 2, 0);
2657                  if (threshB > 1792)                  SubpelRefine(Data);
2658                          threshB = 1792;          }
   
                 bPredEq = get_ipmvdata(pMBs, iWcount, 0, x, y, 0, pmv, psad);  
                 *currMV = pmv[0];                       /* current best := prediction */  
         }  
   
         iFound = 0;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
2659  */  */
2660    
2661          if (currMV->x > max_dx) {          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
2662                  currMV->x = EVEN(max_dx);          pMB->sad16 = Data->iMinSAD[0];
2663          }          pMB->mode = MODE_INTER;
2664          if (currMV->x < min_dx) {          pMB->sad16 += 10*d_mv_bits(pMB->mvs[0].x, pMB->mvs[0].y, Data->predMV, Data->iFcode, 0, 0);
2665                  currMV->x = EVEN(min_dx);          return;
         }  
         if (currMV->y > max_dy) {  
                 currMV->y = EVEN(max_dy);  
         }  
         if (currMV->y < min_dy) {  
                 currMV->y = EVEN(min_dy);  
2666          }          }
2667    
2668          iMinSAD =  void
2669                  sad16(cur,  GMEanalysis(const MBParam * const pParam,
2670                            get_iref_mv(pRef, x, y, 16, currMV,                          const FRAMEINFO * const current,
2671                                                   iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);                          const FRAMEINFO * const reference,
2672          iMinSAD +=                          const IMAGE * const pRefH,
2673                  calc_delta_16(currMV->x - center_x, currMV->y - center_y,                          const IMAGE * const pRefV,
2674                                            (uint8_t) iFcode, iQuant);                          const IMAGE * const pRefHV)
   
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->i_mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->i_sad16))) {  
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
2675                  {                  {
2676                          if (!MVzero(*currMV)) {          uint32_t x, y;
2677                                  iMinSAD += MV16_00_BIAS;          MACROBLOCK * const pMBs = current->mbs;
2678                                  CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures          const IMAGE * const pCurrent = &current->image;
2679                                  iMinSAD -= MV16_00_BIAS;          const IMAGE * const pReference = &reference->image;
                         }  
                 }  
   
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfastInt16_Terminate_with_Refine;  
         }  
   
2680    
2681  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion          int32_t iMinSAD[5], temp[5];
2682     vector of the median.          VECTOR currentMV[5];
2683     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2          SearchData Data;
2684  */          memset(&Data, 0, sizeof(SearchData));
2685    
2686          if ((bPredEq) && (MVequal(pmv[0], prevMB->i_mvs[0])))          Data.iEdgedWidth = pParam->edged_width;
2687                  iFound = 2;          Data.rounding = pParam->m_rounding_type;
2688    
2689  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          Data.currentMV = &currentMV[0];
2690     Otherwise select large Diamond Search.          Data.iMinSAD = &iMinSAD[0];
2691  */          Data.iFcode = current->fcode;
2692            Data.temp = temp;
2693    
2694          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))          CheckCandidate = CheckCandidate16I;
                 iDiamondSize = 2;               // halfpel units!  
         else  
                 iDiamondSize = 4;               // halfpel units!  
2695    
2696  /*          if (sadInit) (*sadInit) ();
    Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  
    Also calculate (0,0) but do not subtract offset.  
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset.  
 */  
2697    
2698  // (0,0) is often a good choice          for (y = 0; y < pParam->mb_height; y ++) {
2699                    for (x = 0; x < pParam->mb_width; x ++) {
2700    
2701          if (!MVzero(pmv[0]))                          GMEanalyzeMB(pCurrent->y, pReference->y, pRefH->y, pRefV->y, pRefHV->y, x, y, pParam, pMBs, &Data);
2702                  CHECK_MV16_ZERO;                  }
2703            }
2704            return;
2705    }
2706    
 // previous frame MV is always possible  
2707    
2708          if (!MVzero(prevMB->i_mvs[0]))  WARPPOINTS
2709                  if (!MVequal(prevMB->i_mvs[0], pmv[0]))  GlobalMotionEst(MACROBLOCK * const pMBs,
2710                          CHECK_MV16_CANDIDATE(prevMB->i_mvs[0].x, prevMB->i_mvs[0].y);                                  const MBParam * const pParam,
2711                                    const FRAMEINFO * const current,
2712  // left neighbour, if allowed                                  const FRAMEINFO * const reference,
2713                                    const IMAGE * const pRefH,
2714          if (!MVzero(pmv[1]))                                  const IMAGE * const pRefV,
2715                  if (!MVequal(pmv[1], prevMB->i_mvs[0]))                                  const IMAGE * const pRefHV)
2716                          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;  
2717    
2718            const int deltax=8;             // upper bound for difference between a MV and it's neighbour MVs
2719            const int deltay=8;
2720            const unsigned int gradx=512;           // lower bound for gradient in MB (ignore "flat" blocks)
2721            const unsigned int grady=512;
2722    
2723  /* Step 6: If MinSAD <= thresa goto Step 10.          double sol[4] = { 0., 0., 0., 0. };
    If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
 */  
2724    
2725          if ((iMinSAD <= threshA) ||          WARPPOINTS gmc;
                 (MVequal(*currMV, prevMB->i_mvs[0]) &&  
                  ((int32_t) iMinSAD < prevMB->i_sad16))) {  
2726    
2727                  if (MotionFlags & PMV_EARLYSTOP16)          uint32_t mx, my;
                         goto PMVfastInt16_Terminate_with_Refine;  
         }  
2728    
2729            int MBh = pParam->mb_height;
2730            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  /************ (Diamond Search)  **************/          int num=0;
2735  /*          int oldnum;
    Step 7: Perform Diamond search, with either the small or large diamond.  
    If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
    Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
    If center then goto step 10.  
    Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
    Refine by using small diamond and goto step 10.  
 */  
2736    
2737          if (MotionFlags & PMV_USESQUARES16)          gmc.duv[0].x = gmc.duv[0].y = gmc.duv[1].x = gmc.duv[1].y = gmc.duv[2].x = gmc.duv[2].y = 0;
                 MainSearchPtr = Square16_MainSearch;  
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
2738    
2739          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          GMEanalysis(pParam,current, reference, pRefH, pRefV, pRefHV);
2740    
2741            /* block based ME isn't done, yet, so do a quick presearch */
2742    
2743  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  // filter mask of all blocks
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  
                                                   currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
2744    
2745          if (iSAD < iMinSAD) {          for (my = 0; my < (uint32_t)MBh; my++)
2746                  *currMV = newMV;          for (mx = 0; mx < (uint32_t)MBw; mx++)
2747                  iMinSAD = iSAD;          {
2748                    const int mbnum = mx + my * MBw;
2749                            pMBs[mbnum].mcsel = 0;
2750          }          }
2751    
         if (MotionFlags & PMV_EXTSEARCH16) {  
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
2752    
2753                  if (!(MVequal(pmv[0], backupMV))) {          for (my = 1; my < (uint32_t)MBh-1; my++) /* ignore boundary blocks */
2754                          iSAD =          for (mx = 1; mx < (uint32_t)MBw-1; mx++) /* theirs MVs are often wrong */
2755                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,          {
2756                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,                  const int mbnum = mx + my * MBw;
2757                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,                  MACROBLOCK *const pMB = &pMBs[mbnum];
2758                                                                    iDiamondSize, iFcode, iQuant, iFound);                  const VECTOR mv = pMB->mvs[0];
2759    
2760                          if (iSAD < iMinSAD) {                  /* don't use object boundaries */
2761                                  *currMV = newMV;                  if   ( (abs(mv.x -   (pMB-1)->mvs[0].x) < deltax)
2762                                  iMinSAD = iSAD;                          && (abs(mv.y -   (pMB-1)->mvs[0].y) < deltay)
2763                            && (abs(mv.x -   (pMB+1)->mvs[0].x) < deltax)
2764                            && (abs(mv.y -   (pMB+1)->mvs[0].y) < deltay)
2765                            && (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                          }                          }
                 }  
   
                 if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {  
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
2776    
2777                          if (iSAD < iMinSAD) {                  /* only use "structured" blocks */
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
2778                  }                  }
2779          }          }
2780            emms();
2781    
2782  /*          /*      further filtering would be possible, but during iteration, remaining
2783     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.                  outliers usually are removed, too */
 */  
2784    
2785  PMVfastInt16_Terminate_with_Refine:          if (num>= minblocks)
2786            do {            /* until convergence */
2787                    double DtimesF[4];
2788                    double a,b,c,n,invdenom;
2789                    double meanx,meany;
2790    
2791          pMB->i_mvs[0] = pMB->i_mvs[1] = pMB->i_mvs[2] = pMB->i_mvs[3] = pMB->i_mv16 = *currMV;                  a = b = c = n = 0;
2792          pMB->i_sad8[0] = pMB->i_sad8[1] = pMB->i_sad8[2] = pMB->i_sad8[3] = pMB->i_sad16 = iMinSAD;                  DtimesF[0] = DtimesF[1] = DtimesF[2] = DtimesF[3] = 0.;
2793                    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_HALFPELREFINE16)  // perform final half-pel step                          if (!pMBs[mbnum].mcsel)
2800                  iMinSAD =                                  continue;
                         Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
2801    
2802          pmv[0] = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          // get _REAL_ prediction (halfpel possible)                          n++;
2803                            a += 16*mx+8;
2804                            b += 16*my+8;
2805                            c += (16*mx+8)*(16*mx+8)+(16*my+8)*(16*my+8);
2806    
2807  PMVfastInt16_Terminate_without_Refine:                          DtimesF[0] += (double)mv.x;
2808          currPMV->x = currMV->x - center_x;                          DtimesF[1] += (double)mv.x*(16*mx+8) + (double)mv.y*(16*my+8);
2809          currPMV->y = currMV->y - center_y;                          DtimesF[2] += (double)mv.x*(16*my+8) - (double)mv.y*(16*mx+8);
2810          return iMinSAD;                          DtimesF[3] += (double)mv.y;
2811  }  }
2812    
2813            invdenom = a*a+b*b-c*n;
2814    
2815    /* Solve the system:    sol = (D'*E*D)^{-1} D'*E*F   */
2816    /* D'*E*F has been calculated in the same loop as matrix */
2817    
2818  /* ***********************************************************          sol[0] = -c*DtimesF[0] + a*DtimesF[1] + b*DtimesF[2];
2819          bvop motion estimation          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  void          sol[0] /= invdenom;
2824  MotionEstimationBVOP(MBParam * const pParam,          sol[1] /= invdenom;
2825                                           FRAMEINFO * const frame,          sol[2] /= invdenom;
2826                                           const int32_t time_bp,          sol[3] /= invdenom;
2827                                           const int32_t time_pp,  
2828                                           // forward (past) reference          meanx = meany = 0.;
2829                                           const MACROBLOCK * const f_mbs,          oldnum = 0;
2830                                           const IMAGE * const f_ref,          for (my = 1; my < (uint32_t)MBh-1; my++)
2831                                           const IMAGE * const f_refH,                  for (mx = 1; mx < (uint32_t)MBw-1; mx++)
                                          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)  
2832  {  {
2833          const int mb_width = pParam->mb_width;                          const int mbnum = mx + my * MBw;
2834          const int mb_height = pParam->mb_height;                          const VECTOR mv = pMBs[mbnum].mvs[0];
         const int edged_width = pParam->edged_width;  
2835    
2836          const int32_t iWidth = pParam->width;                          if (!pMBs[mbnum].mcsel)
2837          const int32_t iHeight = pParam->height;                                  continue;
2838    
2839                            oldnum++;
2840                            meanx += fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - (double)mv.x );
2841                            meany += fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - (double)mv.y );
2842                    }
2843    
2844          int i, j, k;          if (4*meanx > oldnum)   /* better fit than 0.25 (=1/4pel) is useless */
2845                    meanx /= oldnum;
2846            else
2847                    meanx = 0.25;
2848    
2849          static const VECTOR zeroMV={0,0};          if (4*meany > oldnum)
2850                    meany /= oldnum;
2851            else
2852                    meany = 0.25;
2853    
2854          int f_sad16;    /* forward (as usual) search */          num = 0;
2855          int b_sad16;    /* backward (only in b-frames) search */          for (my = 0; my < (uint32_t)MBh; my++)
2856          int i_sad16;    /* interpolated (both direction, b-frames only) */                  for (mx = 0; mx < (uint32_t)MBw; mx++)
2857          int d_sad16;    /* direct mode (assume almost linear motion) */                  {
2858                            const int mbnum = mx + my * MBw;
2859                            const VECTOR mv = pMBs[mbnum].mvs[0];
2860    
2861          int best_sad;                          if (!pMBs[mbnum].mcsel)
2862                                    continue;
2863    
2864          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/                          if  ( ( fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - (double)mv.x ) > meanx )
2865          VECTOR f_interpolMV, b_interpolMV;                                  || ( fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - (double)mv.y ) > meany ) )
2866          VECTOR pmv_dontcare;                                  pMBs[mbnum].mcsel=0;
2867                            else
2868                                    num++;
2869                    }
2870    
2871          int min_dx, max_dx, min_dy, max_dy;          } while ( (oldnum != num) && (num>= minblocks) );
         int f_min_dx, f_max_dx, f_min_dy, f_max_dy;  
         int b_min_dx, b_max_dx, b_min_dy, b_max_dy;  
2872    
2873          int f_count=0;          if (num < minblocks)
2874          int b_count=0;          {
2875          int i_count=0;                  const int iEdgedWidth = pParam->edged_width;
2876          int d_count=0;                  num = 0;
2877    
2878          const int64_t TRB = (int32_t)time_pp - (int32_t)time_bp;  /*              fprintf(stderr,"Warning! Unreliable GME (%d/%d blocks), falling back to translation.\n",num,MBh*MBw);
2879      const int64_t TRD = (int32_t)time_pp;  */
2880                    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          // fprintf(stderr,"TRB = %lld  TRD = %lld  time_bp =%d time_pp =%d\n\n",TRB,TRD,time_bp,time_pp);                  if (!(current->motion_flags & XVID_ME_GME_REFINE))
2883          // note: i==horizontal, j==vertical                          return gmc;
         for (j = 0; j < mb_height; j++) {  
2884    
2885                  f_predMV = zeroMV;      /* prediction is reset at left boundary */                  for (my = 1; my < (uint32_t)MBh-1; my++) /* ignore boundary blocks */
2886                  b_predMV = zeroMV;                  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                  for (i = 0; i < mb_width; i++) {                  if (gmc.duv[0].x)
2901                          MACROBLOCK *mb = &frame->mbs[i + j * mb_width];                          gmc.duv[0].x /= num;
2902                          const MACROBLOCK *f_mb = &f_mbs[i + j * mb_width];                  if (gmc.duv[0].y)
2903                          const MACROBLOCK *b_mb = &b_mbs[i + j * mb_width];                          gmc.duv[0].y /= num;
2904            } else {
2905    
2906                          mb->deltamv=zeroMV;                  gmc.duv[0].x=(int)(sol[0]+0.5);
2907                    gmc.duv[0].y=(int)(sol[3]+0.5);
2908    
2909  /* special case, if collocated block is SKIPed: encoding is forward (0,0), cpb=0 without further ado */                  gmc.duv[1].x=(int)(sol[1]*pParam->width+0.5);
2910                    gmc.duv[1].y=(int)(-sol[2]*pParam->width+0.5);
2911    
2912                          if (b_mb->mode == MODE_INTER && b_mb->cbp == 0 &&                  gmc.duv[2].x=-gmc.duv[1].y;             /* two warp points only */
2913                                  b_mb->mvs[0].x == 0 && b_mb->mvs[0].y == 0) {                  gmc.duv[2].y=gmc.duv[1].x;
2914                                  mb->mode = MODE_NOT_CODED;          }
2915                                  mb->b_mvs[0] = mb->mvs[0] = zeroMV;          if (num>maxblocks)
2916                                  continue;          {       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                          if (b_mb->mode == MODE_INTER4V)  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                                  d_sad16 = 0;          uint8_t* GMCblock = (uint8_t*)malloc(16*pParam->edged_width);
2944                          /* same method of scaling as in decoder.c, so we copy from there */          WARPPOINTS bestwp=*startwp;
2945                      for (k = 0; k < 4; k++) {          WARPPOINTS centerwp,currwp;
2946            int gmcminSAD=0;
2947                                          mb->directmv[k] = b_mb->mvs[k];          int gmcSAD=0;
2948            int direction;
2949    //      int mx,my;
2950    
2951                                          mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);  /* use many blocks... */
2952                      mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)  /*              for (my = 0; my < (uint32_t)pParam->mb_height; my++)
2953                                                                                  ? ((TRB - TRD) * mb->directmv[k].x) / TRD                  for (mx = 0; mx < (uint32_t)pParam->mb_width; mx++)
                                             : 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);  
                                 }  
                         }  
                         else  
2954                          {                          {
2955                                  mb->directmv[3] = mb->directmv[2] = mb->directmv[1] =                          const int mbnum = mx + my * pParam->mb_width;
2956                                          mb->directmv[0] = b_mb->mvs[0];                          pMBs[mbnum].mcsel=1;
2957                    }
2958    */
2959    
2960                                  mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);  /* or rather don't use too many blocks... */
2961                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)  /*
2962                                                                          ? ((TRB - TRD) * mb->directmv[0].x) / TRD                  for (my = 1; my < (uint32_t)MBh-1; my++)
2963                                      : mb->mvs[0].x - mb->directmv[0].x);                  for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2964                    {
2965                      mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);                          const int mbnum = mx + my * MBw;
2966                  mb->b_mvs[0].y = (int32_t) ((mb->directmv[0].y == 0)                          if (MBmask[mbnum-1])
2967                                                                          ? ((TRB - TRD) * mb->directmv[0].y) / TRD                                  MBmask[mbnum-1]=0;
2968                                      : mb->mvs[0].y - mb->directmv[0].y);                          else
2969                                    if (MBmask[mbnum-MBw])
2970                                  d_sad16 = sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,                                          MBmask[mbnum-1]=0;
                                                   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);  
2971    
2972              }              }
2973                      d_sad16 += calc_delta_16(mb->deltamv.x, mb->deltamv.y, 1, frame->quant);  */
2974                    gmcminSAD = globalSAD(&bestwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
                         // forward search  
                         f_sad16 = SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 &frame->image, i, j,  
                                                 mb->mvs[0].x, mb->mvs[0].y,                     /* start point f_directMV */  
                                                 f_predMV.x, f_predMV.y,                         /* center is f-prediction */  
                                                 frame->motion_flags,  
                                                 frame->quant, frame->fcode, pParam,  
                                                 f_mbs, f_mbs,  
                                                 &mb->mvs[0], &pmv_dontcare);  
2975    
2976                    if ( (reference->coding_type == S_VOP)
2977                            && ( (reference->warp.duv[1].x != bestwp.duv[1].x)
2978                              || (reference->warp.duv[1].y != bestwp.duv[1].y)
2979                              || (reference->warp.duv[0].x != bestwp.duv[0].x)
2980                              || (reference->warp.duv[0].y != bestwp.duv[0].y)
2981                              || (reference->warp.duv[2].x != bestwp.duv[2].x)
2982                              || (reference->warp.duv[2].y != bestwp.duv[2].y) ) )
2983                    {
2984                            gmcSAD = globalSAD(&reference->warp, pParam, pMBs,
2985                                                                    current, pRef, pCurr, GMCblock);
2986    
2987                          // backward search                          if (gmcSAD < gmcminSAD)
2988                          b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,                          {       bestwp = reference->warp;
2989                                                  &frame->image, i, j,                                  gmcminSAD = gmcSAD;
                                                 mb->b_mvs[0].x, mb->b_mvs[0].y,         /* start point b_directMV */  
                                                 b_predMV.x, b_predMV.y,                         /* center is b-prediction */  
                                                 frame->motion_flags,  
                                                 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,  1,  
                                                 frame->fcode, frame->bcode,frame->quant,0);  
   
   
 /*  DIRECT MODE DELTA VECTOR SEARCH.  
     This has to be made more effective, but at the moment I'm happy it's running at all */  
   
 /* range is taken without fcode restriction, just a hack instead of writing down the dimensions, of course */  
   
                         get_range(&min_dx, &max_dx, &min_dy, &max_dy, i, j, 16, iWidth, iHeight, 19);  
   
                         d_sad16 = Diamond16_DirectMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i*16 + j*16*edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 TRB,TRD,  
                                                 0,0,  
                                                 d_sad16,  
                                                 &mb->deltamv,  
                                                 mb->directmv, // this has to be pre-initialized with b_mb->mvs[}  
                                         min_dx, max_dx, min_dy, max_dy,  
                                                 edged_width, 1, frame->quant, 0);  
   
   
 //                      i_sad16 = 65535;                /* remove the comment to disable any of the MODEs */  
 //                      f_sad16 = 65535;  
 //                      b_sad16 = 65535;  
 //                      d_sad16 = 65535;  
   
                         if (f_sad16 < b_sad16) {  
                                 best_sad = f_sad16;  
                                 mb->mode = MODE_FORWARD;  
                         } else {  
                                 best_sad = b_sad16;  
                                 mb->mode = MODE_BACKWARD;  
2990                          }                          }
   
                         if (i_sad16 < best_sad) {  
                                 best_sad = i_sad16;  
                                 mb->mode = MODE_INTERPOLATE;  
2991                          }                          }
2992    
2993                          if (d_sad16 < best_sad) {          do {
2994                    direction = 0;
2995                                  if (b_mb->mode == MODE_INTER4V)                  centerwp = bestwp;
                                 {  
   
                                 /* how to calc vectors is defined in standard. mvs[] and b_mvs[] are only for motion compensation */  
                                 /* for the bitstream, the value mb->deltamv is read directly */  
2996    
2997                              for (k = 0; k < 4; k++) {                  currwp = centerwp;
2998    
2999                                                  mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);                  currwp.duv[0].x--;
3000                              mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)                  gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3001                                                                                          ? ((TRB - TRD) * mb->directmv[k].x) / TRD                  if (gmcSAD < gmcminSAD)
3002                                                      : mb->mvs[k].x - mb->directmv[k].x);                  {       bestwp = currwp;
3003                            gmcminSAD = gmcSAD;
3004                              mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);                          direction = 1;
3005                          mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)                  }
3006                                                                                          ? ((TRB - TRD) * mb->directmv[k].y) / TRD                  else
3007                                              : mb->mvs[k].y - mb->directmv[k].y);                  {
3008                    currwp = centerwp; currwp.duv[0].x++;
3009                    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
3026                    {
3027                    currwp = centerwp; currwp.duv[0].y++;
3028                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3029                    if (gmcSAD < gmcminSAD)
3030                    {       bestwp = currwp;
3031                            gmcminSAD = gmcSAD;
3032                            direction = 8;
3033                    }
3034                    }
3035                    if (direction) continue;
3036    
3037                    currwp = centerwp; currwp.duv[1].x++;
3038                    gmcSAD = globalSAD(&currwp, pParam, pMBs, current, pRef, pCurr, GMCblock);
3039                    if (gmcSAD < gmcminSAD)
3040                    {       bestwp = currwp;
3041                            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.347  
changed lines
  Added in v.1129

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