[svn] / branches / dev-api-3 / xvidcore / src / motion / motion_est.c Repository:
ViewVC logotype

Diff of /branches/dev-api-3/xvidcore/src/motion/motion_est.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.232  
changed lines
  Added in v.661

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