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

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