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

Legend:
Removed from v.677  
changed lines
  Added in v.1075

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