[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 252, Sun Jun 30 10:46:29 2002 UTC branches/dev-api-4/xvidcore/src/motion/motion_est.c revision 949, Wed Mar 26 14:56:49 2003 UTC
# Line 1  Line 1 
1  /**************************************************************************  /**************************************************************************
2   *   *
3   *  Modifications:   *      XVID MPEG-4 VIDEO CODEC
4     *      motion estimation
5   *   *
6   *      01.05.2002      updated MotionEstimationBVOP   *      This program is an implementation of a part of one or more MPEG-4
7   *      25.04.2002 partial prevMB conversion   *      Video tools as specified in ISO/IEC 14496-2 standard.  Those intending
8   *  22.04.2002 remove some compile warning by chenm001 <chenm001@163.com>   *      to use this software module in hardware or software products are
9   *  14.04.2002 added MotionEstimationBVOP()   *      advised that its use may infringe existing patents or copyrights, and
10   *  02.04.2002 add EPZS(^2) as ME algorithm, use PMV_USESQUARES to choose between   *      any such use would be at such party's own risk.  The original
11   *             EPZS and EPZS^2   *      developer of this software module and his/her company, and subsequent
12   *  08.02.2002 split up PMVfast into three routines: PMVFast, PMVFast_MainLoop   *      editors and their companies, will have no liability for use of this
13   *             PMVFast_Refine to support multiple searches with different start points   *      software or modifications or derivatives thereof.
  *  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.  
14   *   *
15   *  Michael Militzer <isibaar@videocoding.de>   *      This program is free software; you can redistribute it and/or modify
16     *      it under the terms of the GNU General Public License as published by
17     *      the Free Software Foundation; either version 2 of the License, or
18     *      (at your option) any later version.
19   *   *
20   **************************************************************************/   *      This program is distributed in the hope that it will be useful,
21     *      but WITHOUT ANY WARRANTY; without even the implied warranty of
22     *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     *      GNU General Public License for more details.
24     *
25     *      You should have received a copy of the GNU General Public License
26     *      along with this program; if not, write to the Free Software
27     *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28     *
29     *************************************************************************/
30    
31  #include <assert.h>  #include <assert.h>
32  #include <stdio.h>  #include <stdio.h>
33  #include <stdlib.h>  #include <stdlib.h>
34    #include <string.h>     // memcpy
35    #include <math.h>       // lrint
36    
37  #include "../encoder.h"  #include "../encoder.h"
38  #include "../utils/mbfunctions.h"  #include "../utils/mbfunctions.h"
39  #include "../prediction/mbprediction.h"  #include "../prediction/mbprediction.h"
40  #include "../global.h"  #include "../global.h"
41  #include "../utils/timer.h"  #include "../utils/timer.h"
42    #include "../image/interpolate8x8.h"
43    #include "motion_est.h"
44  #include "motion.h"  #include "motion.h"
45  #include "sad.h"  #include "sad.h"
46    #include "../utils/emms.h"
47    #include "../dct/fdct.h"
48    
49  // very large value  /*****************************************************************************
50  #define MV_MAX_ERROR    (4096 * 256)   * Modified rounding tables -- declared in motion.h
51     * Original tables see ISO spec tables 7-6 -> 7-9
52     ****************************************************************************/
53    
54    const uint32_t roundtab[16] =
55    {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2 };
56    
57    /* K = 4 */
58    const uint32_t roundtab_76[16] =
59    { 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1 };
60    
61    /* K = 2 */
62    const uint32_t roundtab_78[8] =
63    { 0, 0, 1, 1, 0, 0, 0, 1  };
64    
65    /* K = 1 */
66    const uint32_t roundtab_79[4] =
67    { 0, 1, 0, 0 };
68    
69    #define INITIAL_SKIP_THRESH     (10)
70    #define FINAL_SKIP_THRESH       (50)
71    #define MAX_SAD00_FOR_SKIP      (20)
72    #define MAX_CHROMA_SAD_FOR_SKIP (22)
73    
74    #define CHECK_CANDIDATE(X,Y,D) { \
75    CheckCandidate((X),(Y), (D), &iDirection, data ); }
76    
77    /*****************************************************************************
78     * Code
79     ****************************************************************************/
80    
81  // stop search if sdelta < THRESHOLD  static __inline uint32_t
82  #define MV16_THRESHOLD  192  d_mv_bits(int x, int y, const VECTOR pred, const uint32_t iFcode, const int qpel, const int rrv)
83  #define MV8_THRESHOLD   56  {
84            int xb, yb;
85            x = qpel ? x<<1 : x;
86            y = qpel ? y<<1 : y;
87            if (rrv) { x = RRV_MV_SCALEDOWN(x); y = RRV_MV_SCALEDOWN(y); }
88    
89            x -= pred.x;
90            y -= pred.y;
91    
92            if (x) {
93                    x = ABS(x);
94                    x += (1 << (iFcode - 1)) - 1;
95                    x >>= (iFcode - 1);
96                    if (x > 32) x = 32;
97                    xb = mvtab[x] + iFcode;
98            } else xb = 1;
99    
100            if (y) {
101                    y = ABS(y);
102                    y += (1 << (iFcode - 1)) - 1;
103                    y >>= (iFcode - 1);
104                    if (y > 32) y = 32;
105                    yb = mvtab[y] + iFcode;
106            } else yb = 1;
107            return xb + yb;
108    }
109    
110    static int32_t ChromaSAD2(int fx, int fy, int bx, int by, const SearchData * const data)
111    {
112            int sad;
113            const uint32_t stride = data->iEdgedWidth/2;
114            uint8_t * f_refu = data->RefQ,
115                    * f_refv = data->RefQ + 8,
116                    * b_refu = data->RefQ + 16,
117                    * b_refv = data->RefQ + 24;
118    
119            switch (((fx & 1) << 1) | (fy & 1))     {
120                    case 0:
121                            fx = fx / 2; fy = fy / 2;
122                            f_refu = (uint8_t*)data->RefCU + fy * stride + fx, stride;
123                            f_refv = (uint8_t*)data->RefCV + fy * stride + fx, stride;
124                            break;
125                    case 1:
126                            fx = fx / 2; fy = (fy - 1) / 2;
127                            interpolate8x8_halfpel_v(f_refu, data->RefCU + fy * stride + fx, stride, data->rounding);
128                            interpolate8x8_halfpel_v(f_refv, data->RefCV + fy * stride + fx, stride, data->rounding);
129                            break;
130                    case 2:
131                            fx = (fx - 1) / 2; fy = fy / 2;
132                            interpolate8x8_halfpel_h(f_refu, data->RefCU + fy * stride + fx, stride, data->rounding);
133                            interpolate8x8_halfpel_h(f_refv, data->RefCV + fy * stride + fx, stride, data->rounding);
134                            break;
135                    default:
136                            fx = (fx - 1) / 2; fy = (fy - 1) / 2;
137                            interpolate8x8_halfpel_hv(f_refu, data->RefCU + fy * stride + fx, stride, data->rounding);
138                            interpolate8x8_halfpel_hv(f_refv, data->RefCV + fy * stride + fx, stride, data->rounding);
139                            break;
140            }
141    
142  #define NEIGH_MOVE_THRESH 0          switch (((bx & 1) << 1) | (by & 1))     {
143  // how much a block's MV must differ from his neighbour                  case 0:
144  // to be search for INTER4V. The more, the faster...                          bx = bx / 2; by = by / 2;
145                            b_refu = (uint8_t*)data->b_RefCU + by * stride + bx, stride;
146                            b_refv = (uint8_t*)data->b_RefCV + by * stride + bx, stride;
147                            break;
148                    case 1:
149                            bx = bx / 2; by = (by - 1) / 2;
150                            interpolate8x8_halfpel_v(b_refu, data->b_RefCU + by * stride + bx, stride, data->rounding);
151                            interpolate8x8_halfpel_v(b_refv, data->b_RefCV + by * stride + bx, stride, data->rounding);
152                            break;
153                    case 2:
154                            bx = (bx - 1) / 2; by = by / 2;
155                            interpolate8x8_halfpel_h(b_refu, data->b_RefCU + by * stride + bx, stride, data->rounding);
156                            interpolate8x8_halfpel_h(b_refv, data->b_RefCV + by * stride + bx, stride, data->rounding);
157                            break;
158                    default:
159                            bx = (bx - 1) / 2; by = (by - 1) / 2;
160                            interpolate8x8_halfpel_hv(b_refu, data->b_RefCU + by * stride + bx, stride, data->rounding);
161                            interpolate8x8_halfpel_hv(b_refv, data->b_RefCV + by * stride + bx, stride, data->rounding);
162                            break;
163            }
164    
165  /* sad16(0,0) bias; mpeg4 spec suggests nb/2+1 */          sad = sad8bi(data->CurU, b_refu, f_refu, stride);
166  /* nb  = vop pixels * 2^(bpp-8) */          sad += sad8bi(data->CurV, b_refv, f_refv, stride);
 #define MV16_00_BIAS    (128+1)  
 #define MV8_00_BIAS     (0)  
167    
168  /* INTER bias for INTER/INTRA decision; mpeg4 spec suggests 2*nb */          return sad;
169  #define MV16_INTER_BIAS 512  }
170    
 /* Parameters which control inter/inter4v decision */  
 #define IMV16X16                        5  
171    
172  /* vector map (vlc delta size) smoother parameters */  static int32_t
173  #define NEIGH_TEND_16X16        2  ChromaSAD(int dx, int dy, const SearchData * const data)
174  #define NEIGH_TEND_8X8          2  {
175            int sad;
176            const uint32_t stride = data->iEdgedWidth/2;
177    
178  // fast ((A)/2)*2          if (dx == data->temp[5] && dy == data->temp[6]) return data->temp[7]; //it has been checked recently
179  #define EVEN(A)         (((A)<0?(A)+1:(A)) & ~1)          data->temp[5] = dx; data->temp[6] = dy; // backup
180    
181  #define MVzero(A) ( ((A).x)==(0) && ((A).y)==(0) )          switch (((dx & 1) << 1) | (dy & 1))     {
182  #define MVequal(A,B) ( ((A).x)==((B).x) && ((A).y)==((B).y) )                  case 0:
183                            dx = dx / 2; dy = dy / 2;
184                            sad = sad8(data->CurU, data->RefCU + dy * stride + dx, stride);
185                            sad += sad8(data->CurV, data->RefCV + dy * stride + dx, stride);
186                            break;
187                    case 1:
188                            dx = dx / 2; dy = (dy - 1) / 2;
189                            sad = sad8bi(data->CurU, data->RefCU + dy * stride + dx, data->RefCU + (dy+1) * stride + dx, stride);
190                            sad += sad8bi(data->CurV, data->RefCV + dy * stride + dx, data->RefCV + (dy+1) * stride + dx, stride);
191                            break;
192                    case 2:
193                            dx = (dx - 1) / 2; dy = dy / 2;
194                            sad = sad8bi(data->CurU, data->RefCU + dy * stride + dx, data->RefCU + dy * stride + dx+1, stride);
195                            sad += sad8bi(data->CurV, data->RefCV + dy * stride + dx, data->RefCV + dy * stride + dx+1, stride);
196                            break;
197                    default:
198                            dx = (dx - 1) / 2; dy = (dy - 1) / 2;
199                            interpolate8x8_halfpel_hv(data->RefQ, data->RefCU + dy * stride + dx, stride, data->rounding);
200                            sad = sad8(data->CurU, data->RefQ, stride);
201    
202  int32_t PMVfastSearch16(const uint8_t * const pRef,                          interpolate8x8_halfpel_hv(data->RefQ, data->RefCV + dy * stride + dx, stride, data->rounding);
203                                                  const uint8_t * const pRefH,                          sad += sad8(data->CurV, data->RefQ, stride);
204                                                  const uint8_t * const pRefV,                          break;
205                                                  const uint8_t * const pRefHV,          }
206                                                  const IMAGE * const pCur,          data->temp[7] = sad; //backup, part 2
207                                                  const int x,          return sad;
208                                                  const int 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);  
209    
210  int32_t EPZSSearch16(const uint8_t * const pRef,  static __inline const uint8_t *
211                                           const uint8_t * const pRefH,  GetReferenceB(const int x, const int y, const uint32_t dir, const SearchData * const data)
212                                           const uint8_t * const pRefV,  {
213                                           const uint8_t * const pRefHV,  //      dir : 0 = forward, 1 = backward
214                                           const IMAGE * const pCur,          switch ( (dir << 2) | ((x&1)<<1) | (y&1) ) {
215                                           const int x,                  case 0 : return data->Ref + x/2 + (y/2)*(data->iEdgedWidth);
216                                           const int y,                  case 1 : return data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth);
217                                           const uint32_t MotionFlags,                  case 2 : return data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth);
218                                           const uint32_t iQuant,                  case 3 : return data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth);
219                                           const uint32_t iFcode,                  case 4 : return data->bRef + x/2 + (y/2)*(data->iEdgedWidth);
220                                           const MBParam * const pParam,                  case 5 : return data->bRefV + x/2 + ((y-1)/2)*(data->iEdgedWidth);
221                                           const MACROBLOCK * const pMBs,                  case 6 : return data->bRefH + (x-1)/2 + (y/2)*(data->iEdgedWidth);
222                                           const MACROBLOCK * const prevMBs,                  default : return data->bRefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth);
223                                           VECTOR * const currMV,          }
224                                           VECTOR * const currPMV);  }
225    
226    // this is a simpler copy of GetReferenceB, but as it's __inline anyway, we can keep the two separate
227    static __inline const uint8_t *
228    GetReference(const int x, const int y, const SearchData * const data)
229    {
230            switch ( ((x&1)<<1) | (y&1) ) {
231                    case 0 : return data->Ref + x/2 + (y/2)*(data->iEdgedWidth);
232                    case 3 : return data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth);
233                    case 1 : return data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth);
234                    default : return data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth);      //case 2
235            }
236    }
237    
238  int32_t PMVfastSearch8(const uint8_t * const pRef,  static uint8_t *
239                                             const uint8_t * const pRefH,  Interpolate8x8qpel(const int x, const int y, const uint32_t block, const uint32_t dir, const SearchData * const data)
240                                             const uint8_t * const pRefV,  {
241                                             const uint8_t * const pRefHV,  // create or find a qpel-precision reference picture; return pointer to it
242                                             const IMAGE * const pCur,          uint8_t * Reference = data->RefQ + 16*dir;
243                                             const int x,          const uint32_t iEdgedWidth = data->iEdgedWidth;
244                                             const int y,          const uint32_t rounding = data->rounding;
245                                             const int start_x,          const int halfpel_x = x/2;
246                                             const int start_y,          const int halfpel_y = y/2;
247                                             const uint32_t MotionFlags,          const uint8_t *ref1, *ref2, *ref3, *ref4;
                                            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);  
248    
249  int32_t EPZSSearch8(const uint8_t * const pRef,          ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
250                                          const uint8_t * const pRefH,          ref1 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
251                                          const uint8_t * const pRefV,          switch( ((x&1)<<1) + (y&1) ) {
252                                          const uint8_t * const pRefHV,          case 0: // pure halfpel position
253                                          const IMAGE * const pCur,                  return (uint8_t *) ref1;
254                                          const int x,                  break;
                                         const int y,  
                                         const int start_x,  
                                         const int start_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);  
255    
256            case 1: // x halfpel, y qpel - top or bottom during qpel refinement
257                    ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
258                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
259                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
260                    break;
261    
262  typedef int32_t(MainSearch16Func) (const uint8_t * const pRef,          case 2: // x qpel, y halfpel - left or right during qpel refinement
263                                                                     const uint8_t * const pRefH,                  ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
264                                                                     const uint8_t * const pRefV,                  ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
265                                                                     const uint8_t * const pRefHV,                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
266                                                                     const uint8_t * const cur,                  break;
                                                                    const int x,  
                                                                    const int y,  
                                                                    int32_t startx,  
                                                                    int32_t starty,  
                                                                    int32_t iMinSAD,  
                                                                    VECTOR * const currMV,  
                                                                    const VECTOR * const pmv,  
                                                                    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);  
267    
268  typedef MainSearch16Func *MainSearch16FuncPtr;          default: // x and y in qpel resolution - the "corners" (top left/right and
269                             // bottom left/right) during qpel refinement
270                    ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
271                    ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
272                    ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);
273                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
274                    ref3 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
275                    ref4 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
276                    interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
277                    break;
278            }
279            return Reference;
280    }
281    
282    static uint8_t *
283    Interpolate16x16qpel(const int x, const int y, const uint32_t dir, const SearchData * const data)
284    {
285    // create or find a qpel-precision reference picture; return pointer to it
286            uint8_t * Reference = data->RefQ + 16*dir;
287            const uint32_t iEdgedWidth = data->iEdgedWidth;
288            const uint32_t rounding = data->rounding;
289            const int halfpel_x = x/2;
290            const int halfpel_y = y/2;
291            const uint8_t *ref1, *ref2, *ref3, *ref4;
292    
293  typedef int32_t(MainSearch8Func) (const uint8_t * const pRef,          ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
294                                                                    const uint8_t * const pRefH,          switch( ((x&1)<<1) + (y&1) ) {
295                                                                    const uint8_t * const pRefV,          case 3: // x and y in qpel resolution - the "corners" (top left/right and
296                                                                    const uint8_t * const pRefHV,                           // bottom left/right) during qpel refinement
297                                                                    const uint8_t * const cur,                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
298                                                                    const int x,                  ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
299                                                                    const int y,                  ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);
300                                                                    int32_t startx,                  interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
301                                                                    int32_t starty,                  interpolate8x8_avg4(Reference+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, rounding);
302                                                                    int32_t iMinSAD,                  interpolate8x8_avg4(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, rounding);
303                                                                    VECTOR * const currMV,                  interpolate8x8_avg4(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, rounding);
304                                                                    const VECTOR * const pmv,                  break;
                                                                   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);  
   
 typedef MainSearch8Func *MainSearch8FuncPtr;  
   
 static int32_t lambda_vec16[32] =       /* rounded values for lambda param for weight of motion bits as in modified H.26L */  
 { 0, (int) (1.00235 + 0.5), (int) (1.15582 + 0.5), (int) (1.31976 + 0.5),  
                 (int) (1.49591 + 0.5), (int) (1.68601 + 0.5),  
         (int) (1.89187 + 0.5), (int) (2.11542 + 0.5), (int) (2.35878 + 0.5),  
                 (int) (2.62429 + 0.5), (int) (2.91455 + 0.5),  
         (int) (3.23253 + 0.5), (int) (3.58158 + 0.5), (int) (3.96555 + 0.5),  
                 (int) (4.38887 + 0.5), (int) (4.85673 + 0.5),  
         (int) (5.37519 + 0.5), (int) (5.95144 + 0.5), (int) (6.59408 + 0.5),  
                 (int) (7.31349 + 0.5), (int) (8.12242 + 0.5),  
         (int) (9.03669 + 0.5), (int) (10.0763 + 0.5), (int) (11.2669 + 0.5),  
                 (int) (12.6426 + 0.5), (int) (14.2493 + 0.5),  
         (int) (16.1512 + 0.5), (int) (18.442 + 0.5), (int) (21.2656 + 0.5),  
                 (int) (24.8580 + 0.5), (int) (29.6436 + 0.5),  
         (int) (36.4949 + 0.5)  
 };  
   
 static int32_t *lambda_vec8 = lambda_vec16;     /* same table for INTER and INTER4V for now */  
305    
306            case 1: // x halfpel, y qpel - top or bottom during qpel refinement
307                    ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
308                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
309                    interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
310                    interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
311                    interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
312                    break;
313    
314            case 2: // x qpel, y halfpel - left or right during qpel refinement
315                    ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
316                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
317                    interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
318                    interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
319                    interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
320                    break;
321    
322  // mv.length table          case 0: // pure halfpel position
323  static const uint32_t mvtab[33] = {                  return (uint8_t *) ref1;
324          1, 2, 3, 4, 6, 7, 7, 7,          }
325          9, 9, 9, 10, 10, 10, 10, 10,          return Reference;
326          10, 10, 10, 10, 10, 10, 10, 10,  }
         10, 11, 11, 11, 11, 11, 11, 12, 12  
 };  
327    
328    /* CHECK_CANDIATE FUNCTIONS START */
329    
330  static __inline uint32_t  static void
331  mv_bits(int32_t component,  CheckCandidate16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                 const uint32_t iFcode)  
332  {  {
333          if (component == 0)          int xc, yc;
334                  return 1;          const uint8_t * Reference;
335            VECTOR * current;
336          if (component < 0)          int32_t sad; uint32_t t;
                 component = -component;  
337    
338          if (iFcode == 1) {          if ( (x > data->max_dx) || (x < data->min_dx)
339                  if (component > 32)                  || (y > data->max_dy) || (y < data->min_dy) ) return;
                         component = 32;  
340    
341                  return mvtab[component] + 1;          if (!data->qpel_precision) {
342                    Reference = GetReference(x, y, data);
343                    current = data->currentMV;
344                    xc = x; yc = y;
345            } else { // x and y are in 1/4 precision
346                    Reference = Interpolate16x16qpel(x, y, 0, data);
347                    xc = x/2; yc = y/2; //for chroma sad
348                    current = data->currentQMV;
349          }          }
350    
351          component += (1 << (iFcode - 1)) - 1;          sad = sad16v(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
352          component >>= (iFcode - 1);          t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
353    
354            sad += (data->lambda16 * t * sad)>>10;
355            data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;
356    
357          if (component > 32)          if (data->chroma) sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
358                  component = 32;                                                                                                          (yc >> 1) + roundtab_79[yc & 0x3], data);
359    
360          return mvtab[component] + 1 + iFcode - 1;          if (sad < data->iMinSAD[0]) {
361                    data->iMinSAD[0] = sad;
362                    current[0].x = x; current[0].y = y;
363                    *dir = Direction;
364  }  }
365    
366            if (data->temp[1] < data->iMinSAD[1]) {
367                    data->iMinSAD[1] = data->temp[1]; current[1].x = x; current[1].y = y; }
368            if (data->temp[2] < data->iMinSAD[2]) {
369                    data->iMinSAD[2] = data->temp[2]; current[2].x = x; current[2].y = y; }
370            if (data->temp[3] < data->iMinSAD[3]) {
371                    data->iMinSAD[3] = data->temp[3]; current[3].x = x; current[3].y = y; }
372            if (data->temp[4] < data->iMinSAD[4]) {
373                    data->iMinSAD[4] = data->temp[4]; current[4].x = x; current[4].y = y; }
374    
 static __inline uint32_t  
 calc_delta_16(const int32_t dx,  
                           const int32_t dy,  
                           const uint32_t iFcode,  
                           const uint32_t iQuant)  
 {  
         return NEIGH_TEND_16X16 * lambda_vec16[iQuant] * (mv_bits(dx, iFcode) +  
                                                                                                           mv_bits(dy, iFcode));  
375  }  }
376    
377  static __inline uint32_t  static void
378  calc_delta_8(const int32_t dx,  CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                          const int32_t dy,  
                          const uint32_t iFcode,  
                          const uint32_t iQuant)  
379  {  {
380          return NEIGH_TEND_8X8 * lambda_vec8[iQuant] * (mv_bits(dx, iFcode) +          int32_t sad; uint32_t t;
381                                                                                                     mv_bits(dy, iFcode));          const uint8_t * Reference;
382    
383            if ( (x > data->max_dx) || (x < data->min_dx)
384                    || (y > data->max_dy) || (y < data->min_dy) ) return;
385    
386            if (!data->qpel_precision) Reference = GetReference(x, y, data);
387            else Reference = Interpolate8x8qpel(x, y, 0, 0, data);
388    
389            sad = sad8(data->Cur, Reference, data->iEdgedWidth);
390            t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
391    
392            sad += (data->lambda8 * t * (sad+NEIGH_8X8_BIAS))>>10;
393    
394            if (sad < *(data->iMinSAD)) {
395                    *(data->iMinSAD) = sad;
396                    data->currentMV->x = x; data->currentMV->y = y;
397                    *dir = Direction;
398            }
399  }  }
400    
401    
402    static void
403    CheckCandidate32(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
404    {
405            uint32_t t;
406            const uint8_t * Reference;
407    
408            if ( (!(x&1) && x !=0) || (!(y&1) && y !=0) || //non-zero integer value
409                    (x > data->max_dx) || (x < data->min_dx)
410                    || (y > data->max_dy) || (y < data->min_dy) ) return;
411    
412            Reference = GetReference(x, y, data);
413            t = d_mv_bits(x, y, data->predMV, data->iFcode, 0, 1);
414    
415  #ifndef SEARCH16          data->temp[0] = sad32v_c(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
 #define SEARCH16        PMVfastSearch16  
 //#define SEARCH16  FullSearch16  
 //#define SEARCH16  EPZSSearch16  
 #endif  
416    
417  #ifndef SEARCH8          data->temp[0] += (data->lambda16 * t * data->temp[0]) >> 10;
418  #define SEARCH8         PMVfastSearch8          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;
 //#define SEARCH8   EPZSSearch8  
 #endif  
419    
420  bool          if (data->temp[0] < data->iMinSAD[0]) {
421  MotionEstimation(MBParam * const pParam,                  data->iMinSAD[0] = data->temp[0];
422                                   FRAMEINFO * const current,                  data->currentMV[0].x = x; data->currentMV[0].y = y;
423                                   FRAMEINFO * const reference,                  *dir = Direction; }
424                                   const IMAGE * const pRefH,  
425                                   const IMAGE * const pRefV,          if (data->temp[1] < data->iMinSAD[1]) {
426                                   const IMAGE * const pRefHV,                  data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
427                                   const uint32_t iLimit)          if (data->temp[2] < data->iMinSAD[2]) {
428                    data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
429            if (data->temp[3] < data->iMinSAD[3]) {
430                    data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
431            if (data->temp[4] < data->iMinSAD[4]) {
432                    data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
433    }
434    
435    static void
436    CheckCandidate16no4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
437  {  {
438          const uint32_t iWcount = pParam->mb_width;          int32_t sad, xc, yc;
439          const uint32_t iHcount = pParam->mb_height;          const uint8_t * Reference;
440          MACROBLOCK *const pMBs = current->mbs;          uint32_t t;
441          MACROBLOCK *const prevMBs = reference->mbs;          VECTOR * current;
         const IMAGE *const pCurrent = &current->image;  
         const IMAGE *const pRef = &reference->image;  
442    
443          const VECTOR zeroMV = { 0, 0 };          if ( (x > data->max_dx) | ( x < data->min_dx)
444                    | (y > data->max_dy) | (y < data->min_dy) ) return;
445    
446          int32_t x, y;          if (data->rrv && (!(x&1) && x !=0) | (!(y&1) && y !=0) ) return; //non-zero even value
         int32_t iIntra = 0;  
         VECTOR pmv;  
   
         if (sadInit)  
                 (*sadInit) ();  
   
         for (y = 0; y < iHcount; y++)  
                 for (x = 0; x < iWcount; x++) {  
                         MACROBLOCK *const pMB = &pMBs[x + y * iWcount];  
   
                         pMB->sad16 =  
                                 SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,  
                                                  y, current->motion_flags, current->quant,  
                                                  current->fcode, pParam, pMBs, prevMBs, &pMB->mv16,  
                                                  &pMB->pmvs[0]);  
447    
448                          if (0 < (pMB->sad16 - MV16_INTER_BIAS)) {          if (data->qpel_precision) { // x and y are in 1/4 precision
449                                  int32_t deviation;                  Reference = Interpolate16x16qpel(x, y, 0, data);
450                    current = data->currentQMV;
451                    xc = x/2; yc = y/2;
452            } else {
453                    Reference = GetReference(x, y, data);
454                    current = data->currentMV;
455                    xc = x; yc = y;
456            }
457            t = d_mv_bits(x, y, data->predMV, data->iFcode,
458                                            data->qpel^data->qpel_precision, data->rrv);
459    
460                                  deviation =          sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
461                                          dev16(pCurrent->y + x * 16 + y * 16 * pParam->edged_width,          sad += (data->lambda16 * t * sad)>>10;
                                                   pParam->edged_width);  
462    
463                                  if (deviation < (pMB->sad16 - MV16_INTER_BIAS)) {          if (data->chroma) sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
464                                          pMB->mode = MODE_INTRA;                                                                                  (yc >> 1) + roundtab_79[yc & 0x3], data);
                                         pMB->mv16 = pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =  
                                                 pMB->mvs[3] = zeroMV;  
                                         pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =  
                                                 pMB->sad8[3] = 0;  
465    
466                                          iIntra++;          if (sad < *(data->iMinSAD)) {
467                                          if (iIntra >= iLimit)                  *(data->iMinSAD) = sad;
468                                                  return 1;                  current->x = x; current->y = y;
469                    *dir = Direction;
470            }
471    }
472    
473                                          continue;  static void
474    CheckCandidate32I(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
475    {
476    // maximum speed - for P/B/I decision
477            int32_t sad;
478    
479            if ( (x > data->max_dx) || (x < data->min_dx)
480                    || (y > data->max_dy) || (y < data->min_dy) ) return;
481    
482            sad = sad32v_c(data->Cur, data->Ref + x/2 + (y/2)*(data->iEdgedWidth),
483                                                            data->iEdgedWidth, data->temp+1);
484    
485            if (sad < *(data->iMinSAD)) {
486                    *(data->iMinSAD) = sad;
487                    data->currentMV[0].x = x; data->currentMV[0].y = y;
488                    *dir = Direction;
489                                  }                                  }
490            if (data->temp[1] < data->iMinSAD[1]) {
491                    data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
492            if (data->temp[2] < data->iMinSAD[2]) {
493                    data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
494            if (data->temp[3] < data->iMinSAD[3]) {
495                    data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
496            if (data->temp[4] < data->iMinSAD[4]) {
497                    data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
498    
499                          }                          }
500    
501                          pmv = pMB->pmvs[0];  static void
502                          if (current->global_flags & XVID_INTER4V)  CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)
503                                  if ((!(current->global_flags & XVID_LUMIMASKING) ||  {
504                                           pMB->dquant == NO_CHANGE)) {          int32_t sad, xb, yb, xcf, ycf, xcb, ycb;
505                                          int32_t sad8 = IMV16X16 * current->quant;          uint32_t t;
506            const uint8_t *ReferenceF, *ReferenceB;
507                                          if (sad8 < pMB->sad16)          VECTOR *current;
   
                                                 sad8 += pMB->sad8[0] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x, 2 * y, pMB->mv16.x,  
                                                                         pMB->mv16.y, current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[0],  
                                                                         &pMB->pmvs[0]);  
   
                                         if (sad8 < pMB->sad16)  
                                                 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, current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[1],  
                                                                         &pMB->pmvs[1]);  
   
                                         if (sad8 < pMB->sad16)  
                                                 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, current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[2],  
                                                                         &pMB->pmvs[2]);  
   
                                         if (sad8 < pMB->sad16)  
                                                 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,  
                                                                         current->motion_flags, current->quant,  
                                                                         current->fcode, pParam, pMBs, prevMBs,  
                                                                         &pMB->mvs[3], &pMB->pmvs[3]);  
508    
509                                          /* decide: MODE_INTER or MODE_INTER4V          if ( (xf > data->max_dx) | (xf < data->min_dx)
510                                             mpeg4:   if (sad8 < pMB->sad16 - nb/2+1) use_inter4v                  | (yf > data->max_dy) | (yf < data->min_dy) ) return;
                                          */  
511    
512                                          if (sad8 < pMB->sad16) {          if (!data->qpel_precision) {
513                                                  pMB->mode = MODE_INTER4V;                  ReferenceF = GetReference(xf, yf, data);
514                                                  pMB->sad8[0] *= 4;                  xb = data->currentMV[1].x; yb = data->currentMV[1].y;
515                                                  pMB->sad8[1] *= 4;                  ReferenceB = GetReferenceB(xb, yb, 1, data);
516                                                  pMB->sad8[2] *= 4;                  current = data->currentMV;
517                                                  pMB->sad8[3] *= 4;                  xcf = xf; ycf = yf;
518                                                  continue;                  xcb = xb; ycb = yb;
519            } else {
520                    ReferenceF = Interpolate16x16qpel(xf, yf, 0, data);
521                    xb = data->currentQMV[1].x; yb = data->currentQMV[1].y;
522                    current = data->currentQMV;
523                    ReferenceB = Interpolate16x16qpel(xb, yb, 1, data);
524                    xcf = xf/2; ycf = yf/2;
525                    xcb = xb/2; ycb = yb/2;
526            }
527    
528            t = d_mv_bits(xf, yf, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0)
529                     + d_mv_bits(xb, yb, data->bpredMV, data->iFcode, data->qpel^data->qpel_precision, 0);
530    
531            sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
532            sad += (data->lambda16 * t * sad)>>10;
533    
534            if (data->chroma) sad += ChromaSAD2((xcf >> 1) + roundtab_79[xcf & 0x3],
535                                                                                    (ycf >> 1) + roundtab_79[ycf & 0x3],
536                                                                                    (xcb >> 1) + roundtab_79[xcb & 0x3],
537                                                                                    (ycb >> 1) + roundtab_79[ycb & 0x3], data);
538    
539            if (sad < *(data->iMinSAD)) {
540                    *(data->iMinSAD) = sad;
541                    current->x = xf; current->y = yf;
542                    *dir = Direction;
543            }
544                                          }                                          }
545    
546    static void
547    CheckCandidateDirect(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
548    {
549            int32_t sad = 0, xcf = 0, ycf = 0, xcb = 0, ycb = 0;
550            uint32_t k;
551            const uint8_t *ReferenceF;
552            const uint8_t *ReferenceB;
553            VECTOR mvs, b_mvs;
554    
555            if (( x > 31) | ( x < -32) | ( y > 31) | (y < -32)) return;
556    
557            for (k = 0; k < 4; k++) {
558                    mvs.x = data->directmvF[k].x + x;
559                    b_mvs.x = ((x == 0) ?
560                            data->directmvB[k].x
561                            : mvs.x - data->referencemv[k].x);
562    
563                    mvs.y = data->directmvF[k].y + y;
564                    b_mvs.y = ((y == 0) ?
565                            data->directmvB[k].y
566                            : mvs.y - data->referencemv[k].y);
567    
568                    if ( (mvs.x > data->max_dx) | (mvs.x < data->min_dx)
569                            | (mvs.y > data->max_dy) | (mvs.y < data->min_dy)
570                            | (b_mvs.x > data->max_dx) | (b_mvs.x < data->min_dx)
571                            | (b_mvs.y > data->max_dy) | (b_mvs.y < data->min_dy) ) return;
572    
573                    if (data->qpel) {
574                            xcf += mvs.x/2; ycf += mvs.y/2;
575                            xcb += b_mvs.x/2; ycb += b_mvs.y/2;
576                    } else {
577                            xcf += mvs.x; ycf += mvs.y;
578                            xcb += b_mvs.x; ycb += b_mvs.y;
579                            mvs.x *= 2; mvs.y *= 2; //we move to qpel precision anyway
580                            b_mvs.x *= 2; b_mvs.y *= 2;
581                                  }                                  }
582    
583                          pMB->mode = MODE_INTER;                  ReferenceF = Interpolate8x8qpel(mvs.x, mvs.y, k, 0, data);
584                          pMB->pmvs[0] = pmv;     /* pMB->pmvs[1] = pMB->pmvs[2] = pMB->pmvs[3]  are not needed for INTER */                  ReferenceB = Interpolate8x8qpel(b_mvs.x, b_mvs.y, k, 1, data);
                         pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mv16;  
                         pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] =  
                                 pMB->sad16;  
585    
586                    sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
587                                                    ReferenceF, ReferenceB, data->iEdgedWidth);
588                    if (sad > *(data->iMinSAD)) return;
589            }
590    
591            sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;
592    
593            if (data->chroma) sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],
594                                                                                    (ycf >> 3) + roundtab_76[ycf & 0xf],
595                                                                                    (xcb >> 3) + roundtab_76[xcb & 0xf],
596                                                                                    (ycb >> 3) + roundtab_76[ycb & 0xf], data);
597    
598            if (sad < *(data->iMinSAD)) {
599                    *(data->iMinSAD) = sad;
600                    data->currentMV->x = x; data->currentMV->y = y;
601                    *dir = Direction;
602                  }                  }
         return 0;  
603  }  }
604    
605  #define CHECK_MV16_ZERO {\  static void
606    if ( (0 <= max_dx) && (0 >= min_dx) \  CheckCandidateDirectno4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
     && (0 <= max_dy) && (0 >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \  
     iSAD += calc_delta_16(-pmv[0].x, -pmv[0].y, (uint8_t)iFcode, iQuant);\  
     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) - pmv[0].x, (Y) - pmv[0].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) - pmv[0].x, (Y) - pmv[0].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) - pmv[0].x, (Y) - pmv[0].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) - pmv[0].x, (Y) - pmv[0].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(-pmv[0].x, -pmv[0].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)-pmv[0].x, (Y)-pmv[0].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)-pmv[0].x, (Y)-pmv[0].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)-pmv[0].x, (Y)-pmv[0].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)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
 }  
   
 /* too slow and not fully functional at the moment */  
 /*  
 int32_t ZeroSearch16(  
                                         const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const IMAGE * const pCur,  
                                         const int x, const int y,  
                                         const uint32_t MotionFlags,  
                                         const uint32_t iQuant,  
                                         const uint32_t iFcode,  
                                         MBParam * const pParam,  
                                         const MACROBLOCK * const pMBs,  
                                         const MACROBLOCK * const prevMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
607  {  {
608          const int32_t iEdgedWidth = pParam->edged_width;          int32_t sad, xcf, ycf, xcb, ycb;
609          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;          const uint8_t *ReferenceF;
610          int32_t iSAD;          const uint8_t *ReferenceB;
611          int32_t pred_x,pred_y;          VECTOR mvs, b_mvs;
   
         get_pmv(pMBs, x, y, pParam->mb_width, 0, &pred_x, &pred_y);  
   
         iSAD = sad16( cur,  
                 get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth),  
                 iEdgedWidth, MV_MAX_ERROR);  
         if (iSAD <= iQuant * 96)  
                 iSAD -= MV16_00_BIAS;  
   
         currMV->x = 0;  
         currMV->y = 0;  
         currPMV->x = -pred_x;  
         currPMV->y = -pred_y;  
612    
613          return iSAD;          if (( x > 31) | ( x < -32) | ( y > 31) | (y < -32)) return;
614    
615  }          mvs.x = data->directmvF[0].x + x;
616  */          b_mvs.x = ((x == 0) ?
617                    data->directmvB[0].x
618                    : mvs.x - data->referencemv[0].x);
619    
620  int32_t          mvs.y = data->directmvF[0].y + y;
621  Diamond16_MainSearch(const uint8_t * const pRef,          b_mvs.y = ((y == 0) ?
622                                           const uint8_t * const pRefH,                  data->directmvB[0].y
623                                           const uint8_t * const pRefV,                  : mvs.y - data->referencemv[0].y);
624                                           const uint8_t * const pRefHV,  
625                                           const uint8_t * const cur,          if ( (mvs.x > data->max_dx) | (mvs.x < data->min_dx)
626                                           const int x,                  | (mvs.y > data->max_dy) | (mvs.y < data->min_dy)
627                                           const int y,                  | (b_mvs.x > data->max_dx) | (b_mvs.x < data->min_dx)
628                                           int32_t startx,                  | (b_mvs.y > data->max_dy) | (b_mvs.y < data->min_dy) ) return;
629                                           int32_t starty,  
630                                           int32_t iMinSAD,          if (data->qpel) {
631                                           VECTOR * const currMV,                  xcf = 4*(mvs.x/2); ycf = 4*(mvs.y/2);
632                                           const VECTOR * const pmv,                  xcb = 4*(b_mvs.x/2); ycb = 4*(b_mvs.y/2);
633                                           const int32_t min_dx,                  ReferenceF = Interpolate16x16qpel(mvs.x, mvs.y, 0, data);
634                                           const int32_t max_dx,                  ReferenceB = Interpolate16x16qpel(b_mvs.x, b_mvs.y, 1, data);
                                          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 iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = startx;  
         backupMV.y = starty;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
   
         if (iDirection)  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;  
   
                         if (iDirection != 2)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                    backupMV.y, 1);  
                         if (iDirection != 1)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                    backupMV.y, 2);  
                         if (iDirection != 4)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,  
                                                                                    backupMV.y - iDiamondSize, 3);  
                         if (iDirection != 3)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,  
                                                                                    backupMV.y + iDiamondSize, 4);  
635          } else {          } else {
636                  currMV->x = startx;                  xcf = 4*mvs.x; ycf = 4*mvs.y;
637                  currMV->y = starty;                  xcb = 4*b_mvs.x; ycb = 4*b_mvs.y;
638          }                  ReferenceF = GetReference(mvs.x, mvs.y, data);
639          return iMinSAD;                  ReferenceB = GetReferenceB(b_mvs.x, b_mvs.y, 1, data);
640  }  }
641    
642  int32_t          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
643  Square16_MainSearch(const uint8_t * const pRef,          sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * 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,  
                                         int32_t startx,  
                                         int32_t starty,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                         const VECTOR * const pmv,  
                                         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 = startx;  
         backupMV.y = starty;  
   
 /* 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  
 */  
644    
645          CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);          if (data->chroma) sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],
646          CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);                                                                                  (ycf >> 3) + roundtab_76[ycf & 0xf],
647          CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);                                                                                  (xcb >> 3) + roundtab_76[xcb & 0xf],
648          CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);                                                                                  (ycb >> 3) + roundtab_76[ycb & 0xf], data);
   
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 5);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 6);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 7);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 8);  
   
   
         if (iDirection)  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;  
649    
650                          switch (iDirection) {          if (sad < *(data->iMinSAD)) {
651                          case 1:                  *(data->iMinSAD) = sad;
652                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  data->currentMV->x = x; data->currentMV->y = y;
653                                                                                     backupMV.y, 1);                  *dir = Direction;
654                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,          }
655                                                                                   backupMV.y - iDiamondSize, 5);  }
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
                         case 2:  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
656    
                         case 3:  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
657    
658                          case 4:  static void
659                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize,  CheckCandidateBits16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
660                                                                                   3);  {
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 break;  
   
                         case 5:  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 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);  
                                 break;  
   
                         case 6:  
                                 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 - 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, 8);  
661    
662                                  break;          static int16_t in[64], coeff[64];
663            int32_t bits = 0, sum;
664            VECTOR * current;
665            const uint8_t * ptr;
666            int i, cbp = 0, t, xc, yc;
667    
668                          case 7:          if ( (x > data->max_dx) || (x < data->min_dx)
669                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  || (y > data->max_dy) || (y < data->min_dy) ) return;
                                                                                    backupMV.y, 1);  
                                 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, 7);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
670    
671                          case 8:          if (!data->qpel_precision) {
672                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y,                  ptr = GetReference(x, y, data);
673                                                                                   2);                  current = data->currentMV;
674                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize,                  xc = x; yc = y;
675                                                                                   4);          } else { // x and y are in 1/4 precision
676                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,                  ptr = Interpolate16x16qpel(x, y, 0, data);
677                                                                                   backupMV.y + iDiamondSize, 6);                  current = data->currentQMV;
678                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,                  xc = x/2; yc = y/2;
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         default:  
                                 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);  
   
                                 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);  
                                 break;  
679                          }                          }
680          } else {  
681                  currMV->x = startx;          for(i = 0; i < 4; i++) {
682                  currMV->y = starty;                  int s = 8*((i&1) + (i>>1)*data->iEdgedWidth);
683                    transfer_8to16subro(in, data->Cur + s, ptr + s, data->iEdgedWidth);
684                    fdct(in);
685                    if (data->lambda8 == 0) sum = quant_inter(coeff, in, data->lambda16);
686                    else sum = quant4_inter(coeff, in, data->lambda16);
687                    if (sum > 0) {
688                            cbp |= 1 << (5 - i);
689                            bits += data->temp[i] = CodeCoeffInter_CalcBits(coeff, scan_tables[0]);
690                    } else data->temp[i] = 0;
691          }          }
692          return iMinSAD;  
693            bits += t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
694    
695            if (bits < data->iMinSAD[0]) { // there is still a chance, adding chroma
696                    xc = (xc >> 1) + roundtab_79[xc & 0x3];
697                    yc = (yc >> 1) + roundtab_79[yc & 0x3];
698    
699                    //chroma U
700                    ptr = interpolate8x8_switch2(data->RefQ + 64, data->RefCU, 0, 0, xc, yc,  data->iEdgedWidth/2, data->rounding);
701                    transfer_8to16subro(in, ptr, data->CurU, data->iEdgedWidth/2);
702                    fdct(in);
703                    if (data->lambda8 == 0) sum = quant_inter(coeff, in, data->lambda16);
704                    else sum = quant4_inter(coeff, in, data->lambda16);
705                    if (sum > 0) {
706                            cbp |= 1 << (5 - 4);
707                            bits += CodeCoeffInter_CalcBits(coeff, scan_tables[0]);
708  }  }
709    
710                    if (bits < data->iMinSAD[0]) {
711                            //chroma V
712                            ptr = interpolate8x8_switch2(data->RefQ + 64, data->RefCV, 0, 0, xc, yc,  data->iEdgedWidth/2, data->rounding);
713                            transfer_8to16subro(in, ptr, data->CurV, data->iEdgedWidth/2);
714                            fdct(in);
715                            if (data->lambda8 == 0) sum = quant_inter(coeff, in, data->lambda16);
716                            else sum = quant4_inter(coeff, in, data->lambda16);
717                            if (sum > 0) {
718                                    cbp |= 1 << (5 - 5);
719                                    bits += CodeCoeffInter_CalcBits(coeff, scan_tables[0]);
720                            }
721                    }
722            }
723    
724  int32_t          bits += cbpy_tab[15-(cbp>>2)].len;
725  Full16_MainSearch(const uint8_t * const pRef,          bits += mcbpc_inter_tab[(MODE_INTER & 7) | ((cbp & 3) << 3)].len;
                                   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,  
                                   int32_t startx,  
                                   int32_t starty,  
                                   int32_t iMinSAD,  
                                   VECTOR * const currMV,  
                                   const VECTOR * const pmv,  
                                   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 = startx;  
         backupMV.y = starty;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV16_CANDIDATE(dx, dy);  
726    
727          return iMinSAD;          if (bits < data->iMinSAD[0]) {
728                    data->iMinSAD[0] = bits;
729                    current[0].x = x; current[0].y = y;
730                    *dir = Direction;
731  }  }
732    
733  int32_t          if (data->temp[0] + t < data->iMinSAD[1]) {
734  AdvDiamond16_MainSearch(const uint8_t * const pRef,                  data->iMinSAD[1] = data->temp[0] + t; current[1].x = x; current[1].y = y; }
735                                                  const uint8_t * const pRefH,          if (data->temp[1] < data->iMinSAD[2]) {
736                                                  const uint8_t * const pRefV,                  data->iMinSAD[2] = data->temp[1]; current[2].x = x; current[2].y = y; }
737                                                  const uint8_t * const pRefHV,          if (data->temp[2] < data->iMinSAD[3]) {
738                                                  const uint8_t * const cur,                  data->iMinSAD[3] = data->temp[2]; current[3].x = x; current[3].y = y; }
739                                                  const int x,          if (data->temp[3] < data->iMinSAD[4]) {
740                                                  const int y,                  data->iMinSAD[4] = data->temp[3]; current[4].x = x; current[4].y = y; }
741                                                  int32_t startx,  
742                                                  int32_t starty,  }
743                                                  int32_t iMinSAD,  static void
744                                                  VECTOR * const currMV,  CheckCandidateBits8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                                                 const VECTOR * const pmv,  
                                                 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)  
745  {  {
746    
747          int32_t iSAD;          static int16_t in[64], coeff[64];
748            int32_t sum, bits;
749            VECTOR * current;
750            const uint8_t * ptr;
751            int cbp;
752    
753  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */          if ( (x > data->max_dx) || (x < data->min_dx)
754                    || (y > data->max_dy) || (y < data->min_dy) ) return;
755    
756          if (iDirection) {          if (!data->qpel_precision) {
757                  CHECK_MV16_CANDIDATE(startx - iDiamondSize, starty);                  ptr = GetReference(x, y, data);
758                  CHECK_MV16_CANDIDATE(startx + iDiamondSize, starty);                  current = data->currentMV;
759                  CHECK_MV16_CANDIDATE(startx, starty - iDiamondSize);          } else { // x and y are in 1/4 precision
760                  CHECK_MV16_CANDIDATE(startx, starty + iDiamondSize);                  ptr = Interpolate8x8qpel(x, y, 0, 0, data);
761          } else {                  current = data->currentQMV;
762                  int bDirection = 1 + 2 + 4 + 8;          }
763    
764                  do {          transfer_8to16subro(in, data->Cur, ptr, data->iEdgedWidth);
765                          iDirection = 0;          fdct(in);
766                          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 (data->lambda8 == 0) sum = quant_inter(coeff, in, data->lambda16);
767                                  CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);          else sum = quant4_inter(coeff, in, data->lambda16);
768            if (sum > 0) {
769                    bits = CodeCoeffInter_CalcBits(coeff, scan_tables[0]);
770                    cbp = 1;
771            } else cbp = bits = 0;
772    
773                          if (bDirection & 2)          bits += sum = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
                                 CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);  
774    
775                          if (bDirection & 4)          if (bits < data->iMinSAD[0]) {
776                                  CHECK_MV16_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);                  data->temp[0] = cbp;
777                    data->iMinSAD[0] = bits;
778                    current[0].x = x; current[0].y = y;
779                    *dir = Direction;
780            }
781    }
782    
783                          if (bDirection & 8)  /* CHECK_CANDIATE FUNCTIONS END */
                                 CHECK_MV16_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);  
784    
785                          /* now we're doing diagonal checks near our candidate */  /* MAINSEARCH FUNCTIONS START */
786    
787                          if (iDirection)         //checking if anything found  static void
788    AdvDiamondSearch(int x, int y, const SearchData * const data, int bDirection)
789                          {                          {
790    
791    /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
792    
793            int iDirection;
794    
795            for(;;) { //forever
796                    iDirection = 0;
797                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
798                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
799                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
800                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
801    
802                    /* now we're doing diagonal checks near our candidate */
803    
804                    if (iDirection) {               //if anything found
805                                  bDirection = iDirection;                                  bDirection = iDirection;
806                                  iDirection = 0;                                  iDirection = 0;
807                                  startx = currMV->x;                          x = data->currentMV->x; y = data->currentMV->y;
808                                  starty = currMV->y;                          if (bDirection & 3) {   //our candidate is left or right
809                                  if (bDirection & 3)     //our candidate is left or right                                  CHECK_CANDIDATE(x, y + iDiamondSize, 8);
810                                  {                                  CHECK_CANDIDATE(x, y - iDiamondSize, 4);
811                                          CHECK_MV16_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);                          } else {                        // what remains here is up or down
812                                          CHECK_MV16_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y, 2);
813                                  } else                  // what remains here is up or down                                  CHECK_CANDIDATE(x - iDiamondSize, y, 1);
                                 {  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);  
814                                  }                                  }
815    
816                                  if (iDirection) {                                  if (iDirection) {
817                                          bDirection += iDirection;                                          bDirection += iDirection;
818                                          startx = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
                                         starty = currMV->y;  
819                                  }                                  }
820                          } else                          //about to quit, eh? not so fast....                  } else {                                //about to quit, eh? not so fast....
                         {  
821                                  switch (bDirection) {                                  switch (bDirection) {
822                                  case 2:                                  case 2:
823                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
824                                                                                           starty - iDiamondSize, 2 + 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
825                                          break;                                          break;
826                                  case 1:                                  case 1:
827                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
828                                                                                           starty - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty + iDiamondSize, 1 + 8);  
829                                          break;                                          break;
830                                  case 2 + 4:                                  case 2 + 4:
831                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
832                                                                                           starty - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
833                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                          starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
834                                          break;                                          break;
835                                  case 4:                                  case 4:
836                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
837                                                                                           starty - iDiamondSize, 2 + 4);                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty - iDiamondSize, 1 + 4);  
838                                          break;                                          break;
839                                  case 8:                                  case 8:
840                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
841                                                                                           starty + iDiamondSize, 2 + 8);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty + iDiamondSize, 1 + 8);  
842                                          break;                                          break;
843                                  case 1 + 4:                                  case 1 + 4:
844                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
845                                                                                           starty + iDiamondSize, 1 + 8);                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
846                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
                                                                                          starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty - iDiamondSize, 2 + 4);  
847                                          break;                                          break;
848                                  case 2 + 8:                                  case 2 + 8:
849                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
850                                                                                           starty - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
851                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                          starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
852                                          break;                                          break;
853                                  case 1 + 8:                                  case 1 + 8:
854                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
855                                                                                           starty - iDiamondSize, 2 + 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
856                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                                                                          starty + iDiamondSize, 2 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty + iDiamondSize, 1 + 8);  
857                                          break;                                          break;
858                                  default:                //1+2+4+8 == we didn't find anything at all                                  default:                //1+2+4+8 == we didn't find anything at all
859                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
860                                                                                           starty - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
861                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
862                                                                                           starty + iDiamondSize, 1 + 8);                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
863                                          break;                                          break;
864                                  }                                  }
865                                  if (!iDirection)                          if (!iDirection) break;         //ok, the end. really
                                         break;          //ok, the end. really  
                                 else {  
866                                          bDirection = iDirection;                                          bDirection = iDirection;
867                                          startx = currMV->x;                          x = data->currentMV->x; y = data->currentMV->y;
                                         starty = currMV->y;  
                                 }  
                         }  
868                  }                  }
                 while (1);                              //forever  
869          }          }
         return iMinSAD;  
870  }  }
871    
872  int32_t  static void
873  AdvDiamond8_MainSearch(const uint8_t * const pRef,  SquareSearch(int x, int y, const SearchData * const data, int bDirection)
                                            const uint8_t * const pRefH,  
                                            const uint8_t * const pRefV,  
                                            const uint8_t * const pRefHV,  
                                            const uint8_t * const cur,  
                                            const int x,  
                                            const int y,  
                                            int32_t startx,  
                                            int32_t starty,  
                                            int32_t iMinSAD,  
                                            VECTOR * const currMV,  
                                            const VECTOR * const pmv,  
                                            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)  
874  {  {
875            int iDirection;
876    
877          int32_t iSAD;          do {
878                    iDirection = 0;
879                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);
880                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);
881                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);
882                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128);
883                    if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64);
884                    if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128);
885                    if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128);
886                    if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128);
887    
888                    bDirection = iDirection;
889                    x = data->currentMV->x; y = data->currentMV->y;
890            } while (iDirection);
891    }
892    
893    static void
894    DiamondSearch(int x, int y, const SearchData * const data, int bDirection)
895    {
896    
897  /* 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) */
898    
899          if (iDirection) {          int iDirection;
                 CHECK_MV8_CANDIDATE(startx - iDiamondSize, starty);  
                 CHECK_MV8_CANDIDATE(startx + iDiamondSize, starty);  
                 CHECK_MV8_CANDIDATE(startx, starty - iDiamondSize);  
                 CHECK_MV8_CANDIDATE(startx, starty + iDiamondSize);  
         } else {  
                 int bDirection = 1 + 2 + 4 + 8;  
900    
901                  do {                  do {
902                          iDirection = 0;                          iDirection = 0;
903                          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);
904                                  CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);                  if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
905                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
906                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
907    
908                          if (bDirection & 2)                  /* now we're doing diagonal checks near our candidate */
                                 CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);  
909    
910                          if (bDirection & 4)                  if (iDirection) {               //checking if anything found
911                                  CHECK_MV8_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);                          bDirection = iDirection;
912                            iDirection = 0;
913                            x = data->currentMV->x; y = data->currentMV->y;
914                            if (bDirection & 3) {   //our candidate is left or right
915                                    CHECK_CANDIDATE(x, y + iDiamondSize, 8);
916                                    CHECK_CANDIDATE(x, y - iDiamondSize, 4);
917                            } else {                        // what remains here is up or down
918                                    CHECK_CANDIDATE(x + iDiamondSize, y, 2);
919                                    CHECK_CANDIDATE(x - iDiamondSize, y, 1);
920                            }
921                            bDirection += iDirection;
922                            x = data->currentMV->x; y = data->currentMV->y;
923                    }
924            }
925            while (iDirection);
926    }
927    
928                          if (bDirection & 8)  /* MAINSEARCH FUNCTIONS END */
                                 CHECK_MV8_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);  
929    
930                          /* now we're doing diagonal checks near our candidate */  static void
931    SubpelRefine(const SearchData * const data)
932    {
933    /* Do a half-pel or q-pel refinement */
934            const VECTOR centerMV = data->qpel_precision ? *data->currentQMV : *data->currentMV;
935            int iDirection; //only needed because macro expects it
936    
937            CHECK_CANDIDATE(centerMV.x, centerMV.y - 1, 0);
938            CHECK_CANDIDATE(centerMV.x + 1, centerMV.y - 1, 0);
939            CHECK_CANDIDATE(centerMV.x + 1, centerMV.y, 0);
940            CHECK_CANDIDATE(centerMV.x + 1, centerMV.y + 1, 0);
941            CHECK_CANDIDATE(centerMV.x, centerMV.y + 1, 0);
942            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y + 1, 0);
943            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y, 0);
944            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y - 1, 0);
945    }
946    
947    static __inline int
948    SkipDecisionP(const IMAGE * current, const IMAGE * reference,
949                                                            const int x, const int y,
950                                                            const uint32_t stride, const uint32_t iQuant, int rrv)
951    
                         if (iDirection)         //checking if anything found  
952                          {                          {
953                                  bDirection = iDirection;          if(!rrv) {
954                                  iDirection = 0;                  uint32_t sadC = sad8(current->u + x*8 + y*stride*8,
955                                  startx = currMV->x;                                                  reference->u + x*8 + y*stride*8, stride);
956                                  starty = currMV->y;                  if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
957                                  if (bDirection & 3)     //our candidate is left or right                  sadC += sad8(current->v + (x + y*stride)*8,
958                                  {                                                  reference->v + (x + y*stride)*8, stride);
959                                          CHECK_MV8_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);                  if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
960                                          CHECK_MV8_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);                  return 1;
961                                  } else                  // what remains here is up or down  
962            } else {
963                    uint32_t sadC = sad16(current->u + x*16 + y*stride*16,
964                                                    reference->u + x*16 + y*stride*16, stride, 256*4096);
965                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
966                    sadC += sad16(current->v + (x + y*stride)*16,
967                                                    reference->v + (x + y*stride)*16, stride, 256*4096);
968                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
969                    return 1;
970            }
971    }
972    
973    static __inline void
974    SkipMacroblockP(MACROBLOCK *pMB, const int32_t sad)
975                                  {                                  {
976                                          CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);          pMB->mode = MODE_NOT_CODED;
977                                          CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = zeroMV;
978            pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] = pMB->qmvs[3] = zeroMV;
979            pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
980                                  }                                  }
981    
982                                  if (iDirection) {  bool
983                                          bDirection += iDirection;  MotionEstimation(MBParam * const pParam,
984                                          startx = currMV->x;                                   FRAMEINFO * const current,
985                                          starty = currMV->y;                                   FRAMEINFO * const reference,
986                                     const IMAGE * const pRefH,
987                                     const IMAGE * const pRefV,
988                                     const IMAGE * const pRefHV,
989                                     const uint32_t iLimit)
990    {
991            MACROBLOCK *const pMBs = current->mbs;
992            const IMAGE *const pCurrent = &current->image;
993            const IMAGE *const pRef = &reference->image;
994    
995            uint32_t mb_width = pParam->mb_width;
996            uint32_t mb_height = pParam->mb_height;
997            const uint32_t iEdgedWidth = pParam->edged_width;
998            const uint32_t MotionFlags = MakeGoodMotionFlags(current->motion_flags, current->vop_flags, current->vol_flags);
999    
1000            uint32_t x, y;
1001            uint32_t iIntra = 0;
1002        int32_t sad00;
1003    
1004            // some pre-initialized thingies for SearchP
1005            int32_t temp[8];
1006            VECTOR currentMV[5];
1007            VECTOR currentQMV[5];
1008            int32_t iMinSAD[5];
1009            SearchData Data;
1010            memset(&Data, 0, sizeof(SearchData));
1011            Data.iEdgedWidth = iEdgedWidth;
1012            Data.currentMV = currentMV;
1013            Data.currentQMV = currentQMV;
1014            Data.iMinSAD = iMinSAD;
1015            Data.temp = temp;
1016            Data.iFcode = current->fcode;
1017            Data.rounding = pParam->m_rounding_type;
1018            Data.qpel = current->vol_flags & XVID_VOL_QUARTERPEL;
1019            Data.chroma = MotionFlags & XVID_ME_CHROMA16;
1020            Data.rrv = current->vop_flags & XVID_VOP_REDUCED;
1021    
1022            if ((current->vop_flags & XVID_VOP_REDUCED)) {
1023                    mb_width = (pParam->width + 31) / 32;
1024                    mb_height = (pParam->height + 31) / 32;
1025                    Data.qpel = 0;
1026            }
1027    
1028            Data.RefQ = pRefV->u; // a good place, also used in MC (for similar purpose)
1029            if (sadInit) (*sadInit) ();
1030    
1031            for (y = 0; y < mb_height; y++) {
1032                    for (x = 0; x < mb_width; x++)  {
1033                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1034    
1035                            if (!Data.rrv) pMB->sad16 =
1036                                    sad16v(pCurrent->y + (x + y * iEdgedWidth) * 16,
1037                                                            pRef->y + (x + y * iEdgedWidth) * 16,
1038                                                            pParam->edged_width, pMB->sad8 );
1039    
1040                            else pMB->sad16 =
1041                                    sad32v_c(pCurrent->y + (x + y * iEdgedWidth) * 32,
1042                                                            pRef->y + (x + y * iEdgedWidth) * 32,
1043                                                            pParam->edged_width, pMB->sad8 );
1044    
1045                            if (Data.chroma) {
1046                                    Data.temp[7] = sad8(pCurrent->u + x*8 + y*(iEdgedWidth/2)*8,
1047                                                                            pRef->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2)
1048                                                                    + sad8(pCurrent->v + (x + y*(iEdgedWidth/2))*8,
1049                                                                            pRef->v + (x + y*(iEdgedWidth/2))*8, iEdgedWidth/2);
1050                                    pMB->sad16 += Data.temp[7];
1051                            }
1052    
1053                            sad00 = pMB->sad16;
1054    
1055    //initial skip decision
1056    /* no early skip for GMC (global vector = skip vector is unknown!)  */
1057                            if (!(current->vol_flags & XVID_VOL_GMC))       { /* no fast SKIP for S(GMC)-VOPs */
1058                                    if (pMB->dquant == 0 && sad00 < pMB->quant * INITIAL_SKIP_THRESH * (Data.rrv ? 4:1) )
1059                                            if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, iEdgedWidth/2, pMB->quant, Data.rrv)) {
1060                                                    SkipMacroblockP(pMB, sad00);
1061                                                    continue;
1062                                            }
1063                            }
1064    
1065                            SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1066                                                    y, MotionFlags, current->vol_flags, pMB->quant,
1067                                                    &Data, pParam, pMBs, reference->mbs,
1068                                                    current->vop_flags & XVID_VOP_INTER4V, pMB);
1069    
1070    /* final skip decision, a.k.a. "the vector you found, really that good?" */
1071                            if (!(current->vol_flags & XVID_VOL_GMC))       {
1072                                    if ( pMB->dquant == 0 && sad00 < pMB->quant * MAX_SAD00_FOR_SKIP) {
1073                                            if (!(current->vop_flags & XVID_VOP_MODEDECISION_BITS)) {
1074                                                    if ( (100*pMB->sad16)/(sad00+1) > FINAL_SKIP_THRESH * (Data.rrv ? 4:1) )
1075                                                            if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, iEdgedWidth/2, pMB->quant, Data.rrv))
1076                                                                    SkipMacroblockP(pMB, sad00);
1077                                            } else { // BITS mode decision
1078                                                    if (pMB->sad16 > 10)
1079                                                            SkipMacroblockP(pMB, sad00);  // more than 10 bits would be used for this MB - skip
1080    
1081                                            }
1082                                  }                                  }
1083                          } else                          //about to quit, eh? not so fast....                          }
1084                            if (pMB->mode == MODE_INTRA)
1085                                    if (++iIntra > iLimit) return 1;
1086                    }
1087            }
1088    
1089            if (current->vol_flags & XVID_VOL_GMC ) /* GMC only for S(GMC)-VOPs */
1090                          {                          {
1091                                  switch (bDirection) {                  current->warp = GlobalMotionEst( pMBs, pParam, current, reference, pRefH, pRefV, pRefHV);
                                 case 2:  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1:  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 2 + 4:  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 4:  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         break;  
                                 case 8:  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 1 + 4:  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         break;  
                                 case 2 + 8:  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1 + 8:  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         break;  
                                 default:                //1+2+4+8 == we didn't find anything at all  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         break;  
1092                                  }                                  }
1093                                  if (!(iDirection))          return 0;
                                         break;          //ok, the end. really  
                                 else {  
                                         bDirection = iDirection;  
                                         startx = currMV->x;  
                                         starty = currMV->y;  
1094                                  }                                  }
1095    
1096    
1097    static __inline int
1098    make_mask(const VECTOR * const pmv, const int i)
1099    {
1100            int mask = 255, j;
1101            for (j = 0; j < i; j++) {
1102                    if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already
1103                    if (pmv[i].x == pmv[j].x) {
1104                            if (pmv[i].y == pmv[j].y + iDiamondSize) mask &= ~4;
1105                            else if (pmv[i].y == pmv[j].y - iDiamondSize) mask &= ~8;
1106                    } else
1107                            if (pmv[i].y == pmv[j].y) {
1108                                    if (pmv[i].x == pmv[j].x + iDiamondSize) mask &= ~1;
1109                                    else if (pmv[i].x == pmv[j].x - iDiamondSize) mask &= ~2;
1110                          }                          }
1111                  }                  }
1112                  while (1);                              //forever          return mask;
1113    }
1114    
1115    static __inline void
1116    PreparePredictionsP(VECTOR * const pmv, int x, int y, int iWcount,
1117                            int iHcount, const MACROBLOCK * const prevMB, int rrv)
1118    {
1119    
1120    //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself
1121            if (rrv) { iWcount /= 2; iHcount /= 2; }
1122    
1123            if ( (y != 0) && (x < (iWcount-1)) ) {          // [5] top-right neighbour
1124                    pmv[5].x = EVEN(pmv[3].x);
1125                    pmv[5].y = EVEN(pmv[3].y);
1126            } else pmv[5].x = pmv[5].y = 0;
1127    
1128            if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }// pmv[3] is left neighbour
1129            else pmv[3].x = pmv[3].y = 0;
1130    
1131            if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }// [4] top neighbour
1132            else pmv[4].x = pmv[4].y = 0;
1133    
1134            // [1] median prediction
1135            pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
1136    
1137            pmv[0].x = pmv[0].y = 0; // [0] is zero; not used in the loop (checked before) but needed here for make_mask
1138    
1139            pmv[2].x = EVEN(prevMB->mvs[0].x); // [2] is last frame
1140            pmv[2].y = EVEN(prevMB->mvs[0].y);
1141    
1142            if ((x < iWcount-1) && (y < iHcount-1)) {
1143                    pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); //[6] right-down neighbour in last frame
1144                    pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
1145            } else pmv[6].x = pmv[6].y = 0;
1146    
1147            if (rrv) {
1148                    int i;
1149                    for (i = 0; i < 7; i++) {
1150                            pmv[i].x = RRV_MV_SCALEUP(pmv[i].x);
1151                            pmv[i].y = RRV_MV_SCALEUP(pmv[i].y);
1152                    }
1153          }          }
         return iMinSAD;  
1154  }  }
1155    
1156    static int
1157    ModeDecision(const uint32_t iQuant, SearchData * const Data,
1158                    int inter4v,
1159                    MACROBLOCK * const pMB,
1160                    const MACROBLOCK * const pMBs,
1161                    const int x, const int y,
1162                    const MBParam * const pParam,
1163                    const uint32_t MotionFlags,
1164                    const uint32_t VopFlags)
1165    {
1166    
1167  int32_t          int mode = MODE_INTER;
 Full8_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,  
                                  int32_t startx,  
                                  int32_t starty,  
                                  int32_t iMinSAD,  
                                  VECTOR * const currMV,  
                                  const VECTOR * const pmv,  
                                  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 = startx;  
         backupMV.y = starty;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV8_CANDIDATE(dx, dy);  
1168    
1169          return iMinSAD;          if (!(VopFlags & XVID_VOP_MODEDECISION_BITS)) { //normal, fast, SAD-based mode decision
1170    //              int intra = 0;
1171                    int sad;
1172                    int InterBias = MV16_INTER_BIAS;
1173                    if (inter4v == 0 || Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
1174                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant) {
1175                                    mode = 0; //inter
1176                                    sad = Data->iMinSAD[0];
1177                    } else {
1178                            mode = MODE_INTER4V;
1179                            sad = Data->iMinSAD[1] + Data->iMinSAD[2] +
1180                                                    Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant;
1181                            Data->iMinSAD[0] = sad;
1182  }  }
1183    
1184                    /* intra decision */
1185    
1186                    if (iQuant > 8) InterBias += 100 * (iQuant - 8); // to make high quants work
1187                    if (y != 0)
1188                            if ((pMB - pParam->mb_width)->mode == MODE_INTRA ) InterBias -= 80;
1189                    if (x != 0)
1190                            if ((pMB - 1)->mode == MODE_INTRA ) InterBias -= 80;
1191    
1192  int32_t                  if (Data->chroma) InterBias += 50; // to compensate bigger SAD
1193  Halfpel16_Refine(const uint8_t * const pRef,                  if (Data->rrv) InterBias *= 4;
1194                                   const uint8_t * const pRefH,  
1195                                   const uint8_t * const pRefV,                  if (InterBias < pMB->sad16) {
1196                                   const uint8_t * const pRefHV,                          int32_t deviation;
1197                                   const uint8_t * const cur,                          if (!Data->rrv) deviation = dev16(Data->Cur, Data->iEdgedWidth);
1198                                   const int x,                          else deviation = dev16(Data->Cur, Data->iEdgedWidth) +
1199                                   const int y,                                  dev16(Data->Cur+8, Data->iEdgedWidth) +
1200                                   VECTOR * const currMV,                                  dev16(Data->Cur + 8*Data->iEdgedWidth, Data->iEdgedWidth) +
1201                                   int32_t iMinSAD,                                  dev16(Data->Cur+8+8*Data->iEdgedWidth, Data->iEdgedWidth);
                                  const VECTOR * const pmv,  
                                  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_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);  
         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);  
1202    
1203          return iMinSAD;                          if (deviation < (sad - InterBias))  return MODE_INTRA;// intra
1204  }  }
1205                    return mode;
1206    
1207            } else {
1208    
1209                    int bits, intra, i;
1210                    VECTOR backup[5], *v;
1211                    Data->lambda16 = iQuant;
1212            Data->lambda8 = (pParam->vol_flags & XVID_VOL_MPEGQUANT)?1:0;
1213    
1214                    v = Data->qpel ? Data->currentQMV : Data->currentMV;
1215                    for (i = 0; i < 5; i++) {
1216                            Data->iMinSAD[i] = 256*4096;
1217                            backup[i] = v[i];
1218                    }
1219    
1220                    bits = CountMBBitsInter(Data, pMBs, x, y, pParam, MotionFlags);
1221                    if (bits == 0) return MODE_INTER; // quick stop
1222    
1223                    if (inter4v) {
1224                            int inter4v = CountMBBitsInter4v(Data, pMB, pMBs, x, y, pParam, MotionFlags, backup);
1225                            if (inter4v < bits) { Data->iMinSAD[0] = bits = inter4v; mode = MODE_INTER4V; }
1226                    }
1227    
1228    
1229  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)                  intra = CountMBBitsIntra(Data);
1230    
1231                    if (intra < bits) { *Data->iMinSAD = bits = intra; return MODE_INTRA; }
1232    
1233  int32_t                  return mode;
1234  PMVfastSearch16(const uint8_t * const pRef,          }
1235    }
1236    
1237    static void
1238    SearchP(const IMAGE * const pRef,
1239                                  const uint8_t * const pRefH,                                  const uint8_t * const pRefH,
1240                                  const uint8_t * const pRefV,                                  const uint8_t * const pRefV,
1241                                  const uint8_t * const pRefHV,                                  const uint8_t * const pRefHV,
# Line 1227  Line 1243 
1243                                  const int x,                                  const int x,
1244                                  const int y,                                  const int y,
1245                                  const uint32_t MotionFlags,                                  const uint32_t MotionFlags,
1246                    const uint32_t VopFlags,
1247                                  const uint32_t iQuant,                                  const uint32_t iQuant,
1248                                  const uint32_t iFcode,                  SearchData * const Data,
1249                                  const MBParam * const pParam,                                  const MBParam * const pParam,
1250                                  const MACROBLOCK * const pMBs,                                  const MACROBLOCK * const pMBs,
1251                                  const MACROBLOCK * const prevMBs,                                  const MACROBLOCK * const prevMBs,
1252                                  VECTOR * const currMV,                  int inter4v,
1253                                  VECTOR * const currPMV)                  MACROBLOCK * const pMB)
1254  {  {
         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;  
1255    
1256          int32_t iFound;          int i, iDirection = 255, mask, threshA;
1257            VECTOR pmv[7];
1258    
1259          VECTOR newMV;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1260          VECTOR backupMV;                        /* just for PMVFAST */                                                  pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
1261    
1262          VECTOR pmv[4];          get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);
1263          int32_t psad[4];  
1264            Data->temp[5] = Data->temp[6] = 0; // chroma-sad cache
1265            i = Data->rrv ? 2 : 1;
1266            Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16*i;
1267            Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1268            Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1269    
1270            Data->Ref = pRef->y + (x + Data->iEdgedWidth*y) * 16*i;
1271            Data->RefH = pRefH + (x + Data->iEdgedWidth*y) * 16*i;
1272            Data->RefV = pRefV + (x + Data->iEdgedWidth*y) * 16*i;
1273            Data->RefHV = pRefHV + (x + Data->iEdgedWidth*y) * 16*i;
1274            Data->RefCV = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1275            Data->RefCU = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1276    
1277            Data->lambda16 = lambda_vec16[iQuant];
1278            Data->lambda8 = lambda_vec8[iQuant];
1279            Data->qpel_precision = 0;
1280    
1281            if (pMB->dquant != 0) inter4v = 0;
1282    
1283            for(i = 0; i < 5; i++)
1284                    Data->currentMV[i].x = Data->currentMV[i].y = 0;
1285    
1286            if (Data->qpel) Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1287            else Data->predMV = pmv[0];
1288    
1289            i = d_mv_bits(0, 0, Data->predMV, Data->iFcode, 0, 0);
1290            Data->iMinSAD[0] = pMB->sad16 + ((Data->lambda16 * i * pMB->sad16)>>10);
1291            Data->iMinSAD[1] = pMB->sad8[0] + ((Data->lambda8 * i * (pMB->sad8[0]+NEIGH_8X8_BIAS)) >> 10);
1292            Data->iMinSAD[2] = pMB->sad8[1];
1293            Data->iMinSAD[3] = pMB->sad8[2];
1294            Data->iMinSAD[4] = pMB->sad8[3];
1295    
1296            if ((!(VopFlags & XVID_VOP_MODEDECISION_BITS)) || (x | y)) {
1297                    threshA = Data->temp[0]; // that's where we keep this SAD atm
1298                    if (threshA < 512) threshA = 512;
1299                    else if (threshA > 1024) threshA = 1024;
1300            } else
1301                    threshA = 512;
1302    
1303          MainSearch16FuncPtr MainSearchPtr;          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
1304                                            prevMBs + x + y * pParam->mb_width, Data->rrv);
1305    
1306  //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;          if (!Data->rrv) {
1307          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;                  if (inter4v | Data->chroma) CheckCandidate = CheckCandidate16;
1308                            else CheckCandidate = CheckCandidate16no4v; //for extra speed
1309            } else CheckCandidate = CheckCandidate32;
1310    
1311    /* main loop. checking all predictions (but first, which is 0,0 and has been checked in MotionEstimation())*/
1312    
1313            for (i = 1; i < 7; i++) {
1314                    if (!(mask = make_mask(pmv, i)) ) continue;
1315                    CheckCandidate(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1316                    if (Data->iMinSAD[0] <= threshA) break;
1317            }
1318    
1319            if ((Data->iMinSAD[0] <= threshA) ||
1320                            (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
1321                            (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16))) {
1322                    if (!(VopFlags & XVID_VOP_MODEDECISION_BITS)) inter4v = 0;      }
1323            else {
1324    
1325          static int32_t threshA, threshB;                  MainSearchFunc * MainSearchPtr;
1326          int32_t bPredEq;                  if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1327          int32_t iMinSAD, iSAD;                  else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1328                            else MainSearchPtr = DiamondSearch;
1329    
1330  /* Get maximum range */                  MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
1331    
1332  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  /* extended search, diamond starting in 0,0 and in prediction.
1333            note that this search is/might be done in halfpel positions,
1334            which makes it more different than the diamond above */
1335    
1336          if (!(MotionFlags & PMV_HALFPEL16)) {                  if (MotionFlags & XVID_ME_EXTSEARCH16) {
1337                  min_dx = EVEN(min_dx);                          int32_t bSAD;
1338                  max_dx = EVEN(max_dx);                          VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
1339                  min_dy = EVEN(min_dy);                          if (Data->rrv) {
1340                  max_dy = EVEN(max_dy);                                  startMV.x = RRV_MV_SCALEUP(startMV.x);
1341                                    startMV.y = RRV_MV_SCALEUP(startMV.y);
1342          }          }
1343                            if (!(MVequal(startMV, backupMV))) {
1344                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1345    
1346          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1347          bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1348                                    if (bSAD < Data->iMinSAD[0]) {
1349          if ((x == 0) && (y == 0)) {                                          Data->currentMV[0] = backupMV;
1350                  threshA = 512;                                          Data->iMinSAD[0] = bSAD; }
                 threshB = 1024;  
   
         } else {  
                 threshA = psad[0];  
                 threshB = threshA + 256;  
                 if (threshA < 512)  
                         threshA = 512;  
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
1351          }          }
1352    
1353          iFound = 0;                          backupMV = Data->currentMV[0];
1354                            startMV.x = startMV.y = 1;
1355  /* Step 4: Calculate SAD around the Median prediction.                          if (!(MVequal(startMV, backupMV))) {
1356     MinSAD=SAD                                  bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
1357    
1358          *currMV = pmv[0];                       /* current best := prediction */                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1359          if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1360                  currMV->x = EVEN(currMV->x);                                  if (bSAD < Data->iMinSAD[0]) {
1361                  currMV->y = EVEN(currMV->y);                                          Data->currentMV[0] = backupMV;
1362                                            Data->iMinSAD[0] = bSAD; }
1363          }          }
   
         if (currMV->x > max_dx) {  
                 currMV->x = max_dx;  
1364          }          }
         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;  
1365          }          }
1366    
1367          iMinSAD =          if (MotionFlags & XVID_ME_HALFPELREFINE16)
1368                  sad16(cur,                  if ((!(MotionFlags & XVID_ME_HALFPELREFINE16_BITS)) || Data->iMinSAD[0] < 200*(int)iQuant)
1369                            get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,                          SubpelRefine(Data);
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - pmv[0].x, currMV->y - pmv[0].y,  
                                           (uint8_t) iFcode, iQuant);  
1370    
1371          if ((iMinSAD < 256) ||          for(i = 0; i < 5; i++) {
1372                  ((MVequal(*currMV, prevMB->mvs[0])) &&                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // initialize qpel vectors
1373                   ((uint32_t) iMinSAD < prevMB->sad16))) {                  Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
                 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;  
                         }  
                 }  
   
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
1374          }          }
1375    
1376            if (MotionFlags & XVID_ME_QUARTERPELREFINE16)
1377                    if ((!(MotionFlags & XVID_ME_QUARTERPELREFINE16_BITS)) || (Data->iMinSAD[0] < 200*(int)iQuant)) {
1378                            Data->qpel_precision = 1;
1379                            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1380                                            pParam->width, pParam->height, Data->iFcode, 1, 0);
1381    
1382  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion                          SubpelRefine(Data);
1383     vector of the median.                  }
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
1384    
1385          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[0])))          if ((!(VopFlags & XVID_VOP_MODEDECISION_BITS)) && (Data->iMinSAD[0] < (int32_t)iQuant * 30)) inter4v = 0;
                 iFound = 2;  
1386    
1387  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          if (inter4v && (!(VopFlags & XVID_VOP_MODEDECISION_BITS) ||
1388     Otherwise select large Diamond Search.                          (!(MotionFlags & XVID_ME_QUARTERPELREFINE8_BITS)) || (!(MotionFlags & XVID_ME_HALFPELREFINE8_BITS)) ||
1389  */                          ((!(MotionFlags & XVID_ME_EXTSEARCH_BITS)) && (!(MotionFlags&XVID_ME_EXTSEARCH8)) ))) {
1390                    // if decision is BITS-based and all refinement steps will be done in BITS domain, there is no reason to call this loop
1391    
1392          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))                  SearchData Data8;
1393                  iDiamondSize = 1;               // halfpel!                  memcpy(&Data8, Data, sizeof(SearchData)); //quick copy of common data
         else  
                 iDiamondSize = 2;               // halfpel!  
1394    
1395          if (!(MotionFlags & PMV_HALFPELDIAMOND16))                  Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
1396                  iDiamondSize *= 2;                  Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
1397                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
1398                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
1399    
1400  /*                  if ((Data->chroma) && (!(VopFlags & XVID_VOP_MODEDECISION_BITS))) {
1401     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.                          // chroma is only used for comparsion to INTER. if the comparsion will be done in BITS domain, there is no reason to compute it
1402     Also calculate (0,0) but do not subtract offset.                          int sumx = 0, sumy = 0;
1403     Let MinSAD be the smallest SAD up to this point.                          const int div = 1 + Data->qpel;
1404     If MV is (0,0) subtract offset.                          const VECTOR * const mv = Data->qpel ? pMB->qmvs : pMB->mvs;
 */  
1405    
1406  // (0,0) is always possible                          for (i = 0; i < 4; i++) {
1407                                    sumx += mv[i].x / div;
1408                                    sumy += mv[i].y / div;
1409                            }
1410    
1411          if (!MVzero(pmv[0]))                          Data->iMinSAD[1] += ChromaSAD(  (sumx >> 3) + roundtab_76[sumx & 0xf],
1412                  CHECK_MV16_ZERO;                                                                                          (sumy >> 3) + roundtab_76[sumy & 0xf], Data);
1413                    }
1414            }
1415    
1416  // previous frame MV is always possible          inter4v = ModeDecision(iQuant, Data, inter4v, pMB, pMBs, x, y, pParam, MotionFlags, VopFlags);
1417    
1418          if (!MVzero(prevMB->mvs[0]))          if (Data->rrv) {
1419                  if (!MVequal(prevMB->mvs[0], pmv[0]))                          Data->currentMV[0].x = RRV_MV_SCALEDOWN(Data->currentMV[0].x);
1420                          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);                          Data->currentMV[0].y = RRV_MV_SCALEDOWN(Data->currentMV[0].y);
1421            }
1422    
1423  // left neighbour, if allowed          if (inter4v == MODE_INTER) {
1424                    pMB->mode = MODE_INTER;
1425                    pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
1426                    pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = Data->iMinSAD[0];
1427    
1428          if (!MVzero(pmv[1]))                  if(Data->qpel) {
1429                  if (!MVequal(pmv[1], prevMB->mvs[0]))                          pMB->qmvs[0] = pMB->qmvs[1]
1430                          if (!MVequal(pmv[1], pmv[0])) {                                  = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1431                                  if (!(MotionFlags & PMV_HALFPEL16)) {                          pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1432                                          pmv[1].x = EVEN(pmv[1].x);                          pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;
1433                                          pmv[1].y = EVEN(pmv[1].y);                  } else {
1434                            pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1435                            pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
1436                                  }                                  }
1437    
1438                                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);          } else if (inter4v == MODE_INTER4V) {
1439                          }                  pMB->mode = MODE_INTER4V;
1440  // top neighbour, if allowed                  pMB->sad16 = Data->iMinSAD[0];
1441          if (!MVzero(pmv[2]))          } else { // INTRA mode
1442                  if (!MVequal(pmv[2], prevMB->mvs[0]))                  SkipMacroblockP(pMB, 0); // not skip, but similar enough
1443                          if (!MVequal(pmv[2], pmv[0]))                  pMB->mode = MODE_INTRA;
                                 if (!MVequal(pmv[2], pmv[1])) {  
                                         if (!(MotionFlags & PMV_HALFPEL16)) {  
                                                 pmv[2].x = EVEN(pmv[2].x);  
                                                 pmv[2].y = EVEN(pmv[2].y);  
1444                                          }                                          }
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
1445    
 // top right neighbour, if allowed  
                                         if (!MVzero(pmv[3]))  
                                                 if (!MVequal(pmv[3], prevMB->mvs[0]))  
                                                         if (!MVequal(pmv[3], pmv[0]))  
                                                                 if (!MVequal(pmv[3], pmv[1]))  
                                                                         if (!MVequal(pmv[3], pmv[2])) {  
                                                                                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                                                                                         pmv[3].x = EVEN(pmv[3].x);  
                                                                                         pmv[3].y = EVEN(pmv[3].y);  
                                                                                 }  
                                                                                 CHECK_MV16_CANDIDATE(pmv[3].x,  
                                                                                                                          pmv[3].y);  
1446                                                                          }                                                                          }
1447    
1448    static void
1449    Search8(const SearchData * const OldData,
1450                    const int x, const int y,
1451                    const uint32_t MotionFlags,
1452                    const MBParam * const pParam,
1453                    MACROBLOCK * const pMB,
1454                    const MACROBLOCK * const pMBs,
1455                    const int block,
1456                    SearchData * const Data)
1457    {
1458            int i = 0;
1459            Data->iMinSAD = OldData->iMinSAD + 1 + block;
1460            Data->currentMV = OldData->currentMV + 1 + block;
1461            Data->currentQMV = OldData->currentQMV + 1 + block;
1462    
1463            if(Data->qpel) {
1464                    Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1465                    if (block != 0) i = d_mv_bits(  Data->currentQMV->x, Data->currentQMV->y,
1466                                                                                    Data->predMV, Data->iFcode, 0, 0);
1467            } else {
1468                    Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1469                    if (block != 0) i = d_mv_bits(  Data->currentMV->x, Data->currentMV->y,
1470                                                                                    Data->predMV, Data->iFcode, 0, Data->rrv);
1471                                  }                                  }
1472    
1473          if ((MVzero(*currMV)) &&          *(Data->iMinSAD) += (Data->lambda8 * i * (*Data->iMinSAD + NEIGH_8X8_BIAS))>>10;
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV16_00_BIAS;  
1474    
1475            if (MotionFlags & (XVID_ME_EXTSEARCH8|XVID_ME_HALFPELREFINE8|XVID_ME_QUARTERPELREFINE8)) {
1476                    if (Data->rrv) i = 2; else i = 1;
1477    
1478  /* Step 6: If MinSAD <= thresa goto Step 10.                  Data->Ref = OldData->Ref + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));
1479     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.                  Data->RefH = OldData->RefH + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));
1480  */                  Data->RefV = OldData->RefV + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));
1481                    Data->RefHV = OldData->RefHV + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));
1482    
1483          if ((iMinSAD <= threshA) ||                  Data->Cur = OldData->Cur + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));
1484                  (MVequal(*currMV, prevMB->mvs[0]) &&                  Data->qpel_precision = 0;
                  ((uint32_t) iMinSAD < prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
         }  
1485    
1486                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1487                                            pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
1488    
1489  /************ (Diamond Search)  **************/                  if (!Data->rrv) CheckCandidate = CheckCandidate8;
1490  /*                  else CheckCandidate = CheckCandidate16no4v;
    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.  
 */  
1491    
1492          if (MotionFlags & PMV_USESQUARES16)                  if (MotionFlags & XVID_ME_EXTSEARCH8 && (!(MotionFlags & XVID_ME_EXTSEARCH_BITS))) {
1493                  MainSearchPtr = Square16_MainSearch;                          int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
1494    
1495          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                          MainSearchFunc *MainSearchPtr;
1496                            if (MotionFlags & XVID_ME_USESQUARES8) MainSearchPtr = SquareSearch;
1497                                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1498                                            else MainSearchPtr = DiamondSearch;
1499    
1500  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, 255);
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  
                                                   currMV->y, iMinSAD, &newMV, pmv, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
1501    
1502          if (iSAD < iMinSAD) {                          if(*(Data->iMinSAD) < temp_sad) {
1503                  *currMV = newMV;                                          Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1504                  iMinSAD = iSAD;                                          Data->currentQMV->y = 2 * Data->currentMV->y;
1505                            }
1506          }          }
1507    
1508          if (MotionFlags & PMV_EXTSEARCH16) {                  if (MotionFlags & XVID_ME_HALFPELREFINE8) {
1509  /* extended: search (up to) two more times: orignal prediction and (0,0) */                          int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
1510    
1511                  if (!(MVequal(pmv[0], backupMV))) {                          SubpelRefine(Data); // perform halfpel refine of current best vector
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, pmv,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
1512    
1513                          if (iSAD < iMinSAD) {                          if(*(Data->iMinSAD) < temp_sad) { // we have found a better match
1514                                  *currMV = newMV;                                  Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1515                                  iMinSAD = iSAD;                                  Data->currentQMV->y = 2 * Data->currentMV->y;
1516                          }                          }
1517                  }                  }
1518    
1519                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                  if (Data->qpel && MotionFlags & XVID_ME_QUARTERPELREFINE8) {
1520                          iSAD =                                  Data->qpel_precision = 1;
1521                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1522                                                                    iMinSAD, &newMV, pmv, min_dx, max_dx, min_dy,                                          pParam->width, pParam->height, Data->iFcode, 1, 0);
1523                                                                    max_dy, iEdgedWidth, iDiamondSize, iFcode,                                  SubpelRefine(Data);
                                                                   iQuant, iFound);  
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
1524                          }                          }
1525                  }                  }
1526    
1527            if (Data->rrv) {
1528                            Data->currentMV->x = RRV_MV_SCALEDOWN(Data->currentMV->x);
1529                            Data->currentMV->y = RRV_MV_SCALEDOWN(Data->currentMV->y);
1530          }          }
1531    
1532  /*          if(Data->qpel) {
1533     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.                  pMB->pmvs[block].x = Data->currentQMV->x - Data->predMV.x;
1534  */                  pMB->pmvs[block].y = Data->currentQMV->y - Data->predMV.y;
1535                    pMB->qmvs[block] = *Data->currentQMV;
1536            } else {
1537                    pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1538                    pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
1539            }
1540    
1541    PMVfast16_Terminate_with_Refine:          pMB->mvs[block] = *Data->currentMV;
1542          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step          pMB->sad8[block] = 4 * *Data->iMinSAD;
1543                  iMinSAD =  }
1544                          Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
1545                                                           iMinSAD, pmv, min_dx, max_dx, min_dy, max_dy,  /* motion estimation for B-frames */
                                                          iFcode, iQuant, iEdgedWidth);  
1546    
1547    PMVfast16_Terminate_without_Refine:  static __inline VECTOR
1548          currPMV->x = currMV->x - pmv[0].x;  ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1549          currPMV->y = currMV->y - pmv[0].y;  {
1550          return iMinSAD;  /* the stupidiest function ever */
1551            return (mode == MODE_FORWARD ? pMB->mvs[0] : pMB->b_mvs[0]);
1552  }  }
1553    
1554    static void __inline
1555    PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
1556                                                            const uint32_t iWcount,
1557                                                            const MACROBLOCK * const pMB,
1558                                                            const uint32_t mode_curr)
1559    {
1560    
1561            // [0] is prediction
1562            pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
1563    
1564            pmv[1].x = pmv[1].y = 0; // [1] is zero
1565    
1566            pmv[2] = ChoosePred(pMB, mode_curr);
1567            pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
1568    
1569            if ((y != 0)&&(x != (int)(iWcount+1))) {                        // [3] top-right neighbour
1570                    pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
1571                    pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
1572            } else pmv[3].x = pmv[3].y = 0;
1573    
1574  int32_t          if (y != 0) {
1575  Diamond8_MainSearch(const uint8_t * const pRef,                  pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
1576                                          const uint8_t * const pRefH,                  pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
1577                                          const uint8_t * const pRefV,          } else pmv[4].x = pmv[4].y = 0;
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x,  
                                         const int y,  
                                         int32_t startx,  
                                         int32_t starty,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                         const VECTOR * const pmv,  
                                         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 iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = startx;  
         backupMV.y = starty;  
   
 /* 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!  
   
                         if (iDirection != 2)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                   backupMV.y, 1);  
                         if (iDirection != 1)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                   backupMV.y, 2);  
                         if (iDirection != 4)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y - iDiamondSize, 3);  
                         if (iDirection != 3)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y + iDiamondSize, 4);  
         } else {  
                 currMV->x = startx;  
                 currMV->y = starty;  
         }  
         return iMinSAD;  
 }  
1578    
1579  int32_t          if (x != 0) {
1580  Halfpel8_Refine(const uint8_t * const pRef,                  pmv[5] = ChoosePred(pMB-1, mode_curr);
1581                                  const uint8_t * const pRefH,                  pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1582                                  const uint8_t * const pRefV,          } else pmv[5].x = pmv[5].y = 0;
                                 const uint8_t * const pRefHV,  
                                 const uint8_t * const cur,  
                                 const int x,  
                                 const int y,  
                                 VECTOR * const currMV,  
                                 int32_t iMinSAD,  
                                 const VECTOR * const pmv,  
                                 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);  
1583    
1584          return iMinSAD;          if (x != 0 && y != 0) {
1585                    pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
1586                    pmv[6].x = EVEN(pmv[6].x); pmv[6].y = EVEN(pmv[6].y);
1587            } else pmv[6].x = pmv[6].y = 0;
1588  }  }
1589    
1590    
1591  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)  /* search backward or forward */
1592    static void
1593  int32_t  SearchBF(       const IMAGE * const pRef,
 PMVfastSearch8(const uint8_t * const pRef,  
1594                             const uint8_t * const pRefH,                             const uint8_t * const pRefH,
1595                             const uint8_t * const pRefV,                             const uint8_t * const pRefV,
1596                             const uint8_t * const pRefHV,                             const uint8_t * const pRefHV,
1597                             const IMAGE * const pCur,                             const IMAGE * const pCur,
1598                             const int x,                          const int x, const int y,
                            const int y,  
                            const int start_x,  
                            const int start_y,  
1599                             const uint32_t MotionFlags,                             const uint32_t MotionFlags,
                            const uint32_t iQuant,  
1600                             const uint32_t iFcode,                             const uint32_t iFcode,
1601                             const MBParam * const pParam,                             const MBParam * const pParam,
1602                             const MACROBLOCK * const pMBs,                          MACROBLOCK * const pMB,
1603                             const MACROBLOCK * const prevMBs,                          const VECTOR * const predMV,
1604                             VECTOR * const currMV,                          int32_t * const best_sad,
1605                             VECTOR * const currPMV)                          const int32_t mode_current,
1606                            SearchData * const Data)
1607  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
   
         const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;  
   
         int32_t iDiamondSize;  
1608    
1609          int32_t min_dx;          int i, iDirection = 255, mask;
1610          int32_t max_dx;          VECTOR pmv[7];
1611          int32_t min_dy;          MainSearchFunc *MainSearchPtr;
1612          int32_t max_dy;          *Data->iMinSAD = MV_MAX_ERROR;
1613            Data->iFcode = iFcode;
1614            Data->qpel_precision = 0;
1615            Data->temp[5] = Data->temp[6] = Data->temp[7] = 256*4096; // reset chroma-sad cache
1616    
1617          VECTOR pmv[4];          Data->Ref = pRef->y + (x + y * Data->iEdgedWidth) * 16;
1618          int32_t psad[4];          Data->RefH = pRefH + (x + y * Data->iEdgedWidth) * 16;
1619          VECTOR newMV;          Data->RefV = pRefV + (x + y * Data->iEdgedWidth) * 16;
1620          VECTOR backupMV;          Data->RefHV = pRefHV + (x + y * Data->iEdgedWidth) * 16;
1621          VECTOR startMV;          Data->RefCU = pRef->u + (x + y * Data->iEdgedWidth/2) * 8;
1622            Data->RefCV = pRef->v + (x + y * Data->iEdgedWidth/2) * 8;
1623    
1624  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          Data->predMV = *predMV;
         const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;  
1625    
1626          static int32_t threshA, threshB;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1627          int32_t iFound, bPredEq;                                  pParam->width, pParam->height, iFcode - Data->qpel, 0, 0);
         int32_t iMinSAD, iSAD;  
1628    
1629          int32_t iSubBlock = (y & 1) + (y & 1) + (x & 1);          pmv[0] = Data->predMV;
1630            if (Data->qpel) { pmv[0].x /= 2; pmv[0].y /= 2; }
1631    
1632          MainSearch8FuncPtr MainSearchPtr;          PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);
1633    
1634          /* Init variables */          Data->currentMV->x = Data->currentMV->y = 0;
1635          startMV.x = start_x;          CheckCandidate = CheckCandidate16no4v;
         startMV.y = start_y;  
1636    
1637          /* Get maximum range */  // main loop. checking all predictions
1638          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,          for (i = 0; i < 7; i++) {
1639                            iFcode);                  if (!(mask = make_mask(pmv, i)) ) continue;
1640                    CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
         if (!(MotionFlags & PMV_HALFPELDIAMOND8)) {  
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
1641          }          }
1642    
1643          /* because we might use IF (dx>max_dx) THEN dx=max_dx; */          if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1644          bPredEq =          else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1645                  get_pmvdata(pMBs, (x >> 1), (y >> 1), iWcount, iSubBlock, pmv, psad);                  else MainSearchPtr = DiamondSearch;
1646    
1647          if ((x == 0) && (y == 0)) {          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
                 threshA = 512 / 4;  
                 threshB = 1024 / 4;  
1648    
1649          } else {          SubpelRefine(Data);
                 threshA = psad[0] / 4;  /* good estimate */  
                 threshB = threshA + 256 / 4;  
                 if (threshA < 512 / 4)  
                         threshA = 512 / 4;  
                 if (threshA > 1024 / 4)  
                         threshA = 1024 / 4;  
                 if (threshB > 1792 / 4)  
                         threshB = 1792 / 4;  
         }  
   
         iFound = 0;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
1650    
1651            if (Data->qpel && *Data->iMinSAD < *best_sad + 300) {
1652                    Data->currentQMV->x = 2*Data->currentMV->x;
1653                    Data->currentQMV->y = 2*Data->currentMV->y;
1654                    Data->qpel_precision = 1;
1655                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1656                                            pParam->width, pParam->height, iFcode, 1, 0);
1657                    SubpelRefine(Data);
1658            }
1659    
1660  // Prepare for main loop  // three bits are needed to code backward mode. four for forward
1661    
1662  //  if (MotionFlags & PMV_USESQUARES8)          if (mode_current == MODE_FORWARD) *Data->iMinSAD += 4 * Data->lambda16;
1663  //      MainSearchPtr = Square8_MainSearch;          else *Data->iMinSAD += 3 * Data->lambda16;
 //  else  
1664    
1665          if (MotionFlags & PMV_ADVANCEDDIAMOND8)          if (*Data->iMinSAD < *best_sad) {
1666                  MainSearchPtr = AdvDiamond8_MainSearch;                  *best_sad = *Data->iMinSAD;
1667                    pMB->mode = mode_current;
1668                    if (Data->qpel) {
1669                            pMB->pmvs[0].x = Data->currentQMV->x - predMV->x;
1670                            pMB->pmvs[0].y = Data->currentQMV->y - predMV->y;
1671                            if (mode_current == MODE_FORWARD)
1672                                    pMB->qmvs[0] = *Data->currentQMV;
1673          else          else
1674                  MainSearchPtr = Diamond8_MainSearch;                                  pMB->b_qmvs[0] = *Data->currentQMV;
1675                    } else {
1676                            pMB->pmvs[0].x = Data->currentMV->x - predMV->x;
1677                            pMB->pmvs[0].y = Data->currentMV->y - predMV->y;
1678                    }
1679                    if (mode_current == MODE_FORWARD) pMB->mvs[0] = *Data->currentMV;
1680                    else pMB->b_mvs[0] = *Data->currentMV;
1681            }
1682    
1683            if (mode_current == MODE_FORWARD) *(Data->currentMV+2) = *Data->currentMV;
1684            else *(Data->currentMV+1) = *Data->currentMV; //we store currmv for interpolate search
1685    }
1686    
1687          *currMV = startMV;  static void
1688    SkipDecisionB(const IMAGE * const pCur,
1689                                    const IMAGE * const f_Ref,
1690                                    const IMAGE * const b_Ref,
1691                                    MACROBLOCK * const pMB,
1692                                    const uint32_t x, const uint32_t y,
1693                                    const SearchData * const Data)
1694    {
1695            int dx = 0, dy = 0, b_dx = 0, b_dy = 0;
1696            int32_t sum;
1697            const int div = 1 + Data->qpel;
1698            int k;
1699            const uint32_t stride = Data->iEdgedWidth/2;
1700    //this is not full chroma compensation, only it's fullpel approximation. should work though
1701    
1702          iMinSAD =          for (k = 0; k < 4; k++) {
1703                  sad8(cur,                  dy += Data->directmvF[k].y / div;
1704                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,                  dx += Data->directmvF[0].x / div;
1705                                                  iEdgedWidth), iEdgedWidth);                  b_dy += Data->directmvB[0].y / div;
1706          iMinSAD +=                  b_dx += Data->directmvB[0].x / div;
1707                  calc_delta_8(currMV->x - pmv[0].x, currMV->y - pmv[0].y,          }
                                          (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256 / 4) || ((MVequal(*currMV, prevMB->mvs[iSubBlock]))  
                                                                 && ((uint32_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  
 */  
1708    
1709          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[iSubBlock])))          dy = (dy >> 3) + roundtab_76[dy & 0xf];
1710                  iFound = 2;          dx = (dx >> 3) + roundtab_76[dx & 0xf];
1711            b_dy = (b_dy >> 3) + roundtab_76[b_dy & 0xf];
1712            b_dx = (b_dx >> 3) + roundtab_76[b_dx & 0xf];
1713    
1714  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          sum = sad8bi(pCur->u + 8 * x + 8 * y * stride,
1715     Otherwise select large Diamond Search.                                          f_Ref->u + (y*8 + dy/2) * stride + x*8 + dx/2,
1716  */                                          b_Ref->u + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1717                                            stride);
1718    
1719          if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))          if (sum >= 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) return; //no skip
                 iDiamondSize = 1;               // 1 halfpel!  
         else  
                 iDiamondSize = 2;               // 2 halfpel = 1 full pixel!  
1720    
1721          if (!(MotionFlags & PMV_HALFPELDIAMOND8))          sum += sad8bi(pCur->v + 8*x + 8 * y * stride,
1722                  iDiamondSize *= 2;                                          f_Ref->v + (y*8 + dy/2) * stride + x*8 + dx/2,
1723                                            b_Ref->v + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1724                                            stride);
1725    
1726            if (sum < 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) pMB->mode = MODE_DIRECT_NONE_MV; //skipped
1727    }
1728    
1729  /*  static __inline uint32_t
1730     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  SearchDirect(const IMAGE * const f_Ref,
1731     Also calculate (0,0) but do not subtract offset.                                  const uint8_t * const f_RefH,
1732     Let MinSAD be the smallest SAD up to this point.                                  const uint8_t * const f_RefV,
1733     If MV is (0,0) subtract offset.                                  const uint8_t * const f_RefHV,
1734  */                                  const IMAGE * const b_Ref,
1735                                    const uint8_t * const b_RefH,
1736                                    const uint8_t * const b_RefV,
1737                                    const uint8_t * const b_RefHV,
1738                                    const IMAGE * const pCur,
1739                                    const int x, const int y,
1740                                    const uint32_t MotionFlags,
1741                                    const int32_t TRB, const int32_t TRD,
1742                                    const MBParam * const pParam,
1743                                    MACROBLOCK * const pMB,
1744                                    const MACROBLOCK * const b_mb,
1745                                    int32_t * const best_sad,
1746                                    SearchData * const Data)
1747    
1748    {
1749            int32_t skip_sad;
1750            int k = (x + Data->iEdgedWidth*y) * 16;
1751            MainSearchFunc *MainSearchPtr;
1752    
1753            *Data->iMinSAD = 256*4096;
1754            Data->Ref = f_Ref->y + k;
1755            Data->RefH = f_RefH + k;
1756            Data->RefV = f_RefV + k;
1757            Data->RefHV = f_RefHV + k;
1758            Data->bRef = b_Ref->y + k;
1759            Data->bRefH = b_RefH + k;
1760            Data->bRefV = b_RefV + k;
1761            Data->bRefHV = b_RefHV + k;
1762            Data->RefCU = f_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1763            Data->RefCV = f_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1764            Data->b_RefCU = b_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1765            Data->b_RefCV = b_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1766    
1767            k = Data->qpel ? 4 : 2;
1768            Data->max_dx = k * (pParam->width - x * 16);
1769            Data->max_dy = k * (pParam->height - y * 16);
1770            Data->min_dx = -k * (16 + x * 16);
1771            Data->min_dy = -k * (16 + y * 16);
1772    
1773            Data->referencemv = Data->qpel ? b_mb->qmvs : b_mb->mvs;
1774            Data->qpel_precision = 0;
1775    
1776            for (k = 0; k < 4; k++) {
1777                    pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);
1778                    pMB->b_mvs[k].x = Data->directmvB[k].x = ((TRB - TRD) * Data->referencemv[k].x) / TRD;
1779                    pMB->mvs[k].y = Data->directmvF[k].y = ((TRB * Data->referencemv[k].y) / TRD);
1780                    pMB->b_mvs[k].y = Data->directmvB[k].y = ((TRB - TRD) * Data->referencemv[k].y) / TRD;
1781    
1782                    if ( (pMB->b_mvs[k].x > Data->max_dx) | (pMB->b_mvs[k].x < Data->min_dx)
1783                            | (pMB->b_mvs[k].y > Data->max_dy) | (pMB->b_mvs[k].y < Data->min_dy) ) {
1784    
1785                            *best_sad = 256*4096; // in that case, we won't use direct mode
1786                            pMB->mode = MODE_DIRECT; // just to make sure it doesn't say "MODE_DIRECT_NONE_MV"
1787                            pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;
1788                            return 256*4096;
1789                    }
1790                    if (b_mb->mode != MODE_INTER4V) {
1791                            pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mvs[0];
1792                            pMB->b_mvs[1] = pMB->b_mvs[2] = pMB->b_mvs[3] = pMB->b_mvs[0];
1793                            Data->directmvF[1] = Data->directmvF[2] = Data->directmvF[3] = Data->directmvF[0];
1794                            Data->directmvB[1] = Data->directmvB[2] = Data->directmvB[3] = Data->directmvB[0];
1795                            break;
1796                    }
1797            }
1798    
1799            CheckCandidate = b_mb->mode == MODE_INTER4V ? CheckCandidateDirect : CheckCandidateDirectno4v;
1800    
1801            CheckCandidate(0, 0, 255, &k, Data);
1802    
1803    // initial (fast) skip decision
1804            if (*Data->iMinSAD < pMB->quant * INITIAL_SKIP_THRESH * (2 + Data->chroma?1:0)) {
1805                    //possible skip
1806                    if (Data->chroma) {
1807                            pMB->mode = MODE_DIRECT_NONE_MV;
1808                            return *Data->iMinSAD; // skip.
1809                    } else {
1810                            SkipDecisionB(pCur, f_Ref, b_Ref, pMB, x, y, Data);
1811                            if (pMB->mode == MODE_DIRECT_NONE_MV) return *Data->iMinSAD; // skip.
1812                    }
1813            }
1814    
1815  // the median prediction might be even better than mv16          skip_sad = *Data->iMinSAD;
1816    
1817          if (!MVequal(pmv[0], startMV))  //      DIRECT MODE DELTA VECTOR SEARCH.
1818                  CHECK_MV8_CANDIDATE(pmv[0].x, pmv[0].y);  //      This has to be made more effective, but at the moment I'm happy it's running at all
1819    
1820  // (0,0) if needed          if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1821          if (!MVzero(pmv[0]))                  else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1822                  if (!MVzero(startMV))                          else MainSearchPtr = DiamondSearch;
                         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]) &&  
                  ((uint32_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;  
1823    
1824            MainSearchPtr(0, 0, Data, 255);
1825    
1826  /* Step 6: If MinSAD <= thresa goto Step 10.          SubpelRefine(Data);
    If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
 */  
1827    
1828          if ((iMinSAD <= threshA) ||          *best_sad = *Data->iMinSAD;
                 (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&  
                  ((uint32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 /************ (Diamond Search)  **************/  
 /*  
    Step 7: Perform Diamond search, with either the small or large diamond.  
    If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
    Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
    If center then goto step 10.  
    Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
    Refine by using small diamond and goto step 10.  
 */  
1829    
1830          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          if (Data->qpel || b_mb->mode == MODE_INTER4V) pMB->mode = MODE_DIRECT;
1831            else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation
1832    
1833  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          pMB->pmvs[3] = *Data->currentMV;
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  
                                                   currMV->y, iMinSAD, &newMV, pmv, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
1834    
1835          if (iSAD < iMinSAD) {          for (k = 0; k < 4; k++) {
1836                  *currMV = newMV;                  pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
1837                  iMinSAD = iSAD;                  pMB->b_mvs[k].x = (     (Data->currentMV->x == 0)
1838                                                            ? Data->directmvB[k].x
1839                                                            :pMB->mvs[k].x - Data->referencemv[k].x);
1840                    pMB->mvs[k].y = (Data->directmvF[k].y + Data->currentMV->y);
1841                    pMB->b_mvs[k].y = ((Data->currentMV->y == 0)
1842                                                            ? Data->directmvB[k].y
1843                                                            : pMB->mvs[k].y - Data->referencemv[k].y);
1844                    if (Data->qpel) {
1845                            pMB->qmvs[k].x = pMB->mvs[k].x; pMB->mvs[k].x /= 2;
1846                            pMB->b_qmvs[k].x = pMB->b_mvs[k].x; pMB->b_mvs[k].x /= 2;
1847                            pMB->qmvs[k].y = pMB->mvs[k].y; pMB->mvs[k].y /= 2;
1848                            pMB->b_qmvs[k].y = pMB->b_mvs[k].y; pMB->b_mvs[k].y /= 2;
1849          }          }
1850    
1851          if (MotionFlags & PMV_EXTSEARCH8) {                  if (b_mb->mode != MODE_INTER4V) {
1852  /* extended: search (up to) two more times: orignal prediction and (0,0) */                          pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1853                            pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1854                  if (!(MVequal(pmv[0], backupMV))) {                          pMB->qmvs[3] = pMB->qmvs[2] = pMB->qmvs[1] = pMB->qmvs[0];
1855                          iSAD =                          pMB->b_qmvs[3] = pMB->b_qmvs[2] = pMB->b_qmvs[1] = pMB->b_qmvs[0];
1856                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                          break;
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, pmv,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
1857                          }                          }
1858                  }                  }
1859            return skip_sad;
1860    }
1861    
1862    static void
1863    SearchInterpolate(const IMAGE * const f_Ref,
1864                                    const uint8_t * const f_RefH,
1865                                    const uint8_t * const f_RefV,
1866                                    const uint8_t * const f_RefHV,
1867                                    const IMAGE * const b_Ref,
1868                                    const uint8_t * const b_RefH,
1869                                    const uint8_t * const b_RefV,
1870                                    const uint8_t * const b_RefHV,
1871                                    const IMAGE * const pCur,
1872                                    const int x, const int y,
1873                                    const uint32_t fcode,
1874                                    const uint32_t bcode,
1875                                    const uint32_t MotionFlags,
1876                                    const MBParam * const pParam,
1877                                    const VECTOR * const f_predMV,
1878                                    const VECTOR * const b_predMV,
1879                                    MACROBLOCK * const pMB,
1880                                    int32_t * const best_sad,
1881                                    SearchData * const fData)
1882    
1883    {
1884    
1885                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          int iDirection, i, j;
1886                          iSAD =          SearchData bData;
1887                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
1888                                                                    iMinSAD, &newMV, pmv, min_dx, max_dx, min_dy,          fData->qpel_precision = 0;
1889                                                                    max_dy, iEdgedWidth, iDiamondSize, iFcode,          memcpy(&bData, fData, sizeof(SearchData)); //quick copy of common data
1890                                                                    iQuant, iFound);          *fData->iMinSAD = 4096*256;
1891            bData.currentMV++; bData.currentQMV++;
1892            fData->iFcode = bData.bFcode = fcode; fData->bFcode = bData.iFcode = bcode;
1893    
1894            i = (x + y * fData->iEdgedWidth) * 16;
1895            bData.bRef = fData->Ref = f_Ref->y + i;
1896            bData.bRefH = fData->RefH = f_RefH + i;
1897            bData.bRefV = fData->RefV = f_RefV + i;
1898            bData.bRefHV = fData->RefHV = f_RefHV + i;
1899            bData.Ref = fData->bRef = b_Ref->y + i;
1900            bData.RefH = fData->bRefH = b_RefH + i;
1901            bData.RefV = fData->bRefV = b_RefV + i;
1902            bData.RefHV = fData->bRefHV = b_RefHV + i;
1903            bData.b_RefCU = fData->RefCU = f_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
1904            bData.b_RefCV = fData->RefCV = f_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
1905            bData.RefCU = fData->b_RefCU = b_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
1906            bData.RefCV = fData->b_RefCV = b_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
1907    
1908    
1909            bData.bpredMV = fData->predMV = *f_predMV;
1910            fData->bpredMV = bData.predMV = *b_predMV;
1911            fData->currentMV[0] = fData->currentMV[2];
1912    
1913            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);
1914            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);
1915    
1916            if (fData->currentMV[0].x > fData->max_dx) fData->currentMV[0].x = fData->max_dx;
1917            if (fData->currentMV[0].x < fData->min_dx) fData->currentMV[0].x = fData->min_dx;
1918            if (fData->currentMV[0].y > fData->max_dy) fData->currentMV[0].y = fData->max_dy;
1919            if (fData->currentMV[0].y < fData->min_dy) fData->currentMV[0].y = fData->min_dy;
1920    
1921            if (fData->currentMV[1].x > bData.max_dx) fData->currentMV[1].x = bData.max_dx;
1922            if (fData->currentMV[1].x < bData.min_dx) fData->currentMV[1].x = bData.min_dx;
1923            if (fData->currentMV[1].y > bData.max_dy) fData->currentMV[1].y = bData.max_dy;
1924            if (fData->currentMV[1].y < bData.min_dy) fData->currentMV[1].y = bData.min_dy;
1925    
1926                          if (iSAD < iMinSAD) {          CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, 255, &iDirection, fData);
1927                                  *currMV = newMV;  
1928                                  iMinSAD = iSAD;  //diamond
1929            do {
1930                    iDirection = 255;
1931                    // forward MV moves
1932                    i = fData->currentMV[0].x; j = fData->currentMV[0].y;
1933    
1934                    CheckCandidateInt(i + 1, j, 0, &iDirection, fData);
1935                    CheckCandidateInt(i, j + 1, 0, &iDirection, fData);
1936                    CheckCandidateInt(i - 1, j, 0, &iDirection, fData);
1937                    CheckCandidateInt(i, j - 1, 0, &iDirection, fData);
1938    
1939                    // backward MV moves
1940                    i = fData->currentMV[1].x; j = fData->currentMV[1].y;
1941                    fData->currentMV[2] = fData->currentMV[0];
1942                    CheckCandidateInt(i + 1, j, 0, &iDirection, &bData);
1943                    CheckCandidateInt(i, j + 1, 0, &iDirection, &bData);
1944                    CheckCandidateInt(i - 1, j, 0, &iDirection, &bData);
1945                    CheckCandidateInt(i, j - 1, 0, &iDirection, &bData);
1946    
1947            } while (!(iDirection));
1948    
1949    //qpel refinement
1950            if (fData->qpel) {
1951                    if (*fData->iMinSAD > *best_sad + 500) return;
1952                    CheckCandidate = CheckCandidateInt;
1953                    fData->qpel_precision = bData.qpel_precision = 1;
1954                    get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode, 1, 0);
1955                    get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode, 1, 0);
1956                    fData->currentQMV[2].x = fData->currentQMV[0].x = 2 * fData->currentMV[0].x;
1957                    fData->currentQMV[2].y = fData->currentQMV[0].y = 2 * fData->currentMV[0].y;
1958                    fData->currentQMV[1].x = 2 * fData->currentMV[1].x;
1959                    fData->currentQMV[1].y = 2 * fData->currentMV[1].y;
1960                    SubpelRefine(fData);
1961                    if (*fData->iMinSAD > *best_sad + 300) return;
1962                    fData->currentQMV[2] = fData->currentQMV[0];
1963                    SubpelRefine(&bData);
1964            }
1965    
1966            *fData->iMinSAD += (2+3) * fData->lambda16; // two bits are needed to code interpolate mode.
1967    
1968            if (*fData->iMinSAD < *best_sad) {
1969                    *best_sad = *fData->iMinSAD;
1970                    pMB->mvs[0] = fData->currentMV[0];
1971                    pMB->b_mvs[0] = fData->currentMV[1];
1972                    pMB->mode = MODE_INTERPOLATE;
1973                    if (fData->qpel) {
1974                            pMB->qmvs[0] = fData->currentQMV[0];
1975                            pMB->b_qmvs[0] = fData->currentQMV[1];
1976                            pMB->pmvs[1].x = pMB->qmvs[0].x - f_predMV->x;
1977                            pMB->pmvs[1].y = pMB->qmvs[0].y - f_predMV->y;
1978                            pMB->pmvs[0].x = pMB->b_qmvs[0].x - b_predMV->x;
1979                            pMB->pmvs[0].y = pMB->b_qmvs[0].y - b_predMV->y;
1980                    } else {
1981                            pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;
1982                            pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;
1983                            pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;
1984                            pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;
1985                          }                          }
1986                  }                  }
1987          }          }
1988    
1989  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.  void
1990     By performing an optional local half-pixel search, we can refine this result even further.  MotionEstimationBVOP(MBParam * const pParam,
1991  */                                           FRAMEINFO * const frame,
1992                                             const int32_t time_bp,
1993                                             const int32_t time_pp,
1994                                             // forward (past) reference
1995                                             const MACROBLOCK * const f_mbs,
1996                                             const IMAGE * const f_ref,
1997                                             const IMAGE * const f_refH,
1998                                             const IMAGE * const f_refV,
1999                                             const IMAGE * const f_refHV,
2000                                             // backward (future) reference
2001                                             const FRAMEINFO * const b_reference,
2002                                             const IMAGE * const b_ref,
2003                                             const IMAGE * const b_refH,
2004                                             const IMAGE * const b_refV,
2005                                             const IMAGE * const b_refHV)
2006    {
2007            uint32_t i, j;
2008            int32_t best_sad;
2009            uint32_t skip_sad;
2010            int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;
2011            const MACROBLOCK * const b_mbs = b_reference->mbs;
2012    
2013            VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
2014    
2015            const int32_t TRB = time_pp - time_bp;
2016            const int32_t TRD = time_pp;
2017    
2018    // some pre-inintialized data for the rest of the search
2019    
2020            SearchData Data;
2021            int32_t iMinSAD;
2022            VECTOR currentMV[3];
2023            VECTOR currentQMV[3];
2024            int32_t temp[8];
2025            memset(&Data, 0, sizeof(SearchData));
2026            Data.iEdgedWidth = pParam->edged_width;
2027            Data.currentMV = currentMV; Data.currentQMV = currentQMV;
2028            Data.iMinSAD = &iMinSAD;
2029            Data.lambda16 = lambda_vec16[frame->quant];
2030            Data.qpel = pParam->vol_flags & XVID_VOL_QUARTERPEL;
2031            Data.rounding = 0;
2032            Data.chroma = frame->motion_flags & XVID_ME_CHROMA8;
2033            Data.temp = temp;
2034    
2035            Data.RefQ = f_refV->u; // a good place, also used in MC (for similar purpose)
2036            // note: i==horizontal, j==vertical
2037            for (j = 0; j < pParam->mb_height; j++) {
2038    
2039                    f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
2040    
2041    PMVfast8_Terminate_with_Refine:                  for (i = 0; i < pParam->mb_width; i++) {
2042          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step                          MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
2043                  iMinSAD =                          const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
2044                          Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
2045                                                          iMinSAD, pmv, min_dx, max_dx, min_dy, max_dy,  /* special case, if collocated block is SKIPed in P-VOP: encoding is forward (0,0), cpb=0 without further ado */
2046                                                          iFcode, iQuant, iEdgedWidth);                          if (b_reference->coding_type != S_VOP)
2047                                    if (b_mb->mode == MODE_NOT_CODED) {
2048                                            pMB->mode = MODE_NOT_CODED;
2049                                            continue;
2050                                    }
2051    
2052                            Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
2053                            Data.CurU = frame->image.u + (j * Data.iEdgedWidth/2 + i) * 8;
2054                            Data.CurV = frame->image.v + (j * Data.iEdgedWidth/2 + i) * 8;
2055    
2056    /* direct search comes first, because it (1) checks for SKIP-mode
2057            and (2) sets very good predictions for forward and backward search */
2058                            skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2059                                                                            b_ref, b_refH->y, b_refV->y, b_refHV->y,
2060                                                                            &frame->image,
2061                                                                            i, j,
2062                                                                            frame->motion_flags,
2063                                                                            TRB, TRD,
2064                                                                            pParam,
2065                                                                            pMB, b_mb,
2066                                                                            &best_sad,
2067                                                                            &Data);
2068    
2069    PMVfast8_Terminate_without_Refine:                          if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
2070          currPMV->x = currMV->x - pmv[0].x;  
2071          currPMV->y = currMV->y - pmv[0].y;                          // forward search
2072                            SearchBF(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2073                                                    &frame->image, i, j,
2074                                                    frame->motion_flags,
2075                                                    frame->fcode, pParam,
2076                                                    pMB, &f_predMV, &best_sad,
2077                                                    MODE_FORWARD, &Data);
2078    
2079          return iMinSAD;                          // backward search
2080                            SearchBF(b_ref, b_refH->y, b_refV->y, b_refHV->y,
2081                                                    &frame->image, i, j,
2082                                                    frame->motion_flags,
2083                                                    frame->bcode, pParam,
2084                                                    pMB, &b_predMV, &best_sad,
2085                                                    MODE_BACKWARD, &Data);
2086    
2087                            // interpolate search comes last, because it uses data from forward and backward as prediction
2088                            SearchInterpolate(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2089                                                    b_ref, b_refH->y, b_refV->y, b_refHV->y,
2090                                                    &frame->image,
2091                                                    i, j,
2092                                                    frame->fcode, frame->bcode,
2093                                                    frame->motion_flags,
2094                                                    pParam,
2095                                                    &f_predMV, &b_predMV,
2096                                                    pMB, &best_sad,
2097                                                    &Data);
2098    
2099    // final skip decision
2100                            if ( (skip_sad < frame->quant * MAX_SAD00_FOR_SKIP * 2)
2101                                            && ((100*best_sad)/(skip_sad+1) > FINAL_SKIP_THRESH) )
2102                                    SkipDecisionB(&frame->image, f_ref, b_ref, pMB, i, j, &Data);
2103    
2104                            switch (pMB->mode) {
2105                                    case MODE_FORWARD:
2106                                            f_count++;
2107                                            f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2108                                            break;
2109                                    case MODE_BACKWARD:
2110                                            b_count++;
2111                                            b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2112                                            break;
2113                                    case MODE_INTERPOLATE:
2114                                            i_count++;
2115                                            f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2116                                            b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2117                                            break;
2118                                    case MODE_DIRECT:
2119                                    case MODE_DIRECT_NO4V:
2120                                            d_count++;
2121                                    default:
2122                                            break;
2123                            }
2124                    }
2125            }
2126  }  }
2127    
2128  int32_t  static __inline void
2129  EPZSSearch16(const uint8_t * const pRef,  MEanalyzeMB (   const uint8_t * const pRef,
2130                           const uint8_t * const pRefH,                                  const uint8_t * const pCur,
                          const uint8_t * const pRefV,