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

Legend:
Removed from v.430  
changed lines
  Added in v.1136

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