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

Legend:
Removed from v.252  
changed lines
  Added in v.702

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