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

Legend:
Removed from v.248  
changed lines
  Added in v.665

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