[svn] / trunk / xvidcore / src / motion / motion_est.c Repository:
ViewVC logotype

Diff of /trunk/xvidcore/src/motion/motion_est.c

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

revision 3, Fri Mar 8 02:46:11 2002 UTC revision 181, Wed May 22 12:42:25 2002 UTC
# Line 2  Line 2 
2   *   *
3   *  Modifications:   *  Modifications:
4   *   *
5     *      01.05.2002      updated MotionEstimationBVOP
6     *      25.04.2002 partial prevMB conversion
7     *  22.04.2002 remove some compile warning by chenm001 <chenm001@163.com>
8     *  14.04.2002 added MotionEstimationBVOP()
9     *  02.04.2002 add EPZS(^2) as ME algorithm, use PMV_USESQUARES to choose between
10     *             EPZS and EPZS^2
11   *  08.02.2002 split up PMVfast into three routines: PMVFast, PMVFast_MainLoop   *  08.02.2002 split up PMVfast into three routines: PMVFast, PMVFast_MainLoop
12   *             PMVFast_Refine to support multiple searches with different start points   *             PMVFast_Refine to support multiple searches with different start points
13   *      07.01.2002 uv-block-based interpolation   *      07.01.2002 uv-block-based interpolation
# Line 31  Line 37 
37    
38  #include <assert.h>  #include <assert.h>
39  #include <stdio.h>  #include <stdio.h>
40    #include <stdlib.h>
41    
42  #include "../encoder.h"  #include "../encoder.h"
43  #include "../utils/mbfunctions.h"  #include "../utils/mbfunctions.h"
44  #include "../prediction/mbprediction.h"  #include "../prediction/mbprediction.h"
45  #include "../global.h"  #include "../global.h"
46  #include "../utils/timer.h"  #include "../utils/timer.h"
47    #include "motion.h"
48  #include "sad.h"  #include "sad.h"
49    
50  // very large value  // very large value
# Line 46  Line 54 
54  #define MV16_THRESHOLD  192  #define MV16_THRESHOLD  192
55  #define MV8_THRESHOLD   56  #define MV8_THRESHOLD   56
56    
57    #define NEIGH_MOVE_THRESH 0
58    // how much a block's MV must differ from his neighbour
59    // to be search for INTER4V. The more, the faster...
60    
61  /* sad16(0,0) bias; mpeg4 spec suggests nb/2+1 */  /* sad16(0,0) bias; mpeg4 spec suggests nb/2+1 */
62  /* nb  = vop pixels * 2^(bpp-8) */  /* nb  = vop pixels * 2^(bpp-8) */
63  #define MV16_00_BIAS    (128+1)  #define MV16_00_BIAS    (128+1)
64    #define MV8_00_BIAS     (0)
65    
66  /* INTER bias for INTER/INTRA decision; mpeg4 spec suggests 2*nb */  /* INTER bias for INTER/INTRA decision; mpeg4 spec suggests 2*nb */
67  #define INTER_BIAS      512  #define MV16_INTER_BIAS 512
68    
69  /* Parameters which control inter/inter4v decision */  /* Parameters which control inter/inter4v decision */
70  #define IMV16X16                        5  #define IMV16X16                        5
# Line 60  Line 73 
73  #define NEIGH_TEND_16X16        2  #define NEIGH_TEND_16X16        2
74  #define NEIGH_TEND_8X8          2  #define NEIGH_TEND_8X8          2
75    
   
76  // fast ((A)/2)*2  // fast ((A)/2)*2
77  #define EVEN(A)         (((A)<0?(A)+1:(A)) & ~1)  #define EVEN(A)         (((A)<0?(A)+1:(A)) & ~1)
78    
79    #define MVzero(A) ( ((A).x)==(0) && ((A).y)==(0) )
80    #define MVequal(A,B) ( ((A).x)==((B).x) && ((A).y)==((B).y) )
81    
82    int32_t PMVfastSearch16(
83                                            const uint8_t * const pRef,
84                                            const uint8_t * const pRefH,
85                                            const uint8_t * const pRefV,
86                                            const uint8_t * const pRefHV,
87                                            const IMAGE * const pCur,
88                                            const int x, const int y,
89                                            const uint32_t MotionFlags,
90                                            const uint32_t iQuant,
91                                            const uint32_t iFcode,
92                                            const MBParam * const pParam,
93                                            const MACROBLOCK * const pMBs,
94                                            const MACROBLOCK * const prevMBs,
95                                            VECTOR * const currMV,
96                                            VECTOR * const currPMV);
97    
98  #define MIN(X, Y) ((X)<(Y)?(X):(Y))  int32_t EPZSSearch16(
99  #define MAX(X, Y) ((X)>(Y)?(X):(Y))                                          const uint8_t * const pRef,
100  #define ABS(X) (((X)>0)?(X):-(X))                                          const uint8_t * const pRefH,
101  #define SIGN(X) (((X)>0)?1:-1)                                          const uint8_t * const pRefV,
102                                            const uint8_t * const pRefHV,
103                                            const IMAGE * const pCur,
104                                            const int x, const int y,
105                                            const uint32_t MotionFlags,
106                                            const uint32_t iQuant,
107                                            const uint32_t iFcode,
108                                            const MBParam * const pParam,
109                                            const MACROBLOCK * const pMBs,
110                                            const MACROBLOCK * const prevMBs,
111                                            VECTOR * const currMV,
112                                            VECTOR * const currPMV);
113    
114    
115  int32_t PMVfastSearch8(  int32_t PMVfastSearch8(
# Line 78  Line 119 
119                                          const uint8_t * const pRefHV,                                          const uint8_t * const pRefHV,
120                                          const IMAGE * const pCur,                                          const IMAGE * const pCur,
121                                          const int x, const int y,                                          const int x, const int y,
122                                          const int start_x, int start_y,                                          const int start_x, const int start_y,
123                                          const uint32_t iQuality,                                          const uint32_t MotionFlags,
124                                          MBParam * const pParam,                                          const uint32_t iQuant,
125                                          MACROBLOCK * const pMBs,                                          const uint32_t iFcode,
126                                            const MBParam * const pParam,
127                                            const MACROBLOCK * const pMBs,
128                                            const MACROBLOCK * const prevMBs,
129                                          VECTOR * const currMV,                                          VECTOR * const currMV,
130                                          VECTOR * const currPMV);                                          VECTOR * const currPMV);
131    
132  int32_t PMVfastSearch16(  int32_t EPZSSearch8(
133                                          const uint8_t * const pRef,                                          const uint8_t * const pRef,
134                                          const uint8_t * const pRefH,                                          const uint8_t * const pRefH,
135                                          const uint8_t * const pRefV,                                          const uint8_t * const pRefV,
136                                          const uint8_t * const pRefHV,                                          const uint8_t * const pRefHV,
137                                          const IMAGE * const pCur,                                          const IMAGE * const pCur,
138                                          const int x, const int y,                                          const int x, const int y,
139                                          const uint32_t iQuality,                                          const int start_x, const int start_y,
140                                          MBParam * const pParam,                                          const uint32_t MotionFlags,
141                                          MACROBLOCK * const pMBs,                                          const uint32_t iQuant,
142                                            const uint32_t iFcode,
143                                            const MBParam * const pParam,
144                                            const MACROBLOCK * const pMBs,
145                                            const MACROBLOCK * const prevMBs,
146                                          VECTOR * const currMV,                                          VECTOR * const currMV,
147                                          VECTOR * const currPMV);                                          VECTOR * const currPMV);
148    
149    
150    typedef int32_t (MainSearch16Func)(
151            const uint8_t * const pRef,
152            const uint8_t * const pRefH,
153            const uint8_t * const pRefV,
154            const uint8_t * const pRefHV,
155            const uint8_t * const cur,
156            const int x, const int y,
157            int32_t startx, int32_t starty,
158            int32_t iMinSAD,
159            VECTOR * const currMV,
160            const VECTOR * const pmv,
161            const int32_t min_dx, const int32_t max_dx,
162            const int32_t min_dy, const int32_t max_dy,
163            const int32_t iEdgedWidth,
164            const int32_t iDiamondSize,
165            const int32_t iFcode,
166            const int32_t iQuant,
167            int iFound);
168    
169    typedef MainSearch16Func* MainSearch16FuncPtr;
170    
 /* diamond search stuff  
    keep the the sequence in circular order (so optimization works)  
 */  
171    
172  typedef struct  typedef int32_t (MainSearch8Func)(
173  {          const uint8_t * const pRef,
174          int32_t dx;          const uint8_t * const pRefH,
175          int32_t dy;          const uint8_t * const pRefV,
176  }          const uint8_t * const pRefHV,
177  DPOINT;          const uint8_t * const cur,
178            const int x, const int y,
179            int32_t startx, int32_t starty,
180            int32_t iMinSAD,
181            VECTOR * const currMV,
182            const VECTOR * const pmv,
183            const int32_t min_dx, const int32_t max_dx,
184            const int32_t min_dy, const int32_t max_dy,
185            const int32_t iEdgedWidth,
186            const int32_t iDiamondSize,
187            const int32_t iFcode,
188            const int32_t iQuant,
189            int iFound);
190    
191    typedef MainSearch8Func* MainSearch8FuncPtr;
192    
193  static const DPOINT diamond_small[4] =  static int32_t lambda_vec16[32] =  /* rounded values for lambda param for weight of motion bits as in modified H.26L */
194  {          {     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),
195          {0, 1}, {1, 0}, {0, -1}, {-1, 0}          (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),
196  };          (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),
197            (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),
198            (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),
199            (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),
200            (int)(36.4949+0.5)      };
201    
202    static int32_t *lambda_vec8 = lambda_vec16;     /* same table for INTER and INTER4V for now*/
203    
 static const DPOINT diamond_large[8] =  
 {  
         {0, 2}, {1, 1}, {2, 0}, {1, -1}, {0, -2}, {-1, -1}, {-2, 0}, {-1, 1}  
 };  
204    
205    
206  // mv.length table  // mv.length table
# Line 159  Line 238 
238  }  }
239    
240    
241  static __inline uint32_t calc_delta_16(const int32_t dx, const int32_t dy, const uint32_t iFcode)  static __inline uint32_t calc_delta_16(const int32_t dx, const int32_t dy, const uint32_t iFcode, const uint32_t iQuant)
 {  
         return NEIGH_TEND_16X16 * (mv_bits(dx, iFcode) + mv_bits(dy, iFcode));  
 }  
   
 static __inline uint32_t calc_delta_8(const int32_t dx, const int32_t dy, const uint32_t iFcode)  
   
242  {  {
243      return NEIGH_TEND_8X8 * (mv_bits(dx, iFcode) + mv_bits(dy, iFcode));          return NEIGH_TEND_16X16 * lambda_vec16[iQuant] * (mv_bits(dx, iFcode) + mv_bits(dy, iFcode));
244  }  }
245    
246    static __inline uint32_t calc_delta_8(const int32_t dx, const int32_t dy, const uint32_t iFcode, const uint32_t iQuant)
247    
   
   
 /* calculate the min/max range (in halfpixels)  
         relative to the _MACROBLOCK_ position  
 */  
   
 static void __inline get_range(  
                         int32_t * const min_dx, int32_t * const max_dx,  
                         int32_t * const min_dy, int32_t * const max_dy,  
                         const uint32_t x, const uint32_t y,  
                         const uint32_t block_sz,                                        // block dimension, 8 or 16  
                         const uint32_t width, const uint32_t height,  
                         const uint32_t fcode)  
248  {  {
249          const int search_range = 32 << (fcode - 1);      return NEIGH_TEND_8X8 * lambda_vec8[iQuant] * (mv_bits(dx, iFcode) + mv_bits(dy, iFcode));
     const int high = search_range - 1;  
     const int low = -search_range;  
   
         // convert full-pixel measurements to half pixel  
         const int hp_width = 2 * width;  
         const int hp_height = 2 * height;  
         const int hp_edge = 2 * block_sz;  
         const int hp_x = 2 * (x) * block_sz;            // we need _right end_ of block, not x-coordinate  
         const int hp_y = 2 * (y) * block_sz;            // same for _bottom end_  
   
     *max_dx = MIN(high, hp_width - hp_x);  
     *max_dy = MIN(high, hp_height - hp_y);  
     *min_dx = MAX(low,  -(hp_edge + hp_x));  
     *min_dy = MAX(low,  -(hp_edge + hp_y));  
250  }  }
251    
252    
 /* getref: calculate reference image pointer  
 the decision to use interpolation h/v/hv or the normal image is  
 based on dx & dy.  
 */  
   
 static __inline const uint8_t * get_ref(  
                                 const uint8_t * const refn,  
                                 const uint8_t * const refh,  
                                 const uint8_t * const refv,  
                                 const uint8_t * const refhv,  
                                 const uint32_t x, const uint32_t y,  
                                 const uint32_t block,                                   // block dimension, 8 or 16  
                                 const int32_t dx, const int32_t dy,  
                                 const uint32_t stride)  
 {  
         switch ( ((dx&1)<<1) + (dy&1) )         // ((dx%2)?2:0)+((dy%2)?1:0)  
     {  
         case 0 : return refn + (x*block+dx/2) + (y*block+dy/2)*stride;  
     case 1 : return refv + (x*block+dx/2) + (y*block+(dy-1)/2)*stride;  
         case 2 : return refh + (x*block+(dx-1)/2) + (y*block+dy/2)*stride;  
         default :  
         case 3 : return refhv + (x*block+(dx-1)/2) + (y*block+(dy-1)/2)*stride;  
         }  
 }  
   
253    
 /* This is somehow a copy of get_ref, but with MV instead of X,Y */  
254    
 static __inline const uint8_t * get_ref_mv(  
                                 const uint8_t * const refn,  
                                 const uint8_t * const refh,  
                                 const uint8_t * const refv,  
                                 const uint8_t * const refhv,  
                                 const uint32_t x, const uint32_t y,  
                                 const uint32_t block,                   // block dimension, 8 or 16  
                                 const VECTOR* mv,       // measured in half-pel!  
                                 const uint32_t stride)  
 {  
         switch ( (((mv->x)&1)<<1) + ((mv->y)&1) )  
     {  
         case 0 : return refn + (x*block+(mv->x)/2) + (y*block+(mv->y)/2)*stride;  
         case 1 : return refv + (x*block+(mv->x)/2) + (y*block+((mv->y)-1)/2)*stride;  
         case 2 : return refh + (x*block+((mv->x)-1)/2) + (y*block+(mv->y)/2)*stride;  
         default :  
         case 3 : return refhv + (x*block+((mv->x)-1)/2) + (y*block+((mv->y)-1)/2)*stride;  
         }  
 }  
255    
256  #ifndef SEARCH16  #ifndef SEARCH16
257  #define SEARCH16        PMVfastSearch16  #define SEARCH16        PMVfastSearch16
258    //#define SEARCH16      FullSearch16
259    //#define SEARCH16      EPZSSearch16
260  #endif  #endif
261    
262  #ifndef SEARCH8  #ifndef SEARCH8
263  #define SEARCH8         PMVfastSearch8  #define SEARCH8         PMVfastSearch8
264    //#define SEARCH8       EPZSSearch8
265  #endif  #endif
266    
267  bool MotionEstimation(  bool MotionEstimation(
                         MACROBLOCK * const pMBs,  
268                          MBParam * const pParam,                          MBParam * const pParam,
269                      const IMAGE * const pRef,          FRAMEINFO * const current,
270            FRAMEINFO * const reference,
271                          const IMAGE * const pRefH,                          const IMAGE * const pRefH,
272                      const IMAGE * const pRefV,                      const IMAGE * const pRefV,
273                          const IMAGE * const pRefHV,                          const IMAGE * const pRefHV,
                     IMAGE * const pCurrent,  
274                          const uint32_t iLimit)                          const uint32_t iLimit)
275    
276  {  {
277      const uint32_t iWcount = pParam->mb_width;      const uint32_t iWcount = pParam->mb_width;
278      const uint32_t iHcount = pParam->mb_height;      const uint32_t iHcount = pParam->mb_height;
279            MACROBLOCK * const pMBs = current->mbs;
280            MACROBLOCK * const prevMBs = reference->mbs;    // previous frame
281    
282          uint32_t i, j, iIntra = 0;          const IMAGE * const pCurrent = &current->image;
283            const IMAGE * const pRef = &reference->image;
284    
285      VECTOR mv16;          const VECTOR zeroMV = {0,0};
     VECTOR pmv16;  
286    
287      int32_t sad8 = 0;          int32_t x, y;
288      int32_t sad16;          int32_t iIntra = 0;
289      int32_t deviation;          VECTOR pmv;
290    
291          // note: i==horizontal, j==vertical          if (sadInit)
292      for (i = 0; i < iHcount; i++)                  (*sadInit)();
                 for (j = 0; j < iWcount; j++)  
                 {  
                         MACROBLOCK *pMB = &pMBs[j + i * iWcount];  
293    
294                          sad16 = SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,          for (y = 0; y < iHcount; y++)
295                                            j, i, pParam->motion_flags,                  for (x = 0; x < iWcount; x++)
296                                            pParam, pMBs, &mv16, &pmv16);                  {
297                          pMB->sad16=sad16;                          MACROBLOCK* const pMB = &pMBs[x + y * iWcount];
298    
299                            pMB->sad16 = SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,
300                                             x, y, current->motion_flags, current->quant, current->fcode,
301                                             pParam, pMBs, prevMBs, &pMB->mv16, &pMB->pmvs[0]);
302    
                 /* decide: MODE_INTER or MODE_INTRA  
                         if (dev_intra < sad_inter - 2 * nb) use_intra  
                 */  
303    
304                  deviation = dev16(pCurrent->y + j*16 + i*16*pParam->edged_width, pParam->edged_width);                          if (0 < (pMB->sad16 - MV16_INTER_BIAS))
305                            {
306                                    int32_t deviation;
307                                    deviation = dev16(pCurrent->y + x*16 + y*16*pParam->edged_width,
308                                                             pParam->edged_width);
309    
310                  if (deviation < (sad16 - INTER_BIAS))                                  if (deviation < (pMB->sad16 - MV16_INTER_BIAS))
311                  {                  {
312                          pMB->mode = MODE_INTRA;                          pMB->mode = MODE_INTRA;
313                          pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = 0;                                          pMB->mv16 = pMB->mvs[0] = pMB->mvs[1]
314                          pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = 0;                                                                   = pMB->mvs[2] = pMB->mvs[3] = zeroMV;
315                                            pMB->sad16 = pMB->sad8[0] = pMB->sad8[1]
316                                                                 = pMB->sad8[2] = pMB->sad8[3] = 0;
317    
318                          iIntra++;                          iIntra++;
319                          if(iIntra >= iLimit)                          if(iIntra >= iLimit)
# Line 312  Line 321 
321    
322                          continue;                          continue;
323                  }                  }
324                            }
325                            pMB->mode = MODE_INTER;
326                            pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mv16;
327               pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = pMB->sad16;
328                    }
329    
330            // we try to do as few INTER4V-searches as possible. So we split ME in two parts, normal
331            // SEARCH16 and only for special blocks SEARCH8. May this should be modified for quality
332            // levels.
333    
                 if (pParam->global_flags & XVID_INTER4V)  
                 {  
                         pMB->sad8[0] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,  
                                         2 * j, 2 * i, mv16.x, mv16.y, pParam->motion_flags,  
                                         pParam, pMBs, &pMB->mvs[0], &pMB->pmvs[0]);  
334    
                         pMB->sad8[1] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,  
                                         2 * j + 1, 2 * i, mv16.x, mv16.y, pParam->motion_flags,  
                                         pParam, pMBs, &pMB->mvs[1], &pMB->pmvs[1]);  
335    
336                          pMB->sad8[2] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,          if (current->global_flags & XVID_INTER4V)
337                                          2 * j, 2 * i + 1, mv16.x, mv16.y, pParam->motion_flags,                  for (y = 0; y < iHcount; y++)
338                                          pParam, pMBs, &pMB->mvs[2], &pMB->pmvs[2]);                          for (x = 0; x < iWcount; x++)
339                            {
340                                    MACROBLOCK* const pMB = &pMBs[x + y * iWcount];
341    
342                                    if (pMB->mode == MODE_INTRA)
343                                            continue;
344    
                         pMB->sad8[3] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,  
                                         2 * j + 1, 2 * i + 1, mv16.x, mv16.y, pParam->motion_flags,  
                                         pParam, pMBs, &pMB->mvs[3], &pMB->pmvs[3]);  
345    
346                          sad8 = pMB->sad8[0] + pMB->sad8[1] + pMB->sad8[2] + pMB->sad8[3];                                  if ( (!(current->global_flags & XVID_LUMIMASKING) || pMB->dquant == NO_CHANGE) )
347                  }                                  {
348                                    int32_t neigh=0;
349    
350                                    if (x>0)
351                                    {       neigh += abs((pMB->mv16.x)-((pMB-1)->mv16.x));
352                                            neigh += abs((pMB->mv16.y)-((pMB-1)->mv16.y));
353                                    }
354                                    if (y>0)
355                                    {       neigh += abs((pMB->mv16.x)-((pMB-iWcount)->mv16.x));
356                                            neigh += abs((pMB->mv16.y)-((pMB-iWcount)->mv16.y));
357                                    }
358                                    if (x<(iWcount-1))
359                                    {       neigh += abs((pMB->mv16.x)-((pMB+1)->mv16.x));
360                                            neigh += abs((pMB->mv16.y)-((pMB+1)->mv16.y));
361                                    }
362                                    if (y<(iHcount-1))
363                                    {       neigh += abs((pMB->mv16.x)-((pMB+iHcount)->mv16.x));
364                                            neigh += abs((pMB->mv16.y)-((pMB+iHcount)->mv16.y));
365                                    }
366    
367                                    if (neigh > NEIGH_MOVE_THRESH)
368                                    {
369                                            int32_t sad8 = IMV16X16 * current->quant;
370    
371                                            if (sad8 < pMB->sad16)
372                                            sad8 += pMB->sad8[0]
373                                                    = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,
374                                                                   2*x, 2*y, pMB->mv16.x, pMB->mv16.y,
375                                                                       current->motion_flags, current->quant, current->fcode,
376                                                                   pParam, pMBs, prevMBs, &pMB->mvs[0], &pMB->pmvs[0]);
377    
378                                            if (sad8 < pMB->sad16)
379                                            sad8 += pMB->sad8[1]
380                                                    = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,
381                                           2*x+1, 2*y, pMB->mv16.x, pMB->mv16.y,
382                                                            current->motion_flags, current->quant, current->fcode,
383                                                            pParam, pMBs, prevMBs, &pMB->mvs[1], &pMB->pmvs[1]);
384    
385                                            if (sad8 < pMB->sad16)
386                                            sad8 += pMB->sad8[2]
387                                                    = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,
388                                                            2*x, 2*y+1, pMB->mv16.x, pMB->mv16.y,
389                                                            current->motion_flags, current->quant, current->fcode,
390                                                            pParam, pMBs, prevMBs, &pMB->mvs[2], &pMB->pmvs[2]);
391    
392                                            if (sad8 < pMB->sad16)
393                                            sad8 += pMB->sad8[3]
394                                                    = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,
395                                                            2*x+1, 2*y+1, pMB->mv16.x, pMB->mv16.y,
396                                                            current->motion_flags, current->quant, current->fcode,
397                                                            pParam, pMBs, prevMBs, &pMB->mvs[3], &pMB->pmvs[3]);
398    
399                  /* decide: MODE_INTER or MODE_INTER4V                  /* decide: MODE_INTER or MODE_INTER4V
400                          mpeg4:   if (sad8 < sad16 - nb/2+1) use_inter4v                             mpeg4:   if (sad8 < pMB->sad16 - nb/2+1) use_inter4v
401                  */                  */
402    
403                  if (pMB->dquant == NO_CHANGE) {                                          if (sad8 < pMB->sad16)
                         if (((pParam->global_flags & XVID_INTER4V)==0) ||  
                                 (sad16 < (sad8 + (int32_t)(IMV16X16 * pParam->quant)))) {  
   
                                 sad8 = sad16;  
                                 pMB->mode = MODE_INTER;  
                                 pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = mv16.x;  
                                 pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = mv16.y;  
                                 pMB->pmvs[0].x = pmv16.x;  
                                 pMB->pmvs[0].y = pmv16.y;  
                         }  
                         else  
                                 pMB->mode = MODE_INTER4V;  
                 }  
                 else  
404                  {                  {
405                          sad8 = sad16;                                                  pMB->mode = MODE_INTER4V;
406                          pMB->mode = MODE_INTER;                        pMB->sad8[0] *= 4;
407                          pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = mv16.x;                                                  pMB->sad8[1] *= 4;
408                          pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = mv16.y;                                                  pMB->sad8[2] *= 4;
409                          pMB->pmvs[0].x = pmv16.x;                                                  pMB->sad8[3] *= 4;
410                          pMB->pmvs[0].y = pmv16.y;                                                  continue;
411                  }                  }
412    
413                                            pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mv16;
414          }          }
415    
         return 0;  
416  }  }
417    
418  #define MVzero(A) ( ((A).x)==(0) && ((A).y)==(0) )                  // get_pmv has to be called again, because inter4v changes predictors
419    
420  #define MVequal(A,B) ( ((A).x)==((B).x) && ((A).y)==((B).y) )                          pmv = get_pmv(pMBs, x, y, pParam->mb_width, 0);
421                            pMB->pmvs[0].x = pMB->mv16.x - pmv.x;   /* the other pmvs are only needed in INTER4V-mode */
422                            pMB->pmvs[0].y = pMB->mv16.y - pmv.y;
423    
424                            }
425    
426            return 0;
427    }
428    
429  #define CHECK_MV16_ZERO {\  #define CHECK_MV16_ZERO {\
430    if ( (0 <= max_dx) && (0 >= min_dx) \    if ( (0 <= max_dx) && (0 >= min_dx) \
431      && (0 <= max_dy) && (0 >= min_dy) ) \      && (0 <= max_dy) && (0 >= min_dy) ) \
432    { \    { \
433      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \
434      iSAD += calc_delta_16(-pmv[0].x, -pmv[0].y, (uint8_t)iFcode) * iQuant;\      iSAD += calc_delta_16(-pmv[0].x, -pmv[0].y, (uint8_t)iFcode, iQuant);\
     if (iSAD <= iQuant * 96)    \  
         iSAD -= MV16_00_BIAS; \  
435      if (iSAD < iMinSAD) \      if (iSAD < iMinSAD) \
436      {  iMinSAD=iSAD; currMV->x=0; currMV->y=0; }  }     \      {  iMinSAD=iSAD; currMV->x=0; currMV->y=0; }  }     \
437  }  }
438    
439    #define NOCHECK_MV16_CANDIDATE(X,Y) { \
440        iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \
441        iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode, iQuant);\
442        if (iSAD < iMinSAD) \
443        {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \
444    }
445    
446  #define CHECK_MV16_CANDIDATE(X,Y) { \  #define CHECK_MV16_CANDIDATE(X,Y) { \
447    if ( ((X) <= max_dx) && ((X) >= min_dx) \    if ( ((X) <= max_dx) && ((X) >= min_dx) \
448      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
449    { \    { \
450      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \
451      iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode) * iQuant;\      iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode, iQuant);\
452      if (iSAD < iMinSAD) \      if (iSAD < iMinSAD) \
453      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \
454  }  }
# Line 400  Line 458 
458      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
459    { \    { \
460      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \
461      iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode) * iQuant;\      iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode, iQuant);\
462      if (iSAD < iMinSAD) \      if (iSAD < iMinSAD) \
463      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \
464  }  }
# Line 410  Line 468 
468      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
469    { \    { \
470      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \
471      iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode) * iQuant;\      iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode, iQuant);\
472      if (iSAD < iMinSAD) \      if (iSAD < iMinSAD) \
473      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \
474  }  }
# Line 418  Line 476 
476    
477  #define CHECK_MV8_ZERO {\  #define CHECK_MV8_ZERO {\
478    iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, 0, 0 , iEdgedWidth), iEdgedWidth); \    iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, 0, 0 , iEdgedWidth), iEdgedWidth); \
479    iSAD += calc_delta_8(-pmv[0].x, -pmv[0].y, (uint8_t)iFcode) * iQuant;\    iSAD += calc_delta_8(-pmv[0].x, -pmv[0].y, (uint8_t)iFcode, iQuant);\
480    if (iSAD < iMinSAD) \    if (iSAD < iMinSAD) \
481    { iMinSAD=iSAD; currMV->x=0; currMV->y=0; } \    { iMinSAD=iSAD; currMV->x=0; currMV->y=0; } \
482  }  }
483    
484    #define NOCHECK_MV8_CANDIDATE(X,Y) \
485      { \
486        iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \
487        iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode, iQuant);\
488        if (iSAD < iMinSAD) \
489        {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \
490    }
491    
492  #define CHECK_MV8_CANDIDATE(X,Y) { \  #define CHECK_MV8_CANDIDATE(X,Y) { \
493    if ( ((X) <= max_dx) && ((X) >= min_dx) \    if ( ((X) <= max_dx) && ((X) >= min_dx) \
494      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
495    { \    { \
496      iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \      iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \
497      iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode) * iQuant;\      iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode, iQuant);\
498      if (iSAD < iMinSAD) \      if (iSAD < iMinSAD) \
499      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \
500  }  }
# Line 439  Line 504 
504      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
505    { \    { \
506      iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \      iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \
507      iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode) * iQuant;\      iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode, iQuant);\
508      if (iSAD < iMinSAD) \      if (iSAD < iMinSAD) \
509      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \
510  }  }
# Line 449  Line 514 
514      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
515    { \    { \
516      iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \      iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \
517      iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode) * iQuant;\      iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode, iQuant);\
518      if (iSAD < iMinSAD) \      if (iSAD < iMinSAD) \
519      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \
520  }  }
# Line 464  Line 529 
529                                          const IMAGE * const pCur,                                          const IMAGE * const pCur,
530                                          const int x, const int y,                                          const int x, const int y,
531                                          const uint32_t MotionFlags,                                          const uint32_t MotionFlags,
532                                            const uint32_t iQuant,
533                                            const uint32_t iFcode,
534                                          MBParam * const pParam,                                          MBParam * const pParam,
535                                          MACROBLOCK * const pMBs,                                          const MACROBLOCK * const pMBs,
536                                            const MACROBLOCK * const prevMBs,
537                                          VECTOR * const currMV,                                          VECTOR * const currMV,
538                                          VECTOR * const currPMV)                                          VECTOR * const currPMV)
539  {  {
540          const int32_t iEdgedWidth = pParam->edged_width;          const int32_t iEdgedWidth = pParam->edged_width;
         const int32_t iQuant = pParam->quant;  
541          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;
542          int32_t iSAD;          int32_t iSAD;
543          int32_t pred_x,pred_y;          int32_t pred_x,pred_y;
# Line 493  Line 560 
560  }  }
561  */  */
562    
563  int32_t PMVfastSearch16_MainSearch(  int32_t Diamond16_MainSearch(
564                                          const uint8_t * const pRef,                                          const uint8_t * const pRef,
565                                          const uint8_t * const pRefH,                                          const uint8_t * const pRefH,
566                                          const uint8_t * const pRefV,                                          const uint8_t * const pRefV,
# Line 550  Line 617 
617          return iMinSAD;          return iMinSAD;
618  }  }
619    
620  int32_t PMVfastSearch16_Refine(  int32_t Square16_MainSearch(
621                                          const uint8_t * const pRef,                                          const uint8_t * const pRef,
622                                          const uint8_t * const pRefH,                                          const uint8_t * const pRefH,
623                                          const uint8_t * const pRefV,                                          const uint8_t * const pRefV,
624                                          const uint8_t * const pRefHV,                                          const uint8_t * const pRefHV,
625                                          const uint8_t * const cur,                                          const uint8_t * const cur,
626                                          const int x, const int y,                                          const int x, const int y,
627                                          VECTOR * const currMV,                                          int32_t startx, int32_t starty,
628                                          int32_t iMinSAD,                                          int32_t iMinSAD,
629                                            VECTOR * const currMV,
630                                          const VECTOR * const pmv,                                          const VECTOR * const pmv,
631                                          const int32_t min_dx, const int32_t max_dx,                                          const int32_t min_dx, const int32_t max_dx,
632                                          const int32_t min_dy, const int32_t max_dy,                                          const int32_t min_dy, const int32_t max_dy,
633                                            const int32_t iEdgedWidth,
634                                            const int32_t iDiamondSize,
635                                          const int32_t iFcode,                                          const int32_t iFcode,
636                                          const int32_t iQuant,                                          const int32_t iQuant,
637                                          const int32_t iEdgedWidth)                                          int iFound)
638  {  {
639  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  /* Do a square search around given starting point, return SAD of best */
640    
641            int32_t iDirection=0;
642          int32_t iSAD;          int32_t iSAD;
643          VECTOR backupMV = *currMV;          VECTOR backupMV;
644            backupMV.x = startx;
645          CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y-1);          backupMV.y = starty;
         CHECK_MV16_CANDIDATE(backupMV.x  ,backupMV.y-1);  
         CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y-1);  
         CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y+1);  
         CHECK_MV16_CANDIDATE(backupMV.x  ,backupMV.y+1);  
         CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y+1);  
   
         return iMinSAD;  
 }  
   
 #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)  
646    
647  int32_t PMVfastSearch16(  /* It's one search with full square pattern, and new parts for all following diamonds */
                                         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,  
                                         MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
 {  
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iFcode = pParam->fixed_code;  
         const int32_t iQuant = pParam->quant;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
648    
649          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;  /*   new direction are extra, so 1-4 is normal diamond
650          537
651          1*2
652          648
653    */
654    
655          int32_t iDiamondSize;          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y,1);
656            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);
657            CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);
658            CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);
659    
660          int32_t min_dx;          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);
661          int32_t max_dx;          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);
662          int32_t min_dy;          CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);
663          int32_t max_dy;          CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);
664    
         int32_t iFound;  
665    
666          VECTOR newMV;          if (iDirection)
667          VECTOR backupMV;        /* just for PMVFAST */                  while (!iFound)
668                    {
669                            iFound = 1;
670                            backupMV=*currMV;
671    
672          VECTOR pmv[4];                          switch (iDirection)
673          int32_t psad[4];                          {
674                                    case 1:
675                                            CHECK_MV16_CANDIDATE_FOUND(backupMV.x-iDiamondSize,backupMV.y,1);
676                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);
677                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);
678                                            break;
679                                    case 2:
680                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);
681                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);
682                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);
683                                            break;
684    
685          MACROBLOCK * const pMB = pMBs + x + y * iWcount;                                  case 3:
686                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);
687                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);
688                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);
689                                            break;
690    
691          static int32_t threshA,threshB;                                  case 4:
692          int32_t bPredEq;                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);
693          int32_t iMinSAD,iSAD;                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);
694                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);
695                                            break;
696    
697  /* Get maximum range */                                  case 5:
698          get_range(&min_dx, &max_dx, &min_dy, &max_dy,                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y,1);
699                          x, y, 16, iWidth, iHeight, iFcode);                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);
700                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);
701                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);
702                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);
703                                            break;
704    
705  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */                                  case 6:
706                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);
707                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);
708    
709          if (!(MotionFlags & PMV_HALFPEL16 ))                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);
710          { min_dx = EVEN(min_dx);                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);
711            max_dx = EVEN(max_dx);                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);
           min_dy = EVEN(min_dy);  
           max_dy = EVEN(max_dy);  
         }               /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
712    
713                                            break;
714    
715          bPredEq  = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);                                  case 7:
716                                            CHECK_MV16_CANDIDATE_FOUND(backupMV.x-iDiamondSize,backupMV.y,1);
717                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);
718                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);
719                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);
720                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);
721                                            break;
722    
723          if ((x==0) && (y==0) )                                  case 8:
724          {                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);
725                  threshA =  512;                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);
726                  threshB = 1024;                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);
727                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);
728                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);
729                                            break;
730                            default:
731                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y,1);
732                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);
733                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);
734                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);
735    
736                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);
737                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);
738                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);
739                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);
740                                            break;
741                            }
742          }          }
743          else          else
744          {          {
745                  threshA = psad[0];                          currMV->x = startx;
746                  threshB = threshA+256;                          currMV->y = starty;
747                  if (threshA< 512) threshA =  512;                  }
748                  if (threshA>1024) threshA = 1024;          return iMinSAD;
                 if (threshB>1792) threshB = 1792;  
749          }          }
750    
         iFound=0;  
   
 /* Step 2: 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],pMB->mvs[0]) ) )  
                 iFound=2;  
   
 /* Step 3: If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.  
         Otherwise select large Diamond Search.  
 */  
751    
752          if ( (pmv[0].x != 0) || (pmv[0].y != 0) || (threshB<1536) || (bPredEq) )  int32_t Full16_MainSearch(
753                  iDiamondSize=1; // halfpel!                                          const uint8_t * const pRef,
754          else                                          const uint8_t * const pRefH,
755                                            const uint8_t * const pRefV,
756                                            const uint8_t * const pRefHV,
757                                            const uint8_t * const cur,
758                                            const int x, const int y,
759                                            int32_t startx, int32_t starty,
760                                            int32_t iMinSAD,
761                                            VECTOR * const currMV,
762                                            const VECTOR * const pmv,
763                                            const int32_t min_dx, const int32_t max_dx,
764                                            const int32_t min_dy, const int32_t max_dy,
765                                            const int32_t iEdgedWidth,
766                                            const int32_t iDiamondSize,
767                                            const int32_t iFcode,
768                                            const int32_t iQuant,
769                                            int iFound)
770    {
771            int32_t iSAD;
772            int32_t dx,dy;
773            VECTOR backupMV;
774            backupMV.x = startx;
775            backupMV.y = starty;
776    
777            for (dx = min_dx; dx<=max_dx; dx+=iDiamondSize)
778                    for (dy = min_dy; dy<= max_dy; dy+=iDiamondSize)
779                            NOCHECK_MV16_CANDIDATE(dx,dy);
780    
781            return iMinSAD;
782    }
783    
784    int32_t AdvDiamond16_MainSearch(
785            const uint8_t * const pRef,
786            const uint8_t * const pRefH,
787            const uint8_t * const pRefV,
788            const uint8_t * const pRefHV,
789            const uint8_t * const cur,
790            const int x, const int y,
791            int32_t startx, int32_t starty,
792            int32_t iMinSAD,
793            VECTOR * const currMV,
794            const VECTOR * const pmv,
795            const int32_t min_dx, const int32_t max_dx,
796            const int32_t min_dy, const int32_t max_dy,
797            const int32_t iEdgedWidth,
798            const int32_t iDiamondSize,
799            const int32_t iFcode,
800            const int32_t iQuant,
801            int iDirection)
802    {
803    
804            int32_t iSAD;
805    
806    /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
807    
808            if (iDirection)
809            {
810                    CHECK_MV16_CANDIDATE(startx-iDiamondSize, starty);
811                    CHECK_MV16_CANDIDATE(startx+iDiamondSize, starty);
812                    CHECK_MV16_CANDIDATE(startx, starty-iDiamondSize);
813                    CHECK_MV16_CANDIDATE(startx, starty+iDiamondSize);
814            }
815            else
816            {
817                    int bDirection = 1+2+4+8;
818                    do
819                    {
820                            iDirection = 0;
821                            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)
822                                    CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize,starty,1);
823    
824                            if (bDirection&2)
825                                    CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize,starty,2);
826    
827                            if (bDirection&4)
828                                    CHECK_MV16_CANDIDATE_DIR(startx,starty-iDiamondSize,4);
829    
830                            if (bDirection&8)
831                                    CHECK_MV16_CANDIDATE_DIR(startx,starty+iDiamondSize,8);
832    
833                            /* now we're doing diagonal checks near our candidate */
834    
835                            if (iDirection) //checking if anything found
836                            {
837                                    bDirection = iDirection;
838                                    iDirection = 0;
839                                    startx=currMV->x; starty=currMV->y;
840                                    if (bDirection & 3) //our candidate is left or right
841                                    {
842                                            CHECK_MV16_CANDIDATE_DIR(startx,starty+iDiamondSize, 8);
843                                            CHECK_MV16_CANDIDATE_DIR(startx,starty-iDiamondSize, 4);
844                                    }
845                                    else // what remains here is up or down
846                                    {
847                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty, 2);
848                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty, 1);
849                                    }
850    
851                                    if (iDirection)
852                                    {       bDirection+=iDirection;
853                                            startx=currMV->x; starty=currMV->y;
854                                    }
855                            }
856                            else //about to quit, eh? not so fast....
857                            {
858                                    switch (bDirection)
859                                    {
860                                    case 2:
861                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
862                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
863                                            break;
864                                    case 1:
865                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
866                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
867                                            break;
868                                    case 2+4:
869                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
870                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
871                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
872                                            break;
873                                    case 4:
874                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
875                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
876                                            break;
877                                    case 8:
878                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
879                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
880                                            break;
881                                    case 1+4:
882                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
883                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
884                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
885                                            break;
886                                    case 2+8:
887                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
888                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
889                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
890                                            break;
891                                    case 1+8:
892                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
893                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
894                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
895                                            break;
896                                    default: //1+2+4+8 == we didn't find anything at all
897                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
898                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
899                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
900                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
901                                            break;
902                                    }
903                                    if (!iDirection) break; //ok, the end. really
904                                    else
905                                    {       bDirection=iDirection;
906                                            startx=currMV->x; starty=currMV->y;
907                                    }
908                            }
909                    }
910                    while (1); //forever
911            }
912            return iMinSAD;
913    }
914    
915    int32_t AdvDiamond8_MainSearch(
916            const uint8_t * const pRef,
917            const uint8_t * const pRefH,
918            const uint8_t * const pRefV,
919            const uint8_t * const pRefHV,
920            const uint8_t * const cur,
921            const int x, const int y,
922            int32_t startx, int32_t starty,
923            int32_t iMinSAD,
924            VECTOR * const currMV,
925            const VECTOR * const pmv,
926            const int32_t min_dx, const int32_t max_dx,
927            const int32_t min_dy, const int32_t max_dy,
928            const int32_t iEdgedWidth,
929            const int32_t iDiamondSize,
930            const int32_t iFcode,
931            const int32_t iQuant,
932            int iDirection)
933    {
934    
935            int32_t iSAD;
936    
937    /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
938    
939            if (iDirection)
940            {
941                    CHECK_MV8_CANDIDATE(startx-iDiamondSize, starty);
942                    CHECK_MV8_CANDIDATE(startx+iDiamondSize, starty);
943                    CHECK_MV8_CANDIDATE(startx, starty-iDiamondSize);
944                    CHECK_MV8_CANDIDATE(startx, starty+iDiamondSize);
945            }
946            else
947            {
948                    int bDirection = 1+2+4+8;
949                    do
950                    {
951                            iDirection = 0;
952                            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)
953                                    CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize,starty,1);
954    
955                            if (bDirection&2)
956                                    CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize,starty,2);
957    
958                            if (bDirection&4)
959                                    CHECK_MV8_CANDIDATE_DIR(startx,starty-iDiamondSize,4);
960    
961                            if (bDirection&8)
962                                    CHECK_MV8_CANDIDATE_DIR(startx,starty+iDiamondSize,8);
963    
964                            /* now we're doing diagonal checks near our candidate */
965    
966                            if (iDirection) //checking if anything found
967                            {
968                                    bDirection = iDirection;
969                                    iDirection = 0;
970                                    startx=currMV->x; starty=currMV->y;
971                                    if (bDirection & 3) //our candidate is left or right
972                                    {
973                                            CHECK_MV8_CANDIDATE_DIR(startx,starty+iDiamondSize, 8);
974                                            CHECK_MV8_CANDIDATE_DIR(startx,starty-iDiamondSize, 4);
975                                    }
976                                    else // what remains here is up or down
977                                    {
978                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty, 2);
979                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty, 1);
980                                    }
981    
982                                    if (iDirection)
983                                    {       bDirection+=iDirection;
984                                            startx=currMV->x; starty=currMV->y;
985                                    }
986                            }
987                            else //about to quit, eh? not so fast....
988                            {
989                                    switch (bDirection)
990                                    {
991                                    case 2:
992                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
993                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
994                                            break;
995                                    case 1:
996                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
997                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
998                                            break;
999                                    case 2+4:
1000                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
1001                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
1002                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
1003                                            break;
1004                                    case 4:
1005                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
1006                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
1007                                            break;
1008                                    case 8:
1009                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
1010                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
1011                                            break;
1012                                    case 1+4:
1013                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
1014                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
1015                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
1016                                            break;
1017                                    case 2+8:
1018                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
1019                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
1020                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
1021                                            break;
1022                                    case 1+8:
1023                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
1024                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
1025                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
1026                                            break;
1027                                    default: //1+2+4+8 == we didn't find anything at all
1028                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
1029                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
1030                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
1031                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
1032                                            break;
1033                                    }
1034                                    if (!(iDirection)) break; //ok, the end. really
1035                                    else
1036                                    {       bDirection=iDirection;
1037                                            startx=currMV->x; starty=currMV->y;
1038                                    }
1039                            }
1040                    }
1041                    while (1); //forever
1042            }
1043            return iMinSAD;
1044    }
1045    
1046    
1047    int32_t Full8_MainSearch(
1048                                            const uint8_t * const pRef,
1049                                            const uint8_t * const pRefH,
1050                                            const uint8_t * const pRefV,
1051                                            const uint8_t * const pRefHV,
1052                                            const uint8_t * const cur,
1053                                            const int x, const int y,
1054                                            int32_t startx, int32_t starty,
1055                                            int32_t iMinSAD,
1056                                            VECTOR * const currMV,
1057                                            const VECTOR * const pmv,
1058                                            const int32_t min_dx, const int32_t max_dx,
1059                                            const int32_t min_dy, const int32_t max_dy,
1060                                            const int32_t iEdgedWidth,
1061                                            const int32_t iDiamondSize,
1062                                            const int32_t iFcode,
1063                                            const int32_t iQuant,
1064                                            int iFound)
1065    {
1066            int32_t iSAD;
1067            int32_t dx,dy;
1068            VECTOR backupMV;
1069            backupMV.x = startx;
1070            backupMV.y = starty;
1071    
1072            for (dx = min_dx; dx<=max_dx; dx+=iDiamondSize)
1073                    for (dy = min_dy; dy<= max_dy; dy+=iDiamondSize)
1074                            NOCHECK_MV8_CANDIDATE(dx,dy);
1075    
1076            return iMinSAD;
1077    }
1078    
1079    
1080    
1081    int32_t Halfpel16_Refine(
1082            const uint8_t * const pRef,
1083            const uint8_t * const pRefH,
1084            const uint8_t * const pRefV,
1085            const uint8_t * const pRefHV,
1086            const uint8_t * const cur,
1087            const int x, const int y,
1088            VECTOR * const currMV,
1089            int32_t iMinSAD,
1090            const VECTOR * const pmv,
1091            const int32_t min_dx, const int32_t max_dx,
1092            const int32_t min_dy, const int32_t max_dy,
1093            const int32_t iFcode,
1094            const int32_t iQuant,
1095            const int32_t iEdgedWidth)
1096    {
1097    /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */
1098    
1099            int32_t iSAD;
1100            VECTOR backupMV = *currMV;
1101    
1102            CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y-1);
1103            CHECK_MV16_CANDIDATE(backupMV.x  ,backupMV.y-1);
1104            CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y-1);
1105            CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y);
1106            CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y);
1107            CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y+1);
1108            CHECK_MV16_CANDIDATE(backupMV.x  ,backupMV.y+1);
1109            CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y+1);
1110    
1111            return iMinSAD;
1112    }
1113    
1114    #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)
1115    
1116    
1117    int32_t PMVfastSearch16(
1118                                            const uint8_t * const pRef,
1119                                            const uint8_t * const pRefH,
1120                                            const uint8_t * const pRefV,
1121                                            const uint8_t * const pRefHV,
1122                                            const IMAGE * const pCur,
1123                                            const int x, const int y,
1124                                            const uint32_t MotionFlags,
1125                                            const uint32_t iQuant,
1126                                            const uint32_t iFcode,
1127                                            const MBParam * const pParam,
1128                                            const MACROBLOCK * const pMBs,
1129                                            const MACROBLOCK * const prevMBs,
1130                                            VECTOR * const currMV,
1131                                            VECTOR * const currPMV)
1132    {
1133        const uint32_t iWcount = pParam->mb_width;
1134            const int32_t iWidth = pParam->width;
1135            const int32_t iHeight = pParam->height;
1136            const int32_t iEdgedWidth = pParam->edged_width;
1137    
1138            const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;
1139    
1140            int32_t iDiamondSize;
1141    
1142            int32_t min_dx;
1143            int32_t max_dx;
1144            int32_t min_dy;
1145            int32_t max_dy;
1146    
1147            int32_t iFound;
1148    
1149            VECTOR newMV;
1150            VECTOR backupMV;        /* just for PMVFAST */
1151    
1152            VECTOR pmv[4];
1153            int32_t psad[4];
1154    
1155            MainSearch16FuncPtr MainSearchPtr;
1156    
1157    //      const MACROBLOCK * const pMB = pMBs + x + y * iWcount;
1158            const MACROBLOCK * const prevMB = prevMBs + x + y * iWcount;
1159    
1160            static int32_t threshA,threshB;
1161            int32_t bPredEq;
1162            int32_t iMinSAD,iSAD;
1163    
1164    /* Get maximum range */
1165            get_range(&min_dx, &max_dx, &min_dy, &max_dy,
1166                      x, y, 16, iWidth, iHeight, iFcode);
1167    
1168    /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */
1169    
1170            if (!(MotionFlags & PMV_HALFPEL16 ))
1171            { min_dx = EVEN(min_dx);
1172            max_dx = EVEN(max_dx);
1173            min_dy = EVEN(min_dy);
1174            max_dy = EVEN(max_dy);
1175            }               /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */
1176    
1177    
1178            bPredEq  = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);
1179    
1180            if ((x==0) && (y==0) )
1181            {
1182                    threshA =  512;
1183                    threshB = 1024;
1184    
1185            }
1186            else
1187            {
1188                    threshA = psad[0];
1189                    threshB = threshA+256;
1190                    if (threshA< 512) threshA =  512;
1191                    if (threshA>1024) threshA = 1024;
1192                    if (threshB>1792) threshB = 1792;
1193            }
1194    
1195            iFound=0;
1196    
1197    /* Step 4: Calculate SAD around the Median prediction.
1198       MinSAD=SAD
1199       If Motion Vector equal to Previous frame motion vector
1200       and MinSAD<PrevFrmSAD goto Step 10.
1201       If SAD<=256 goto Step 10.
1202    */
1203    
1204            *currMV=pmv[0];         /* current best := prediction */
1205            if (!(MotionFlags & PMV_HALFPEL16 ))
1206            {       /* This should NOT be necessary! */
1207                    currMV->x = EVEN(currMV->x);
1208                    currMV->y = EVEN(currMV->y);
1209            }
1210    
1211            if (currMV->x > max_dx)
1212            {
1213                    currMV->x=max_dx;
1214            }
1215            if (currMV->x < min_dx)
1216            {
1217                    currMV->x=min_dx;
1218            }
1219            if (currMV->y > max_dy)
1220            {
1221                    currMV->y=max_dy;
1222            }
1223            if (currMV->y < min_dy)
1224            {
1225                    currMV->y=min_dy;
1226            }
1227    
1228            iMinSAD = sad16( cur,
1229                             get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV, iEdgedWidth),
1230                             iEdgedWidth, MV_MAX_ERROR);
1231            iMinSAD += calc_delta_16(currMV->x-pmv[0].x, currMV->y-pmv[0].y, (uint8_t)iFcode, iQuant);
1232    
1233            if ( (iMinSAD < 256 ) || ( (MVequal(*currMV,prevMB->mvs[0])) && ((uint32_t)iMinSAD < prevMB->sad16) ) )
1234            {
1235                    if (iMinSAD < 2*iQuant) // high chances for SKIP-mode
1236                    {
1237                            if (!MVzero(*currMV))
1238                            {
1239                                    iMinSAD += MV16_00_BIAS;
1240                                    CHECK_MV16_ZERO;                // (0,0) saves space for letterboxed pictures
1241                                    iMinSAD -= MV16_00_BIAS;
1242                            }
1243                    }
1244    
1245                    if (MotionFlags & PMV_QUICKSTOP16)
1246                            goto PMVfast16_Terminate_without_Refine;
1247                    if (MotionFlags & PMV_EARLYSTOP16)
1248                            goto PMVfast16_Terminate_with_Refine;
1249            }
1250    
1251    
1252    /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion
1253       vector of the median.
1254       If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2
1255    */
1256    
1257            if ((bPredEq) && (MVequal(pmv[0],prevMB->mvs[0]) ) )
1258                    iFound=2;
1259    
1260    /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.
1261       Otherwise select large Diamond Search.
1262    */
1263    
1264            if ( (!MVzero(pmv[0])) || (threshB<1536) || (bPredEq) )
1265                    iDiamondSize=1; // halfpel!
1266            else
1267                  iDiamondSize=2; // halfpel!                  iDiamondSize=2; // halfpel!
1268    
1269          if (!(MotionFlags & PMV_HALFPELDIAMOND16) )          if (!(MotionFlags & PMV_HALFPELDIAMOND16) )
1270                    iDiamondSize*=2;
1271    
1272    /*
1273       Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.
1274       Also calculate (0,0) but do not subtract offset.
1275       Let MinSAD be the smallest SAD up to this point.
1276       If MV is (0,0) subtract offset.
1277    */
1278    
1279    // (0,0) is always possible
1280    
1281            if (!MVzero(pmv[0]))
1282                    CHECK_MV16_ZERO;
1283    
1284    // previous frame MV is always possible
1285    
1286            if (!MVzero(prevMB->mvs[0]))
1287            if (!MVequal(prevMB->mvs[0],pmv[0]))
1288                    CHECK_MV16_CANDIDATE(prevMB->mvs[0].x,prevMB->mvs[0].y);
1289    
1290    // left neighbour, if allowed
1291    
1292            if (!MVzero(pmv[1]))
1293            if (!MVequal(pmv[1],prevMB->mvs[0]))
1294            if (!MVequal(pmv[1],pmv[0]))
1295            {
1296                    if (!(MotionFlags & PMV_HALFPEL16 ))
1297                    {       pmv[1].x = EVEN(pmv[1].x);
1298                            pmv[1].y = EVEN(pmv[1].y);
1299                    }
1300    
1301                    CHECK_MV16_CANDIDATE(pmv[1].x,pmv[1].y);
1302            }
1303    
1304    // top neighbour, if allowed
1305            if (!MVzero(pmv[2]))
1306            if (!MVequal(pmv[2],prevMB->mvs[0]))
1307            if (!MVequal(pmv[2],pmv[0]))
1308            if (!MVequal(pmv[2],pmv[1]))
1309            {
1310                    if (!(MotionFlags & PMV_HALFPEL16 ))
1311                    {       pmv[2].x = EVEN(pmv[2].x);
1312                            pmv[2].y = EVEN(pmv[2].y);
1313                    }
1314                    CHECK_MV16_CANDIDATE(pmv[2].x,pmv[2].y);
1315    
1316    // top right neighbour, if allowed
1317                    if (!MVzero(pmv[3]))
1318                    if (!MVequal(pmv[3],prevMB->mvs[0]))
1319                    if (!MVequal(pmv[3],pmv[0]))
1320                    if (!MVequal(pmv[3],pmv[1]))
1321                    if (!MVequal(pmv[3],pmv[2]))
1322                    {
1323                            if (!(MotionFlags & PMV_HALFPEL16 ))
1324                            {       pmv[3].x = EVEN(pmv[3].x);
1325                                    pmv[3].y = EVEN(pmv[3].y);
1326                            }
1327                            CHECK_MV16_CANDIDATE(pmv[3].x,pmv[3].y);
1328                    }
1329            }
1330    
1331            if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96)*/ )
1332                    iMinSAD -= MV16_00_BIAS;
1333    
1334    
1335    /* Step 6: If MinSAD <= thresa goto Step 10.
1336       If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.
1337    */
1338    
1339            if ( (iMinSAD <= threshA) || ( MVequal(*currMV,prevMB->mvs[0]) && ((uint32_t)iMinSAD < prevMB->sad16) ) )
1340            {
1341                    if (MotionFlags & PMV_QUICKSTOP16)
1342                            goto PMVfast16_Terminate_without_Refine;
1343                    if (MotionFlags & PMV_EARLYSTOP16)
1344                            goto PMVfast16_Terminate_with_Refine;
1345            }
1346    
1347    
1348    /************ (Diamond Search)  **************/
1349    /*
1350       Step 7: Perform Diamond search, with either the small or large diamond.
1351       If Found=2 only examine one Diamond pattern, and afterwards goto step 10
1352       Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.
1353       If center then goto step 10.
1354       Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.
1355       Refine by using small diamond and goto step 10.
1356    */
1357    
1358            if (MotionFlags & PMV_USESQUARES16)
1359                    MainSearchPtr = Square16_MainSearch;
1360            else
1361                    if (MotionFlags & PMV_ADVANCEDDIAMOND16)
1362                            MainSearchPtr = AdvDiamond16_MainSearch;
1363                    else
1364                            MainSearchPtr = Diamond16_MainSearch;
1365    
1366            backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */
1367    
1368    /* default: use best prediction as starting point for one call of PMVfast_MainSearch */
1369            iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
1370                                              x, y,
1371                                              currMV->x, currMV->y, iMinSAD, &newMV,
1372                                              pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);
1373    
1374            if (iSAD < iMinSAD)
1375            {
1376                    *currMV = newMV;
1377                    iMinSAD = iSAD;
1378            }
1379    
1380            if (MotionFlags & PMV_EXTSEARCH16)
1381            {
1382    /* extended: search (up to) two more times: orignal prediction and (0,0) */
1383    
1384                    if (!(MVequal(pmv[0],backupMV)) )
1385                    {       iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
1386                                                              x, y,
1387                                                              pmv[0].x, pmv[0].y, iMinSAD, &newMV,
1388                                                              pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);
1389    
1390                    if (iSAD < iMinSAD)
1391                    {
1392                            *currMV = newMV;
1393                            iMinSAD = iSAD;
1394                    }
1395                    }
1396    
1397                    if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )
1398                    {       iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
1399                                                              x, y,
1400                                                              0, 0, iMinSAD, &newMV,
1401                                                              pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);
1402    
1403                    if (iSAD < iMinSAD)
1404                    {
1405                            *currMV = newMV;
1406                            iMinSAD = iSAD;
1407                    }
1408                    }
1409            }
1410    
1411    /*
1412       Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.
1413    */
1414    
1415    PMVfast16_Terminate_with_Refine:
1416            if (MotionFlags & PMV_HALFPELREFINE16)          // perform final half-pel step
1417                    iMinSAD = Halfpel16_Refine( pRef, pRefH, pRefV, pRefHV, cur,
1418                                      x, y,
1419                                      currMV, iMinSAD,
1420                                      pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);
1421    
1422    PMVfast16_Terminate_without_Refine:
1423            currPMV->x = currMV->x - pmv[0].x;
1424            currPMV->y = currMV->y - pmv[0].y;
1425            return iMinSAD;
1426    }
1427    
1428    
1429    
1430    
1431    
1432    
1433    int32_t Diamond8_MainSearch(
1434            const uint8_t * const pRef,
1435            const uint8_t * const pRefH,
1436            const uint8_t * const pRefV,
1437            const uint8_t * const pRefHV,
1438            const uint8_t * const cur,
1439            const int x, const int y,
1440            int32_t startx, int32_t starty,
1441            int32_t iMinSAD,
1442            VECTOR * const currMV,
1443            const VECTOR * const pmv,
1444            const int32_t min_dx, const int32_t max_dx,
1445            const int32_t min_dy, const int32_t max_dy,
1446            const int32_t iEdgedWidth,
1447            const int32_t iDiamondSize,
1448            const int32_t iFcode,
1449            const int32_t iQuant,
1450            int iFound)
1451    {
1452    /* Do a diamond search around given starting point, return SAD of best */
1453    
1454            int32_t iDirection=0;
1455            int32_t iSAD;
1456            VECTOR backupMV;
1457            backupMV.x = startx;
1458            backupMV.y = starty;
1459    
1460    /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */
1461    
1462            CHECK_MV8_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y,1);
1463            CHECK_MV8_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);
1464            CHECK_MV8_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);
1465            CHECK_MV8_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);
1466    
1467            if (iDirection)
1468                    while (!iFound)
1469                    {
1470                            iFound = 1;
1471                            backupMV=*currMV;       // since iDirection!=0, this is well defined!
1472    
1473                            if ( iDirection != 2)
1474                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x-iDiamondSize,backupMV.y,1);
1475                            if ( iDirection != 1)
1476                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x+iDiamondSize,backupMV.y,2);
1477                            if ( iDirection != 4)
1478                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x,backupMV.y-iDiamondSize,3);
1479                            if ( iDirection != 3)
1480                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x,backupMV.y+iDiamondSize,4);
1481                    }
1482            else
1483            {
1484                    currMV->x = startx;
1485                    currMV->y = starty;
1486            }
1487            return iMinSAD;
1488    }
1489    
1490    int32_t Halfpel8_Refine(
1491            const uint8_t * const pRef,
1492            const uint8_t * const pRefH,
1493            const uint8_t * const pRefV,
1494            const uint8_t * const pRefHV,
1495            const uint8_t * const cur,
1496            const int x, const int y,
1497            VECTOR * const currMV,
1498            int32_t iMinSAD,
1499            const VECTOR * const pmv,
1500            const int32_t min_dx, const int32_t max_dx,
1501            const int32_t min_dy, const int32_t max_dy,
1502            const int32_t iFcode,
1503            const int32_t iQuant,
1504            const int32_t iEdgedWidth)
1505    {
1506    /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */
1507    
1508            int32_t iSAD;
1509            VECTOR backupMV = *currMV;
1510    
1511            CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y-1);
1512            CHECK_MV8_CANDIDATE(backupMV.x  ,backupMV.y-1);
1513            CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y-1);
1514            CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y);
1515            CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y);
1516            CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y+1);
1517            CHECK_MV8_CANDIDATE(backupMV.x  ,backupMV.y+1);
1518            CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y+1);
1519    
1520            return iMinSAD;
1521    }
1522    
1523    
1524    #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)
1525    
1526    int32_t PMVfastSearch8(
1527                                            const uint8_t * const pRef,
1528                                            const uint8_t * const pRefH,
1529                                            const uint8_t * const pRefV,
1530                                            const uint8_t * const pRefHV,
1531                                            const IMAGE * const pCur,
1532                                            const int x, const int y,
1533                                            const int start_x, const int start_y,
1534                                            const uint32_t MotionFlags,
1535                                            const uint32_t iQuant,
1536                                            const uint32_t iFcode,
1537                                            const MBParam * const pParam,
1538                                            const MACROBLOCK * const pMBs,
1539                                            const MACROBLOCK * const prevMBs,
1540                                            VECTOR * const currMV,
1541                                            VECTOR * const currPMV)
1542    {
1543        const uint32_t iWcount = pParam->mb_width;
1544            const int32_t iWidth = pParam->width;
1545            const int32_t iHeight = pParam->height;
1546            const int32_t iEdgedWidth = pParam->edged_width;
1547    
1548            const uint8_t * cur = pCur->y + x*8 + y*8*iEdgedWidth;
1549    
1550            int32_t iDiamondSize;
1551    
1552            int32_t min_dx;
1553            int32_t max_dx;
1554            int32_t min_dy;
1555            int32_t max_dy;
1556    
1557            VECTOR pmv[4];
1558            int32_t psad[4];
1559            VECTOR newMV;
1560            VECTOR backupMV;
1561            VECTOR startMV;
1562    
1563    //      const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;
1564            const MACROBLOCK * const prevMB = prevMBs + (x>>1) + (y>>1) * iWcount;
1565    
1566            static int32_t threshA,threshB;
1567            int32_t iFound,bPredEq;
1568            int32_t iMinSAD,iSAD;
1569    
1570            int32_t iSubBlock = (y&1)+(y&1) + (x&1);
1571    
1572            MainSearch8FuncPtr MainSearchPtr;
1573    
1574            /* Init variables */
1575            startMV.x = start_x;
1576            startMV.y = start_y;
1577    
1578            /* Get maximum range */
1579            get_range(&min_dx, &max_dx, &min_dy, &max_dy,
1580                      x, y, 8, iWidth, iHeight, iFcode);
1581    
1582            if (!(MotionFlags & PMV_HALFPELDIAMOND8 ))
1583            { min_dx = EVEN(min_dx);
1584              max_dx = EVEN(max_dx);
1585              min_dy = EVEN(min_dy);
1586              max_dy = EVEN(max_dy);
1587            }               /* because we might use IF (dx>max_dx) THEN dx=max_dx; */
1588    
1589    
1590            bPredEq  = get_pmvdata(pMBs, (x>>1), (y>>1), iWcount, iSubBlock, pmv, psad);
1591    
1592            if ((x==0) && (y==0) )
1593            {
1594                    threshA =  512/4;
1595                    threshB = 1024/4;
1596    
1597            }
1598            else
1599            {
1600                    threshA = psad[0]/4;                    /* good estimate */
1601                    threshB = threshA+256/4;
1602                    if (threshA< 512/4) threshA =  512/4;
1603                    if (threshA>1024/4) threshA = 1024/4;
1604                    if (threshB>1792/4) threshB = 1792/4;
1605            }
1606    
1607            iFound=0;
1608    
1609    /* Step 4: Calculate SAD around the Median prediction.
1610       MinSAD=SAD
1611       If Motion Vector equal to Previous frame motion vector
1612       and MinSAD<PrevFrmSAD goto Step 10.
1613       If SAD<=256 goto Step 10.
1614    */
1615    
1616    
1617    // Prepare for main loop
1618    
1619    //      if (MotionFlags & PMV_USESQUARES8)
1620    //              MainSearchPtr = Square8_MainSearch;
1621    //      else
1622    
1623            if (MotionFlags & PMV_ADVANCEDDIAMOND8)
1624                    MainSearchPtr = AdvDiamond8_MainSearch;
1625            else
1626                    MainSearchPtr = Diamond8_MainSearch;
1627    
1628    
1629            *currMV = startMV;
1630    
1631            iMinSAD = sad8( cur,
1632                            get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV, iEdgedWidth),
1633                            iEdgedWidth);
1634            iMinSAD += calc_delta_8(currMV->x - pmv[0].x, currMV->y - pmv[0].y, (uint8_t)iFcode, iQuant);
1635    
1636            if ( (iMinSAD < 256/4 ) || ( (MVequal(*currMV,prevMB->mvs[iSubBlock]))
1637                                    && ((uint32_t)iMinSAD < prevMB->sad8[iSubBlock]) ) )
1638            {
1639                    if (MotionFlags & PMV_QUICKSTOP16)
1640                            goto PMVfast8_Terminate_without_Refine;
1641                    if (MotionFlags & PMV_EARLYSTOP16)
1642                            goto PMVfast8_Terminate_with_Refine;
1643            }
1644    
1645    /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion
1646       vector of the median.
1647       If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2
1648    */
1649    
1650            if ((bPredEq) && (MVequal(pmv[0],prevMB->mvs[iSubBlock]) ) )
1651                    iFound=2;
1652    
1653    /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.
1654       Otherwise select large Diamond Search.
1655    */
1656    
1657            if ( (!MVzero(pmv[0])) || (threshB<1536/4) || (bPredEq) )
1658                    iDiamondSize=1; // 1 halfpel!
1659            else
1660                    iDiamondSize=2; // 2 halfpel = 1 full pixel!
1661    
1662            if (!(MotionFlags & PMV_HALFPELDIAMOND8) )
1663                  iDiamondSize*=2;                  iDiamondSize*=2;
1664    
1665    
1666    /*
1667       Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.
1668       Also calculate (0,0) but do not subtract offset.
1669       Let MinSAD be the smallest SAD up to this point.
1670       If MV is (0,0) subtract offset.
1671    */
1672    
1673    // the median prediction might be even better than mv16
1674    
1675            if (!MVequal(pmv[0],startMV))
1676                    CHECK_MV8_CANDIDATE(pmv[0].x,pmv[0].y);
1677    
1678    // (0,0) if needed
1679            if (!MVzero(pmv[0]))
1680            if (!MVzero(startMV))
1681            CHECK_MV8_ZERO;
1682    
1683    // previous frame MV if needed
1684            if (!MVzero(prevMB->mvs[iSubBlock]))
1685            if (!MVequal(prevMB->mvs[iSubBlock],startMV))
1686            if (!MVequal(prevMB->mvs[iSubBlock],pmv[0]))
1687            CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x,prevMB->mvs[iSubBlock].y);
1688    
1689            if ( (iMinSAD <= threshA) || ( MVequal(*currMV,prevMB->mvs[iSubBlock]) && ((uint32_t)iMinSAD < prevMB->sad8[iSubBlock]) ) )
1690            {
1691                    if (MotionFlags & PMV_QUICKSTOP16)
1692                            goto PMVfast8_Terminate_without_Refine;
1693                    if (MotionFlags & PMV_EARLYSTOP16)
1694                            goto PMVfast8_Terminate_with_Refine;
1695            }
1696    
1697    
1698    // left neighbour, if allowed and needed
1699            if (!MVzero(pmv[1]))
1700            if (!MVequal(pmv[1],startMV))
1701            if (!MVequal(pmv[1],prevMB->mvs[iSubBlock]))
1702            if (!MVequal(pmv[1],pmv[0]))
1703            {
1704                    if (!(MotionFlags & PMV_HALFPEL8 ))
1705                    {       pmv[1].x = EVEN(pmv[1].x);
1706                            pmv[1].y = EVEN(pmv[1].y);
1707                    }
1708                    CHECK_MV8_CANDIDATE(pmv[1].x,pmv[1].y);
1709            }
1710    
1711    // top neighbour, if allowed and needed
1712            if (!MVzero(pmv[2]))
1713            if (!MVequal(pmv[2],startMV))
1714            if (!MVequal(pmv[2],prevMB->mvs[iSubBlock]))
1715            if (!MVequal(pmv[2],pmv[0]))
1716            if (!MVequal(pmv[2],pmv[1]))
1717            {
1718                    if (!(MotionFlags & PMV_HALFPEL8 ))
1719                    {       pmv[2].x = EVEN(pmv[2].x);
1720                            pmv[2].y = EVEN(pmv[2].y);
1721                    }
1722                    CHECK_MV8_CANDIDATE(pmv[2].x,pmv[2].y);
1723    
1724    // top right neighbour, if allowed and needed
1725            if (!MVzero(pmv[3]))
1726            if (!MVequal(pmv[3],startMV))
1727            if (!MVequal(pmv[3],prevMB->mvs[iSubBlock]))
1728            if (!MVequal(pmv[3],pmv[0]))
1729            if (!MVequal(pmv[3],pmv[1]))
1730            if (!MVequal(pmv[3],pmv[2]))
1731                    {
1732                            if (!(MotionFlags & PMV_HALFPEL8 ))
1733                            {       pmv[3].x = EVEN(pmv[3].x);
1734                                    pmv[3].y = EVEN(pmv[3].y);
1735                            }
1736                            CHECK_MV8_CANDIDATE(pmv[3].x,pmv[3].y);
1737                    }
1738            }
1739    
1740            if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )
1741                    iMinSAD -= MV8_00_BIAS;
1742    
1743    
1744    /* Step 6: If MinSAD <= thresa goto Step 10.
1745       If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.
1746    */
1747    
1748            if ( (iMinSAD <= threshA) || ( MVequal(*currMV,prevMB->mvs[iSubBlock]) && ((uint32_t)iMinSAD < prevMB->sad8[iSubBlock]) ) )
1749            {
1750                    if (MotionFlags & PMV_QUICKSTOP16)
1751                            goto PMVfast8_Terminate_without_Refine;
1752                    if (MotionFlags & PMV_EARLYSTOP16)
1753                            goto PMVfast8_Terminate_with_Refine;
1754            }
1755    
1756    /************ (Diamond Search)  **************/
1757    /*
1758       Step 7: Perform Diamond search, with either the small or large diamond.
1759       If Found=2 only examine one Diamond pattern, and afterwards goto step 10
1760       Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.
1761       If center then goto step 10.
1762       Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.
1763       Refine by using small diamond and goto step 10.
1764    */
1765    
1766            backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */
1767    
1768    /* default: use best prediction as starting point for one call of PMVfast_MainSearch */
1769            iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
1770                                             x, y,
1771                                             currMV->x, currMV->y, iMinSAD, &newMV,
1772                                             pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);
1773    
1774            if (iSAD < iMinSAD)
1775            {
1776                    *currMV = newMV;
1777                    iMinSAD = iSAD;
1778            }
1779    
1780            if (MotionFlags & PMV_EXTSEARCH8)
1781            {
1782    /* extended: search (up to) two more times: orignal prediction and (0,0) */
1783    
1784                    if (!(MVequal(pmv[0],backupMV)) )
1785                    {       iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
1786                                                              x, y,
1787                                                              pmv[0].x, pmv[0].y, iMinSAD, &newMV,
1788                                                              pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);
1789    
1790                    if (iSAD < iMinSAD)
1791                    {
1792                            *currMV = newMV;
1793                            iMinSAD = iSAD;
1794                    }
1795                    }
1796    
1797                    if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )
1798                    {       iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
1799                                                              x, y,
1800                                                              0, 0, iMinSAD, &newMV,
1801                                                              pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);
1802    
1803                    if (iSAD < iMinSAD)
1804                    {
1805                            *currMV = newMV;
1806                            iMinSAD = iSAD;
1807                    }
1808                    }
1809            }
1810    
1811    /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.
1812       By performing an optional local half-pixel search, we can refine this result even further.
1813    */
1814    
1815    PMVfast8_Terminate_with_Refine:
1816            if (MotionFlags & PMV_HALFPELREFINE8)           // perform final half-pel step
1817                    iMinSAD = Halfpel8_Refine( pRef, pRefH, pRefV, pRefHV, cur,
1818                                                     x, y,
1819                                                     currMV, iMinSAD,
1820                                                     pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);
1821    
1822    
1823    PMVfast8_Terminate_without_Refine:
1824            currPMV->x = currMV->x - pmv[0].x;
1825            currPMV->y = currMV->y - pmv[0].y;
1826    
1827            return iMinSAD;
1828    }
1829    
1830    int32_t EPZSSearch16(
1831                                            const uint8_t * const pRef,
1832                                            const uint8_t * const pRefH,
1833                                            const uint8_t * const pRefV,
1834                                            const uint8_t * const pRefHV,
1835                                            const IMAGE * const pCur,
1836                                            const int x, const int y,
1837                                            const uint32_t MotionFlags,
1838                                            const uint32_t iQuant,
1839                                            const uint32_t iFcode,
1840                                            const MBParam * const pParam,
1841                                            const MACROBLOCK * const pMBs,
1842                                            const MACROBLOCK * const prevMBs,
1843                                            VECTOR * const currMV,
1844                                            VECTOR * const currPMV)
1845    {
1846        const uint32_t iWcount = pParam->mb_width;
1847        const uint32_t iHcount = pParam->mb_height;
1848    
1849            const int32_t iWidth = pParam->width;
1850            const int32_t iHeight = pParam->height;
1851            const int32_t iEdgedWidth = pParam->edged_width;
1852    
1853            const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;
1854    
1855            int32_t min_dx;
1856            int32_t max_dx;
1857            int32_t min_dy;
1858            int32_t max_dy;
1859    
1860            VECTOR newMV;
1861            VECTOR backupMV;
1862    
1863            VECTOR pmv[4];
1864            int32_t psad[8];
1865    
1866            static MACROBLOCK * oldMBs = NULL;
1867    //      const MACROBLOCK * const pMB = pMBs + x + y * iWcount;
1868            const MACROBLOCK * const prevMB = prevMBs + x + y * iWcount;
1869            MACROBLOCK * oldMB = NULL;
1870    
1871            static int32_t thresh2;
1872            int32_t bPredEq;
1873            int32_t iMinSAD,iSAD=9999;
1874    
1875            MainSearch16FuncPtr MainSearchPtr;
1876    
1877            if (oldMBs == NULL)
1878            {       oldMBs = (MACROBLOCK*) calloc(iWcount*iHcount,sizeof(MACROBLOCK));
1879    //              fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));
1880            }
1881            oldMB = oldMBs + x + y * iWcount;
1882    
1883    /* Get maximum range */
1884            get_range(&min_dx, &max_dx, &min_dy, &max_dy,
1885                            x, y, 16, iWidth, iHeight, iFcode);
1886    
1887            if (!(MotionFlags & PMV_HALFPEL16 ))
1888            { min_dx = EVEN(min_dx);
1889              max_dx = EVEN(max_dx);
1890              min_dy = EVEN(min_dy);
1891              max_dy = EVEN(max_dy);
1892            }               /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */
1893    
1894            bPredEq  = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);
1895    
1896  /* Step 4: Calculate SAD around the Median prediction.  /* Step 4: Calculate SAD around the Median prediction.
1897          MinSAD=SAD          MinSAD=SAD
1898          If Motion Vector equal to Previous frame motion vector          If Motion Vector equal to Previous frame motion vector
# Line 688  Line 1900 
1900          If SAD<=256 goto Step 10.          If SAD<=256 goto Step 10.
1901  */  */
1902    
   
1903  // Prepare for main loop  // Prepare for main loop
1904    
1905          *currMV=pmv[0];         /* current best := prediction */          *currMV=pmv[0];         /* current best := median prediction */
1906          if (!(MotionFlags & PMV_HALFPEL16 ))          if (!(MotionFlags & PMV_HALFPEL16 ))
1907          {       /* This should NOT be necessary! */          {
1908                  currMV->x = EVEN(currMV->x);                  currMV->x = EVEN(currMV->x);
1909                  currMV->y = EVEN(currMV->y);                  currMV->y = EVEN(currMV->y);
1910          }          }
1911    
1912          if (currMV->x > max_dx)          if (currMV->x > max_dx)
                 {  
1913                          currMV->x=max_dx;                          currMV->x=max_dx;
                 }  
1914          if (currMV->x < min_dx)          if (currMV->x < min_dx)
                 {  
1915                          currMV->x=min_dx;                          currMV->x=min_dx;
                 }  
1916          if (currMV->y > max_dy)          if (currMV->y > max_dy)
                 {  
1917                          currMV->y=max_dy;                          currMV->y=max_dy;
                 }  
1918          if (currMV->y < min_dy)          if (currMV->y < min_dy)
                 {  
1919                          currMV->y=min_dy;                          currMV->y=min_dy;
1920                  }  
1921    /***************** This is predictor SET A: only median prediction ******************/
1922    
1923          iMinSAD = sad16( cur,          iMinSAD = sad16( cur,
1924                  get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV, iEdgedWidth),                  get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV, iEdgedWidth),
1925                  iEdgedWidth, MV_MAX_ERROR);                  iEdgedWidth, MV_MAX_ERROR);
1926          iMinSAD += calc_delta_16(currMV->x-pmv[0].x, currMV->y-pmv[0].y, (uint8_t)iFcode) * iQuant;          iMinSAD += calc_delta_16(currMV->x-pmv[0].x, currMV->y-pmv[0].y, (uint8_t)iFcode, iQuant);
1927    
1928          if ( (iMinSAD < 256 ) || ( (MVequal(*currMV,pMB->mvs[0])) && (iMinSAD < pMB->sad16) ) )  // thresh1 is fixed to 256
1929            if ( (iMinSAD < 256 ) || ( (MVequal(*currMV, prevMB->mvs[0])) && ((uint32_t)iMinSAD < prevMB->sad16) ) )
1930                  {                  {
   
1931                          if (MotionFlags & PMV_QUICKSTOP16)                          if (MotionFlags & PMV_QUICKSTOP16)
1932                                  goto step10b;                                  goto EPZS16_Terminate_without_Refine;
1933                          if (MotionFlags & PMV_EARLYSTOP16)                          if (MotionFlags & PMV_EARLYSTOP16)
1934                                  goto step10;                                  goto EPZS16_Terminate_with_Refine;
1935                  }                  }
1936    
1937  /*  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/
 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. ******** WHAT'S THIS 'OFFSET' ??? ***********  
 */  
1938    
1939  // (0,0) is always possible  // previous frame MV
1940            CHECK_MV16_CANDIDATE(prevMB->mvs[0].x,prevMB->mvs[0].y);
1941    
1942    // set threshhold based on Min of Prediction and SAD of collocated block
1943    // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want
1944    
1945            if ((x==0) && (y==0) )
1946            {
1947                    thresh2 =  512;
1948            }
1949            else
1950            {
1951    /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */
1952    
1953                    thresh2 = MIN(psad[0],iSAD)*6/5 + 128;
1954            }
1955    
1956    // MV=(0,0) is often a good choice
1957    
1958          CHECK_MV16_ZERO;          CHECK_MV16_ZERO;
1959    
 // previous frame MV is always possible  
         CHECK_MV16_CANDIDATE(pMB->mvs[0].x,pMB->mvs[0].y);  
1960    
1961  // left neighbour, if allowed  // left neighbour, if allowed
1962          if (x != 0)          if (x != 0)
# Line 763  Line 1978 
1978                  CHECK_MV16_CANDIDATE(pmv[2].x,pmv[2].y);                  CHECK_MV16_CANDIDATE(pmv[2].x,pmv[2].y);
1979    
1980  // top right neighbour, if allowed  // top right neighbour, if allowed
1981                  if (x != (iWcount-1))                  if ((uint32_t)x != (iWcount-1))
1982                  {                  {
1983                          if (!(MotionFlags & PMV_HALFPEL16 ))                          if (!(MotionFlags & PMV_HALFPEL16 ))
1984                          {       pmv[3].x = EVEN(pmv[3].x);                          {       pmv[3].x = EVEN(pmv[3].x);
# Line 773  Line 1988 
1988                  }                  }
1989          }          }
1990    
1991  /* Step 6: If MinSAD <= thresa goto Step 10.  /* Terminate if MinSAD <= T_2
1992     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]
1993  */  */
1994    
1995          if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[0]) && (iMinSAD < pMB->sad16) ) )          if ( (iMinSAD <= thresh2)
1996                    || ( MVequal(*currMV,prevMB->mvs[0]) && ((uint32_t)iMinSAD <= prevMB->sad16) ) )
1997                  {                  {
1998                          if (MotionFlags & PMV_QUICKSTOP16)                          if (MotionFlags & PMV_QUICKSTOP16)
1999                                  goto step10b;                                  goto EPZS16_Terminate_without_Refine;
2000                          if (MotionFlags & PMV_EARLYSTOP16)                          if (MotionFlags & PMV_EARLYSTOP16)
2001                                  goto step10;                                  goto EPZS16_Terminate_with_Refine;
2002                  }                  }
2003    
2004    /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/
2005    
2006  /************ (Diamond Search)  **************/          backupMV = prevMB->mvs[0];              // collocated MV
2007  /*          backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x );    // acceleration X
2008  Step 7: Perform Diamond search, with either the small or large diamond.          backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y );    // acceleration Y
2009          If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
2010  Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.          CHECK_MV16_CANDIDATE(backupMV.x,backupMV.y);
2011          If center then goto step 10.  
2012  Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  // left neighbour
2013          Refine by using small diamond and goto step 10.          if (x != 0)
2014  */                  CHECK_MV16_CANDIDATE((prevMB-1)->mvs[0].x,(prevMB-1)->mvs[0].y);
2015    
2016    // top neighbour
2017            if (y != 0)
2018                    CHECK_MV16_CANDIDATE((prevMB-iWcount)->mvs[0].x,(prevMB-iWcount)->mvs[0].y);
2019    
2020    // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs
2021    
2022            if ((uint32_t)x != iWcount-1)
2023                    CHECK_MV16_CANDIDATE((prevMB+1)->mvs[0].x,(prevMB+1)->mvs[0].y);
2024    
2025    // bottom neighbour, dito
2026            if ((uint32_t)y != iHcount-1)
2027                    CHECK_MV16_CANDIDATE((prevMB+iWcount)->mvs[0].x,(prevMB+iWcount)->mvs[0].y);
2028    
2029    /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */
2030            if (iMinSAD <= thresh2)
2031                    {
2032                            if (MotionFlags & PMV_QUICKSTOP16)
2033                                    goto EPZS16_Terminate_without_Refine;
2034                            if (MotionFlags & PMV_EARLYSTOP16)
2035                                    goto EPZS16_Terminate_with_Refine;
2036                    }
2037    
2038    /************ (if Diamond Search)  **************/
2039    
2040          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */
2041    
2042  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */
2043          iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,  
2044            iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
2045                  x, y,                  x, y,
2046                  currMV->x, currMV->y, iMinSAD, &newMV,                          currMV->x, currMV->y, iMinSAD, &newMV, pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth,
2047                  pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);                          2, iFcode, iQuant, 0);
2048    
2049          if (iSAD < iMinSAD)          if (iSAD < iMinSAD)
2050          {          {
# Line 810  Line 2052 
2052                  iMinSAD = iSAD;                  iMinSAD = iSAD;
2053          }          }
2054    
2055    
2056          if (MotionFlags & PMV_EXTSEARCH16)          if (MotionFlags & PMV_EXTSEARCH16)
2057          {          {
2058  /* extended: search (up to) two more times: orignal prediction and (0,0) */  /* extended mode: search (up to) two more times: orignal prediction and (0,0) */
2059    
2060                  if (!(MVequal(pmv[0],backupMV)) )                  if (!(MVequal(pmv[0],backupMV)) )
2061                  {       iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,                  {
2062                            iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
2063                                  x, y,                                  x, y,
2064                          pmv[0].x, pmv[0].y, iMinSAD, &newMV,                          pmv[0].x, pmv[0].y, iMinSAD, &newMV,
2065                          pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);                                  pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);
2066                    }
2067    
2068                          if (iSAD < iMinSAD)                          if (iSAD < iMinSAD)
2069                          {                          {
2070                                  *currMV = newMV;                                  *currMV = newMV;
2071                                  iMinSAD = iSAD;                                  iMinSAD = iSAD;
2072                          }                          }
                 }  
2073    
2074                  if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )                  if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )
2075                  {       iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,                  {
2076                            iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
2077                                  x, y,                                  x, y,
2078                          0, 0, iMinSAD, &newMV,                          0, 0, iMinSAD, &newMV,
2079                          pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);                          pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);
2080    
2081                          if (iSAD < iMinSAD)                          if (iSAD < iMinSAD)
2082                          {                          {
# Line 841  Line 2086 
2086                  }                  }
2087          }          }
2088    
2089  /*  /***************        Choose best MV found     **************/
         Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  
 */  
2090    
2091  step10:  EPZS16_Terminate_with_Refine:
2092          if (MotionFlags & PMV_HALFPELREFINE16)          // perform final half-pel step          if (MotionFlags & PMV_HALFPELREFINE16)          // perform final half-pel step
2093                  iMinSAD = PMVfastSearch16_Refine( pRef, pRefH, pRefV, pRefHV, cur,                  iMinSAD = Halfpel16_Refine( pRef, pRefH, pRefV, pRefHV, cur,
2094                                  x, y,                                  x, y,
2095                                  currMV, iMinSAD,                                  currMV, iMinSAD,
2096                                  pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);                                  pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);
2097    
2098  step10b:  EPZS16_Terminate_without_Refine:
         currPMV->x = currMV->x - pmv[0].x;  
         currPMV->y = currMV->y - pmv[0].y;  
         return iMinSAD;  
 }  
   
   
   
   
   
   
 int32_t PMVfastSearch8_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 */  
   
         int32_t iDirection=0;  
         int32_t iSAD;  
         VECTOR backupMV;  
         backupMV.x = startx;  
         backupMV.y = starty;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         CHECK_MV8_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y,1);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);  
   
         if (iDirection)  
                 while (!iFound)  
                 {  
                         iFound = 1;  
                         backupMV=*currMV;       // since iDirection!=0, this is well defined!  
   
                         if ( iDirection != 2)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x-iDiamondSize,backupMV.y,1);  
                         if ( iDirection != 1)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x+iDiamondSize,backupMV.y,2);  
                         if ( iDirection != 4)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,backupMV.y-iDiamondSize,3);  
                         if ( iDirection != 3)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,backupMV.y+iDiamondSize,4);  
                 }  
         else  
                 {  
                         currMV->x = startx;  
                         currMV->y = starty;  
                 }  
         return iMinSAD;  
 }  
   
 int32_t PMVfastSearch8_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;  
2099    
2100          CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y-1);          *oldMB = *prevMB;
         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);  
2101    
2102            currPMV->x = currMV->x - pmv[0].x;
2103            currPMV->y = currMV->y - pmv[0].y;
2104          return iMinSAD;          return iMinSAD;
2105  }  }
2106    
2107    
2108  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)  int32_t EPZSSearch8(
   
 int32_t PMVfastSearch8(  
2109                                          const uint8_t * const pRef,                                          const uint8_t * const pRef,
2110                                          const uint8_t * const pRefH,                                          const uint8_t * const pRefH,
2111                                          const uint8_t * const pRefV,                                          const uint8_t * const pRefV,
2112                                          const uint8_t * const pRefHV,                                          const uint8_t * const pRefHV,
2113                                          const IMAGE * const pCur,                                          const IMAGE * const pCur,
2114                                          const int x, const int y,                                          const int x, const int y,
2115                                          const int start_x, int start_y,                                          const int start_x, const int start_y,
2116                                          const uint32_t MotionFlags,                                          const uint32_t MotionFlags,
2117                                          MBParam * const pParam,                                          const uint32_t iQuant,
2118                                          MACROBLOCK * const pMBs,                                          const uint32_t iFcode,
2119                                            const MBParam * const pParam,
2120                                            const MACROBLOCK * const pMBs,
2121                                            const MACROBLOCK * const prevMBs,
2122                                          VECTOR * const currMV,                                          VECTOR * const currMV,
2123                                          VECTOR * const currPMV)                                          VECTOR * const currPMV)
2124  {  {
2125          const uint32_t iWcount = pParam->mb_width;  /* Please not that EPZS might not be a good choice for 8x8-block motion search ! */
2126    
2127          const int32_t iFcode = pParam->fixed_code;          const uint32_t iWcount = pParam->mb_width;
         const int32_t iQuant = pParam->quant;  
2128          const int32_t iWidth = pParam->width;          const int32_t iWidth = pParam->width;
2129          const int32_t iHeight = pParam->height;          const int32_t iHeight = pParam->height;
2130          const int32_t iEdgedWidth = pParam->edged_width;          const int32_t iEdgedWidth = pParam->edged_width;
2131    
2132          const uint8_t * cur = pCur->y + x*8 + y*8*iEdgedWidth;          const uint8_t * cur = pCur->y + x*8 + y*8*iEdgedWidth;
2133    
2134          int32_t iDiamondSize;          int32_t iDiamondSize=1;
2135    
2136          int32_t min_dx;          int32_t min_dx;
2137          int32_t max_dx;          int32_t max_dx;
2138          int32_t min_dy;          int32_t min_dy;
2139          int32_t max_dy;          int32_t max_dy;
2140    
         VECTOR pmv[4];  
         int32_t psad[4];  
2141          VECTOR newMV;          VECTOR newMV;
2142          VECTOR backupMV;          VECTOR backupMV;
2143    
2144          MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          VECTOR pmv[4];
2145            int32_t psad[8];
2146    
2147            const   int32_t iSubBlock = ((y&1)<<1) + (x&1);
2148    
2149          static int32_t threshA,threshB;  //      const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;
2150          int32_t iFound,bPredEq;          const MACROBLOCK * const prevMB = prevMBs + (x>>1) + (y>>1) * iWcount;
         int32_t iMinSAD,iSAD;  
2151    
2152          int32_t iSubBlock = ((y&1)<<1) + (x&1);          int32_t bPredEq;
2153            int32_t iMinSAD,iSAD=9999;
2154    
2155            MainSearch8FuncPtr MainSearchPtr;
2156    
2157  /* Get maximum range */  /* Get maximum range */
2158      get_range(&min_dx, &max_dx, &min_dy, &max_dy,      get_range(&min_dx, &max_dx, &min_dy, &max_dy,
2159                          x, y, 8, iWidth, iHeight, iFcode);                          x, y, 8, iWidth, iHeight, iFcode);
2160    
2161  /* we work with abs. MVs, not relative to prediction, so range is relative to 0,0 */  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */
2162    
2163          if (!(MotionFlags & PMV_HALFPELDIAMOND8 ))          if (!(MotionFlags & PMV_HALFPEL8 ))
2164          { min_dx = EVEN(min_dx);          { min_dx = EVEN(min_dx);
2165            max_dx = EVEN(max_dx);            max_dx = EVEN(max_dx);
2166            min_dy = EVEN(min_dy);            min_dy = EVEN(min_dy);
2167            max_dy = EVEN(max_dy);            max_dy = EVEN(max_dy);
2168          }               /* because we might use IF (dx>max_dx) THEN dx=max_dx; */          }               /* 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);  
   
         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 2: 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],pMB->mvs[iSubBlock]) ) )  
                 iFound=2;  
   
 /* Step 3: If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.  
         Otherwise select large Diamond Search.  
 */  
2169    
2170          if ( (pmv[0].x != 0) || (pmv[0].y != 0) || (threshB<1536/4) || (bPredEq) )          bPredEq  = get_pmvdata(pMBs, x>>1, y>>1, iWcount, iSubBlock, pmv, psad);
                 iDiamondSize=1; // 1 halfpel!  
         else  
                 iDiamondSize=2; // 2 halfpel = 1 full pixel!  
2171    
         if (!(MotionFlags & PMV_HALFPELDIAMOND8) )  
                 iDiamondSize*=2;  
2172    
2173  /* Step 4: Calculate SAD around the Median prediction.  /* Step 4: Calculate SAD around the Median prediction.
2174          MinSAD=SAD          MinSAD=SAD
# Line 1060  Line 2177 
2177          If SAD<=256 goto Step 10.          If SAD<=256 goto Step 10.
2178  */  */
2179    
   
2180  // Prepare for main loop  // Prepare for main loop
2181    
2182          currMV->x=start_x;              /* start with mv16 */  
2183          currMV->y=start_y;          if (!(MotionFlags & PMV_HALFPEL8))
2184            {
2185                    currMV->x = EVEN(currMV->x);
2186                    currMV->y = EVEN(currMV->y);
2187            }
2188    
2189            if (currMV->x > max_dx)
2190                    currMV->x=max_dx;
2191            if (currMV->x < min_dx)
2192                    currMV->x=min_dx;
2193            if (currMV->y > max_dy)
2194                    currMV->y=max_dy;
2195            if (currMV->y < min_dy)
2196                    currMV->y=min_dy;
2197    
2198    /***************** This is predictor SET A: only median prediction ******************/
2199    
2200    
2201          iMinSAD = sad8( cur,          iMinSAD = sad8( cur,
2202                  get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV, iEdgedWidth),                  get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV, iEdgedWidth),
2203                  iEdgedWidth);                  iEdgedWidth);
2204          iMinSAD += calc_delta_8(currMV->x - pmv[0].x, currMV->y - pmv[0].y, (uint8_t)iFcode) * iQuant;          iMinSAD += calc_delta_8(currMV->x-pmv[0].x, currMV->y-pmv[0].y, (uint8_t)iFcode, iQuant);
2205    
2206    
2207          if ( (iMinSAD < 256/4 ) || ( (MVequal(*currMV,pMB->mvs[iSubBlock])) && (iMinSAD < pMB->sad8[iSubBlock]) ) )  // thresh1 is fixed to 256
2208            if (iMinSAD < 256/4 )
2209                  {                  {
2210                          if (MotionFlags & PMV_QUICKSTOP8)                          if (MotionFlags & PMV_QUICKSTOP8)
2211                                  goto step10_8b;                                  goto EPZS8_Terminate_without_Refine;
2212                          if (MotionFlags & PMV_EARLYSTOP8)                          if (MotionFlags & PMV_EARLYSTOP8)
2213                                  goto step10_8;                                  goto EPZS8_Terminate_with_Refine;
2214                  }                  }
2215    
2216  /*  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/
 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. ******** WHAT'S THIS 'OFFSET' ??? ***********  
 */  
2217    
 // the prediction might be even better than mv16  
         CHECK_MV8_CANDIDATE(pmv[0].x,pmv[0].y);  
2218    
2219  // (0,0) is always possible  // MV=(0,0) is often a good choice
2220          CHECK_MV8_ZERO;          CHECK_MV8_ZERO;
2221    
2222  // previous frame MV is always possible  // previous frame MV
2223          CHECK_MV8_CANDIDATE(pMB->mvs[iSubBlock].x,pMB->mvs[iSubBlock].y);          CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x,prevMB->mvs[iSubBlock].y);
2224    
2225  // left neighbour, if allowed  // left neighbour, if allowed
2226          if (psad[1] != MV_MAX_ERROR)          if (psad[1] != MV_MAX_ERROR)
# Line 1125  Line 2252 
2252                  }                  }
2253          }          }
2254    
2255  /* Step 6: If MinSAD <= thresa goto Step 10.  /*  // this bias is zero anyway, at the moment!
2256     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
2257            if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)
2258                    iMinSAD -= MV8_00_BIAS;
2259    
2260  */  */
2261    
2262          if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[iSubBlock]) && (iMinSAD < pMB->sad8[iSubBlock]) ) )  /* Terminate if MinSAD <= T_2
2263       Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]
2264    */
2265    
2266            if (iMinSAD < 512/4)    /* T_2 == 512/4 hardcoded */
2267                  {                  {
2268                          if (MotionFlags & PMV_QUICKSTOP8)                          if (MotionFlags & PMV_QUICKSTOP8)
2269                                  goto step10_8b;                                  goto EPZS8_Terminate_without_Refine;
2270                          if (MotionFlags & PMV_EARLYSTOP8)                          if (MotionFlags & PMV_EARLYSTOP8)
2271                                  goto step10_8;                                  goto EPZS8_Terminate_with_Refine;
2272                  }                  }
2273    
2274  /************ (Diamond Search)  **************/  /************ (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.  
 */  
2275    
2276          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */
2277    
2278  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          if (!(MotionFlags & PMV_HALFPELDIAMOND8))
2279          iSAD = PMVfastSearch8_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,                  iDiamondSize *= 2;
2280    
2281    /* default: use best prediction as starting point for one call of EPZS_MainSearch */
2282    
2283    /* // there is no EPZS^2 for inter4v at the moment
2284    
2285            if (MotionFlags & PMV_USESQUARES8)
2286                    MainSearchPtr = Square8_MainSearch;
2287            else
2288    */
2289    
2290    //      if (MotionFlags & PMV_USESQUARES8)
2291    //              MainSearchPtr = Square8_MainSearch;
2292    //      else
2293    
2294            if (MotionFlags & PMV_ADVANCEDDIAMOND8)
2295                    MainSearchPtr = AdvDiamond8_MainSearch;
2296            else
2297                    MainSearchPtr = Diamond8_MainSearch;
2298    
2299            iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
2300                  x, y,                  x, y,
2301                  currMV->x, currMV->y, iMinSAD, &newMV,                  currMV->x, currMV->y, iMinSAD, &newMV,
2302                  pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);                  pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth,
2303                    iDiamondSize, iFcode, iQuant, 0);
2304    
2305    
2306          if (iSAD < iMinSAD)          if (iSAD < iMinSAD)
2307          {          {
# Line 1163  Line 2311 
2311    
2312          if (MotionFlags & PMV_EXTSEARCH8)          if (MotionFlags & PMV_EXTSEARCH8)
2313          {          {
2314  /* extended: search (up to) two more times: orignal prediction and (0,0) */  /* extended mode: search (up to) two more times: orignal prediction and (0,0) */
2315    
2316                  if (!(MVequal(pmv[0],backupMV)) )                  if (!(MVequal(pmv[0],backupMV)) )
2317                  {       iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,                  {
2318                            iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
2319                                  x, y,                                  x, y,
2320                          pmv[0].x, pmv[0].y, iMinSAD, &newMV,                          pmv[0].x, pmv[0].y, iMinSAD, &newMV,
2321                          pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);                          pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, 0);
2322    
2323                          if (iSAD < iMinSAD)                          if (iSAD < iMinSAD)
2324                          {                          {
# Line 1179  Line 2328 
2328                  }                  }
2329    
2330                  if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )                  if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )
2331                  {       iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,                  {
2332                            iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
2333                                  x, y,                                  x, y,
2334                          0, 0, iMinSAD, &newMV,                          0, 0, iMinSAD, &newMV,
2335                          pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);                          pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, 0);
2336    
2337                          if (iSAD < iMinSAD)                          if (iSAD < iMinSAD)
2338                          {                          {
# Line 1192  Line 2342 
2342                  }                  }
2343          }          }
2344    
2345  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.  /***************        Choose best MV found     **************/
          By performing an optional local half-pixel search, we can refine this result even further.  
 */  
2346    
2347  step10_8:  EPZS8_Terminate_with_Refine:
2348          if (MotionFlags & PMV_HALFPELREFINE8)           // perform final half-pel step          if (MotionFlags & PMV_HALFPELREFINE8)           // perform final half-pel step
2349                  iMinSAD = PMVfastSearch8_Refine( pRef, pRefH, pRefV, pRefHV, cur,                  iMinSAD = Halfpel8_Refine( pRef, pRefH, pRefV, pRefHV, cur,
2350                                  x, y,                                  x, y,
2351                                  currMV, iMinSAD,                                  currMV, iMinSAD,
2352                                  pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);                                  pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);
2353    
2354  step10_8b:  EPZS8_Terminate_without_Refine:
2355    
2356          currPMV->x = currMV->x - pmv[0].x;          currPMV->x = currMV->x - pmv[0].x;
2357          currPMV->y = currMV->y - pmv[0].y;          currPMV->y = currMV->y - pmv[0].y;
   
2358          return iMinSAD;          return iMinSAD;
2359  }  }
2360    
2361    
2362    
2363    
2364    
2365    /* ***********************************************************
2366            bvop motion estimation
2367    // TODO: need to incorporate prediction here (eg. sad += calc_delta_16)
2368    ***************************************************************/
2369    
2370    
2371    void MotionEstimationBVOP(
2372                            MBParam * const pParam,
2373                            FRAMEINFO * const frame,
2374    
2375                            // forward (past) reference
2376                            const MACROBLOCK * const f_mbs,
2377                        const IMAGE * const f_ref,
2378                            const IMAGE * const f_refH,
2379                        const IMAGE * const f_refV,
2380                            const IMAGE * const f_refHV,
2381                            // backward (future) reference
2382                            const MACROBLOCK * const b_mbs,
2383                        const IMAGE * const b_ref,
2384                            const IMAGE * const b_refH,
2385                        const IMAGE * const b_refV,
2386                            const IMAGE * const b_refHV)
2387    {
2388        const uint32_t mb_width = pParam->mb_width;
2389        const uint32_t mb_height = pParam->mb_height;
2390            const int32_t edged_width = pParam->edged_width;
2391    
2392            uint32_t i,j;
2393    
2394            int32_t f_sad16;
2395            int32_t b_sad16;
2396            int32_t i_sad16;
2397            int32_t d_sad16;
2398            int32_t best_sad;
2399    
2400            VECTOR pmv_dontcare;
2401    
2402            // note: i==horizontal, j==vertical
2403        for (j = 0; j < mb_height; j++)
2404            {
2405                    for (i = 0; i < mb_width; i++)
2406                    {
2407                            MACROBLOCK *mb = &frame->mbs[i + j*mb_width];
2408                            const MACROBLOCK *f_mb = &f_mbs[i + j*mb_width];
2409                            const MACROBLOCK *b_mb = &b_mbs[i + j*mb_width];
2410    
2411                            if (b_mb->mode == MODE_INTER
2412                                    && b_mb->cbp == 0
2413                                    && b_mb->mvs[0].x == 0
2414                                    && b_mb->mvs[0].y == 0)
2415                            {
2416                                    mb->mode = MODE_NOT_CODED;
2417                                    mb->mvs[0].x = 0;
2418                                    mb->mvs[0].y = 0;
2419                                    mb->b_mvs[0].x = 0;
2420                                    mb->b_mvs[0].y = 0;
2421                                    continue;
2422                            }
2423    
2424    
2425                            // forward search
2426                            f_sad16 = SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
2427                                                    &frame->image,
2428                                                    i, j,
2429                                                    frame->motion_flags,  frame->quant, frame->fcode,
2430                                                    pParam,
2431                                                    f_mbs, f_mbs /* todo */,
2432                                                    &mb->mvs[0], &pmv_dontcare);    // ignore pmv
2433    
2434                            // backward search
2435                            b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
2436                                                    &frame->image,
2437                                                    i, j,
2438                                                    frame->motion_flags,  frame->quant, frame->bcode,
2439                                                    pParam,
2440                                                    b_mbs, b_mbs, /* todo */
2441                                                    &mb->b_mvs[0], &pmv_dontcare);  // ignore pmv
2442    
2443                            // interpolate search (simple, but effective)
2444                            i_sad16 = sad16bi_c(
2445                                            frame->image.y + i*16 + j*16*edged_width,
2446                                            get_ref(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
2447                                                    i, j, 16, mb->mvs[0].x, mb->mvs[0].y, edged_width),
2448                                            get_ref(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
2449                                                    i, j, 16, mb->b_mvs[0].x, mb->b_mvs[0].x, edged_width),
2450                                            edged_width);
2451    
2452                            // TODO: direct search
2453                            // predictor + range of [-32,32]
2454                            d_sad16 = 65535;
2455    
2456    
2457                            if (f_sad16 < b_sad16)
2458                            {
2459                                    best_sad = f_sad16;
2460                                    mb->mode = MODE_FORWARD;
2461                            }
2462                            else
2463                            {
2464                                    best_sad = b_sad16;
2465                                    mb->mode = MODE_BACKWARD;
2466                            }
2467    
2468                            if (i_sad16 < best_sad)
2469                            {
2470                                    best_sad = i_sad16;
2471                                    mb->mode = MODE_INTERPOLATE;
2472                            }
2473    
2474                            if (d_sad16 < best_sad)
2475                            {
2476                                    best_sad = d_sad16;
2477                                    mb->mode = MODE_DIRECT;
2478                            }
2479    
2480                    }
2481            }
2482    }

Legend:
Removed from v.3  
changed lines
  Added in v.181

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