[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

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