[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 184, Mon May 27 18:07:38 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      const uint32_t iWcount = pParam->mb_width;      const uint32_t iWcount = pParam->mb_width;
277      const uint32_t iHcount = pParam->mb_height;      const uint32_t iHcount = pParam->mb_height;
278            MACROBLOCK * const pMBs = current->mbs;
279            MACROBLOCK * const prevMBs = reference->mbs;
280            const IMAGE * const pCurrent = &current->image;
281            const IMAGE * const pRef = &reference->image;
282    
283          uint32_t i, j, iIntra = 0;          const VECTOR zeroMV = {0,0};
284    
285      VECTOR mv16;          int32_t x, y;
286      VECTOR pmv16;          int32_t iIntra = 0;
287            VECTOR pmv;
288    
289      int32_t sad8 = 0;          if (sadInit)
290      int32_t sad16;                  (*sadInit)();
     int32_t deviation;  
291    
292          // note: i==horizontal, j==vertical          for (y = 0; y < iHcount; y++)
293      for (i = 0; i < iHcount; i++)                  for (x = 0; x < iWcount; x++)
                 for (j = 0; j < iWcount; j++)  
294                  {                  {
295                          MACROBLOCK *pMB = &pMBs[j + i * iWcount];                          MACROBLOCK* const pMB = &pMBs[x + y * iWcount];
   
                         sad16 = SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,  
                                           j, i, pParam->motion_flags,  
                                           pParam, pMBs, &mv16, &pmv16);  
                         pMB->sad16=sad16;  
296    
297                            pMB->sad16 = SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,
298                                                     x, y, current->motion_flags, current->quant, current->fcode,
299                                                     pParam, pMBs, prevMBs, &pMB->mv16, &pMB->pmvs[0]);
300    
301                  /* decide: MODE_INTER or MODE_INTRA                          if (0 < (pMB->sad16 - MV16_INTER_BIAS))
302                          if (dev_intra < sad_inter - 2 * nb) use_intra                          {
303                  */                                  int32_t deviation;
304                                    deviation = dev16(pCurrent->y + x*16 + y*16*pParam->edged_width, pParam->edged_width);
                 deviation = dev16(pCurrent->y + j*16 + i*16*pParam->edged_width, pParam->edged_width);  
305    
306                  if (deviation < (sad16 - INTER_BIAS))                                  if (deviation < (pMB->sad16 - MV16_INTER_BIAS))
307                  {                  {
308                          pMB->mode = MODE_INTRA;                          pMB->mode = MODE_INTRA;
309                          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] = pMB->mvs[2] = pMB->mvs[3] = zeroMV;
310                          pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = 0;                                          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = 0;
311    
312                          iIntra++;                          iIntra++;
313                          if(iIntra >= iLimit)                          if(iIntra >= iLimit)
# Line 312  Line 315 
315    
316                          continue;                          continue;
317                  }                  }
   
                 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]);  
   
                         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]);  
   
                         pMB->sad8[2] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,  
                                         2 * j, 2 * i + 1, mv16.x, mv16.y, pParam->motion_flags,  
                                         pParam, pMBs, &pMB->mvs[2], &pMB->pmvs[2]);  
   
                         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]);  
   
                         sad8 = pMB->sad8[0] + pMB->sad8[1] + pMB->sad8[2] + pMB->sad8[3];  
318                  }                  }
319    
320                            pmv = pMB->pmvs[0];
321                            if (current->global_flags & XVID_INTER4V)
322                                    if ( (!(current->global_flags & XVID_LUMIMASKING) || pMB->dquant == NO_CHANGE) )
323                                    {
324                                            int32_t sad8 = IMV16X16 * current->quant; if (sad8 < pMB->sad16)
325    
326                                            sad8 += pMB->sad8[0]            = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,
327                                                                                                                            2*x, 2*y, pMB->mv16.x, pMB->mv16.y,
328                                                                                                                            current->motion_flags, current->quant, current->fcode,
329                                                                                                                            pParam, pMBs, prevMBs, &pMB->mvs[0], &pMB->pmvs[0]);
330    
331                                            if (sad8 < pMB->sad16)
332                                                    sad8 += pMB->sad8[1]    = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,
333                                                                                                                            2*x+1, 2*y, pMB->mv16.x, pMB->mv16.y,
334                                                                                                                            current->motion_flags, current->quant, current->fcode,
335                                                                                                                            pParam, pMBs, prevMBs, &pMB->mvs[1], &pMB->pmvs[1]);
336    
337                                            if (sad8 < pMB->sad16)
338                                                    sad8 += pMB->sad8[2] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,
339                                                                                                                            2*x, 2*y+1, pMB->mv16.x, pMB->mv16.y,
340                                                                                                                            current->motion_flags, current->quant, current->fcode,
341                                                                                                                            pParam, pMBs, prevMBs, &pMB->mvs[2], &pMB->pmvs[2]);
342    
343                                            if (sad8 < pMB->sad16)
344                                                    sad8 += pMB->sad8[3]    = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,
345                                                                                                                            2*x+1, 2*y+1, pMB->mv16.x, pMB->mv16.y,
346                                                                                                                            current->motion_flags, current->quant, current->fcode,
347                                                                                                                            pParam, pMBs, prevMBs, &pMB->mvs[3], &pMB->pmvs[3]);
348    
349                  /* decide: MODE_INTER or MODE_INTER4V                  /* decide: MODE_INTER or MODE_INTER4V
350                          mpeg4:   if (sad8 < sad16 - nb/2+1) use_inter4v                                                  mpeg4:   if (sad8 < pMB->sad16 - nb/2+1) use_inter4v
351                  */                  */
352    
353                  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  
354                  {                  {
355                          sad8 = sad16;                                                  pMB->mode = MODE_INTER4V;
356                          pMB->mode = MODE_INTER;                              pMB->sad8[0] *= 4;
357                          pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = mv16.x;                                                  pMB->sad8[1] *= 4;
358                          pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = mv16.y;                                                  pMB->sad8[2] *= 4;
359                          pMB->pmvs[0].x = pmv16.x;                                                  pMB->sad8[3] *= 4;
360                          pMB->pmvs[0].y = pmv16.y;                                                  continue;
                 }  
361          }          }
362    
         return 0;  
363  }  }
364    
365  #define MVzero(A) ( ((A).x)==(0) && ((A).y)==(0) )                                  pMB->mode = MODE_INTER;
366                                    pMB->pmvs[0] = pmv; /* pMB->pmvs[1] = pMB->pmvs[2] = pMB->pmvs[3]  are not needed for INTER */
367  #define MVequal(A,B) ( ((A).x)==((B).x) && ((A).y)==((B).y) )                                  pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mv16;
368                                    pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = pMB->sad16;
369    
370                    }
371                    return 0;
372    }
373    
374  #define CHECK_MV16_ZERO {\  #define CHECK_MV16_ZERO {\
375    if ( (0 <= max_dx) && (0 >= min_dx) \    if ( (0 <= max_dx) && (0 >= min_dx) \
376      && (0 <= max_dy) && (0 >= min_dy) ) \      && (0 <= max_dy) && (0 >= min_dy) ) \
377    { \    { \
378      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); \
379      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; \  
380      if (iSAD < iMinSAD) \      if (iSAD < iMinSAD) \
381      {  iMinSAD=iSAD; currMV->x=0; currMV->y=0; }  }     \      {  iMinSAD=iSAD; currMV->x=0; currMV->y=0; }  }     \
382  }  }
383    
384    #define NOCHECK_MV16_CANDIDATE(X,Y) { \
385        iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \
386        iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode, iQuant);\
387        if (iSAD < iMinSAD) \
388        {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \
389    }
390    
391  #define CHECK_MV16_CANDIDATE(X,Y) { \  #define CHECK_MV16_CANDIDATE(X,Y) { \
392    if ( ((X) <= max_dx) && ((X) >= min_dx) \    if ( ((X) <= max_dx) && ((X) >= min_dx) \
393      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
394    { \    { \
395      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); \
396      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);\
397      if (iSAD < iMinSAD) \      if (iSAD < iMinSAD) \
398      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \
399  }  }
# Line 400  Line 403 
403      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
404    { \    { \
405      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); \
406      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);\
407      if (iSAD < iMinSAD) \      if (iSAD < iMinSAD) \
408      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \
409  }  }
# Line 410  Line 413 
413      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
414    { \    { \
415      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); \
416      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);\
417      if (iSAD < iMinSAD) \      if (iSAD < iMinSAD) \
418      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \
419  }  }
# Line 418  Line 421 
421    
422  #define CHECK_MV8_ZERO {\  #define CHECK_MV8_ZERO {\
423    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); \
424    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);\
425    if (iSAD < iMinSAD) \    if (iSAD < iMinSAD) \
426    { iMinSAD=iSAD; currMV->x=0; currMV->y=0; } \    { iMinSAD=iSAD; currMV->x=0; currMV->y=0; } \
427  }  }
428    
429    #define NOCHECK_MV8_CANDIDATE(X,Y) \
430      { \
431        iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \
432        iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode, iQuant);\
433        if (iSAD < iMinSAD) \
434        {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \
435    }
436    
437  #define CHECK_MV8_CANDIDATE(X,Y) { \  #define CHECK_MV8_CANDIDATE(X,Y) { \
438    if ( ((X) <= max_dx) && ((X) >= min_dx) \    if ( ((X) <= max_dx) && ((X) >= min_dx) \
439      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
440    { \    { \
441      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); \
442      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);\
443      if (iSAD < iMinSAD) \      if (iSAD < iMinSAD) \
444      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \
445  }  }
# Line 439  Line 449 
449      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
450    { \    { \
451      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); \
452      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);\
453      if (iSAD < iMinSAD) \      if (iSAD < iMinSAD) \
454      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \
455  }  }
# Line 449  Line 459 
459      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
460    { \    { \
461      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); \
462      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);\
463      if (iSAD < iMinSAD) \      if (iSAD < iMinSAD) \
464      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \
465  }  }
# Line 464  Line 474 
474                                          const IMAGE * const pCur,                                          const IMAGE * const pCur,
475                                          const int x, const int y,                                          const int x, const int y,
476                                          const uint32_t MotionFlags,                                          const uint32_t MotionFlags,
477                                            const uint32_t iQuant,
478                                            const uint32_t iFcode,
479                                          MBParam * const pParam,                                          MBParam * const pParam,
480                                          MACROBLOCK * const pMBs,                                          const MACROBLOCK * const pMBs,
481                                            const MACROBLOCK * const prevMBs,
482                                          VECTOR * const currMV,                                          VECTOR * const currMV,
483                                          VECTOR * const currPMV)                                          VECTOR * const currPMV)
484  {  {
485          const int32_t iEdgedWidth = pParam->edged_width;          const int32_t iEdgedWidth = pParam->edged_width;
         const int32_t iQuant = pParam->quant;  
486          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;
487          int32_t iSAD;          int32_t iSAD;
488          int32_t pred_x,pred_y;          int32_t pred_x,pred_y;
# Line 493  Line 505 
505  }  }
506  */  */
507    
508  int32_t PMVfastSearch16_MainSearch(  int32_t Diamond16_MainSearch(
509                                          const uint8_t * const pRef,                                          const uint8_t * const pRef,
510                                          const uint8_t * const pRefH,                                          const uint8_t * const pRefH,
511                                          const uint8_t * const pRefV,                                          const uint8_t * const pRefV,
# Line 550  Line 562 
562          return iMinSAD;          return iMinSAD;
563  }  }
564    
565  int32_t PMVfastSearch16_Refine(  int32_t Square16_MainSearch(
566                                          const uint8_t * const pRef,                                          const uint8_t * const pRef,
567                                          const uint8_t * const pRefH,                                          const uint8_t * const pRefH,
568                                          const uint8_t * const pRefV,                                          const uint8_t * const pRefV,
569                                          const uint8_t * const pRefHV,                                          const uint8_t * const pRefHV,
570                                          const uint8_t * const cur,                                          const uint8_t * const cur,
571                                          const int x, const int y,                                          const int x, const int y,
572                                          VECTOR * const currMV,                                          int32_t startx, int32_t starty,
573                                          int32_t iMinSAD,                                          int32_t iMinSAD,
574                                            VECTOR * const currMV,
575                                          const VECTOR * const pmv,                                          const VECTOR * const pmv,
576                                          const int32_t min_dx, const int32_t max_dx,                                          const int32_t min_dx, const int32_t max_dx,
577                                          const int32_t min_dy, const int32_t max_dy,                                          const int32_t min_dy, const int32_t max_dy,
578                                            const int32_t iEdgedWidth,
579                                            const int32_t iDiamondSize,
580                                          const int32_t iFcode,                                          const int32_t iFcode,
581                                          const int32_t iQuant,                                          const int32_t iQuant,
582                                          const int32_t iEdgedWidth)                                          int iFound)
583  {  {
584  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  /* Do a square search around given starting point, return SAD of best */
585    
586            int32_t iDirection=0;
587          int32_t iSAD;          int32_t iSAD;
588          VECTOR backupMV = *currMV;          VECTOR backupMV;
589            backupMV.x = startx;
590          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)  
591    
592  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;  
593    
594          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;  /*   new direction are extra, so 1-4 is normal diamond
595          537
596          1*2
597          648
598    */
599    
600          int32_t iDiamondSize;          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y,1);
601            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);
602            CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);
603            CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);
604    
605          int32_t min_dx;          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);
606          int32_t max_dx;          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);
607          int32_t min_dy;          CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);
608          int32_t max_dy;          CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);
609    
         int32_t iFound;  
610    
611          VECTOR newMV;          if (iDirection)
612          VECTOR backupMV;        /* just for PMVFAST */                  while (!iFound)
613                    {
614                            iFound = 1;
615                            backupMV=*currMV;
616    
617          VECTOR pmv[4];                          switch (iDirection)
618          int32_t psad[4];                          {
619                                    case 1:
620                                            CHECK_MV16_CANDIDATE_FOUND(backupMV.x-iDiamondSize,backupMV.y,1);
621                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);
622                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);
623                                            break;
624                                    case 2:
625                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);
626                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);
627                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);
628                                            break;
629    
630          MACROBLOCK * const pMB = pMBs + x + y * iWcount;                                  case 3:
631                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);
632                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);
633                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);
634                                            break;
635    
636          static int32_t threshA,threshB;                                  case 4:
637          int32_t bPredEq;                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);
638          int32_t iMinSAD,iSAD;                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);
639                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);
640                                            break;
641    
642  /* Get maximum range */                                  case 5:
643          get_range(&min_dx, &max_dx, &min_dy, &max_dy,                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y,1);
644                          x, y, 16, iWidth, iHeight, iFcode);                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);
645                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);
646                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);
647                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);
648                                            break;
649    
650  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */                                  case 6:
651                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);
652                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);
653    
654          if (!(MotionFlags & PMV_HALFPEL16 ))                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);
655          { min_dx = EVEN(min_dx);                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);
656            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; */  
657    
658                                            break;
659    
660          bPredEq  = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);                                  case 7:
661                                            CHECK_MV16_CANDIDATE_FOUND(backupMV.x-iDiamondSize,backupMV.y,1);
662                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);
663                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);
664                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);
665                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);
666                                            break;
667    
668          if ((x==0) && (y==0) )                                  case 8:
669          {                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);
670                  threshA =  512;                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);
671                  threshB = 1024;                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);
672                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);
673                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);
674                                            break;
675                            default:
676                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y,1);
677                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);
678                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);
679                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);
680    
681                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);
682                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);
683                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);
684                                            CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);
685                                            break;
686                            }
687          }          }
688          else          else
689          {          {
690                  threshA = psad[0];                          currMV->x = startx;
691                  threshB = threshA+256;                          currMV->y = starty;
692                  if (threshA< 512) threshA =  512;                  }
693                  if (threshA>1024) threshA = 1024;          return iMinSAD;
                 if (threshB>1792) threshB = 1792;  
694          }          }
695    
696          iFound=0;  
697    int32_t Full16_MainSearch(
698  /* Step 2: Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion                                          const uint8_t * const pRef,
699          vector of the median.                                          const uint8_t * const pRefH,
700          If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2                                          const uint8_t * const pRefV,
701  */                                          const uint8_t * const pRefHV,
702                                            const uint8_t * const cur,
703          if ((bPredEq) && (MVequal(pmv[0],pMB->mvs[0]) ) )                                          const int x, const int y,
704                  iFound=2;                                          int32_t startx, int32_t starty,
705                                            int32_t iMinSAD,
706  /* Step 3: If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.                                          VECTOR * const currMV,
707          Otherwise select large Diamond Search.                                          const VECTOR * const pmv,
708  */                                          const int32_t min_dx, const int32_t max_dx,
709                                            const int32_t min_dy, const int32_t max_dy,
710          if ( (pmv[0].x != 0) || (pmv[0].y != 0) || (threshB<1536) || (bPredEq) )                                          const int32_t iEdgedWidth,
711                  iDiamondSize=1; // halfpel!                                          const int32_t iDiamondSize,
712          else                                          const int32_t iFcode,
713                  iDiamondSize=2; // halfpel!                                          const int32_t iQuant,
714                                            int iFound)
715    {
716            int32_t iSAD;
717            int32_t dx,dy;
718            VECTOR backupMV;
719            backupMV.x = startx;
720            backupMV.y = starty;
721    
722            for (dx = min_dx; dx<=max_dx; dx+=iDiamondSize)
723                    for (dy = min_dy; dy<= max_dy; dy+=iDiamondSize)
724                            NOCHECK_MV16_CANDIDATE(dx,dy);
725    
726            return iMinSAD;
727    }
728    
729    int32_t AdvDiamond16_MainSearch(
730            const uint8_t * const pRef,
731            const uint8_t * const pRefH,
732            const uint8_t * const pRefV,
733            const uint8_t * const pRefHV,
734            const uint8_t * const cur,
735            const int x, const int y,
736            int32_t startx, int32_t starty,
737            int32_t iMinSAD,
738            VECTOR * const currMV,
739            const VECTOR * const pmv,
740            const int32_t min_dx, const int32_t max_dx,
741            const int32_t min_dy, const int32_t max_dy,
742            const int32_t iEdgedWidth,
743            const int32_t iDiamondSize,
744            const int32_t iFcode,
745            const int32_t iQuant,
746            int iDirection)
747    {
748    
749            int32_t iSAD;
750    
751    /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
752    
753            if (iDirection)
754            {
755                    CHECK_MV16_CANDIDATE(startx-iDiamondSize, starty);
756                    CHECK_MV16_CANDIDATE(startx+iDiamondSize, starty);
757                    CHECK_MV16_CANDIDATE(startx, starty-iDiamondSize);
758                    CHECK_MV16_CANDIDATE(startx, starty+iDiamondSize);
759            }
760            else
761            {
762                    int bDirection = 1+2+4+8;
763                    do
764                    {
765                            iDirection = 0;
766                            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)
767                                    CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize,starty,1);
768    
769                            if (bDirection&2)
770                                    CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize,starty,2);
771    
772                            if (bDirection&4)
773                                    CHECK_MV16_CANDIDATE_DIR(startx,starty-iDiamondSize,4);
774    
775                            if (bDirection&8)
776                                    CHECK_MV16_CANDIDATE_DIR(startx,starty+iDiamondSize,8);
777    
778                            /* now we're doing diagonal checks near our candidate */
779    
780                            if (iDirection) //checking if anything found
781                            {
782                                    bDirection = iDirection;
783                                    iDirection = 0;
784                                    startx=currMV->x; starty=currMV->y;
785                                    if (bDirection & 3) //our candidate is left or right
786                                    {
787                                            CHECK_MV16_CANDIDATE_DIR(startx,starty+iDiamondSize, 8);
788                                            CHECK_MV16_CANDIDATE_DIR(startx,starty-iDiamondSize, 4);
789                                    }
790                                    else // what remains here is up or down
791                                    {
792                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty, 2);
793                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty, 1);
794                                    }
795    
796                                    if (iDirection)
797                                    {       bDirection+=iDirection;
798                                            startx=currMV->x; starty=currMV->y;
799                                    }
800                            }
801                            else //about to quit, eh? not so fast....
802                            {
803                                    switch (bDirection)
804                                    {
805                                    case 2:
806                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
807                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
808                                            break;
809                                    case 1:
810                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
811                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
812                                            break;
813                                    case 2+4:
814                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
815                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
816                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
817                                            break;
818                                    case 4:
819                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
820                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
821                                            break;
822                                    case 8:
823                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
824                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
825                                            break;
826                                    case 1+4:
827                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
828                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
829                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
830                                            break;
831                                    case 2+8:
832                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
833                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
834                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
835                                            break;
836                                    case 1+8:
837                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
838                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
839                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
840                                            break;
841                                    default: //1+2+4+8 == we didn't find anything at all
842                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
843                                            CHECK_MV16_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
844                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
845                                            CHECK_MV16_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
846                                            break;
847                                    }
848                                    if (!iDirection) break; //ok, the end. really
849                                    else
850                                    {       bDirection=iDirection;
851                                            startx=currMV->x; starty=currMV->y;
852                                    }
853                            }
854                    }
855                    while (1); //forever
856            }
857            return iMinSAD;
858    }
859    
860    int32_t AdvDiamond8_MainSearch(
861            const uint8_t * const pRef,
862            const uint8_t * const pRefH,
863            const uint8_t * const pRefV,
864            const uint8_t * const pRefHV,
865            const uint8_t * const cur,
866            const int x, const int y,
867            int32_t startx, int32_t starty,
868            int32_t iMinSAD,
869            VECTOR * const currMV,
870            const VECTOR * const pmv,
871            const int32_t min_dx, const int32_t max_dx,
872            const int32_t min_dy, const int32_t max_dy,
873            const int32_t iEdgedWidth,
874            const int32_t iDiamondSize,
875            const int32_t iFcode,
876            const int32_t iQuant,
877            int iDirection)
878    {
879    
880            int32_t iSAD;
881    
882    /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
883    
884            if (iDirection)
885            {
886                    CHECK_MV8_CANDIDATE(startx-iDiamondSize, starty);
887                    CHECK_MV8_CANDIDATE(startx+iDiamondSize, starty);
888                    CHECK_MV8_CANDIDATE(startx, starty-iDiamondSize);
889                    CHECK_MV8_CANDIDATE(startx, starty+iDiamondSize);
890            }
891            else
892            {
893                    int bDirection = 1+2+4+8;
894                    do
895                    {
896                            iDirection = 0;
897                            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)
898                                    CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize,starty,1);
899    
900                            if (bDirection&2)
901                                    CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize,starty,2);
902    
903                            if (bDirection&4)
904                                    CHECK_MV8_CANDIDATE_DIR(startx,starty-iDiamondSize,4);
905    
906                            if (bDirection&8)
907                                    CHECK_MV8_CANDIDATE_DIR(startx,starty+iDiamondSize,8);
908    
909                            /* now we're doing diagonal checks near our candidate */
910    
911                            if (iDirection) //checking if anything found
912                            {
913                                    bDirection = iDirection;
914                                    iDirection = 0;
915                                    startx=currMV->x; starty=currMV->y;
916                                    if (bDirection & 3) //our candidate is left or right
917                                    {
918                                            CHECK_MV8_CANDIDATE_DIR(startx,starty+iDiamondSize, 8);
919                                            CHECK_MV8_CANDIDATE_DIR(startx,starty-iDiamondSize, 4);
920                                    }
921                                    else // what remains here is up or down
922                                    {
923                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty, 2);
924                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty, 1);
925                                    }
926    
927                                    if (iDirection)
928                                    {       bDirection+=iDirection;
929                                            startx=currMV->x; starty=currMV->y;
930                                    }
931                            }
932                            else //about to quit, eh? not so fast....
933                            {
934                                    switch (bDirection)
935                                    {
936                                    case 2:
937                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
938                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
939                                            break;
940                                    case 1:
941                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
942                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
943                                            break;
944                                    case 2+4:
945                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
946                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
947                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
948                                            break;
949                                    case 4:
950                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
951                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
952                                            break;
953                                    case 8:
954                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
955                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
956                                            break;
957                                    case 1+4:
958                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
959                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
960                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
961                                            break;
962                                    case 2+8:
963                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
964                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
965                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
966                                            break;
967                                    case 1+8:
968                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
969                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
970                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
971                                            break;
972                                    default: //1+2+4+8 == we didn't find anything at all
973                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty-iDiamondSize, 1+4);
974                                            CHECK_MV8_CANDIDATE_DIR(startx-iDiamondSize, starty+iDiamondSize, 1+8);
975                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty-iDiamondSize, 2+4);
976                                            CHECK_MV8_CANDIDATE_DIR(startx+iDiamondSize, starty+iDiamondSize, 2+8);
977                                            break;
978                                    }
979                                    if (!(iDirection)) break; //ok, the end. really
980                                    else
981                                    {       bDirection=iDirection;
982                                            startx=currMV->x; starty=currMV->y;
983                                    }
984                            }
985                    }
986                    while (1); //forever
987            }
988            return iMinSAD;
989    }
990    
991    
992    int32_t Full8_MainSearch(
993                                            const uint8_t * const pRef,
994                                            const uint8_t * const pRefH,
995                                            const uint8_t * const pRefV,
996                                            const uint8_t * const pRefHV,
997                                            const uint8_t * const cur,
998                                            const int x, const int y,
999                                            int32_t startx, int32_t starty,
1000                                            int32_t iMinSAD,
1001                                            VECTOR * const currMV,
1002                                            const VECTOR * const pmv,
1003                                            const int32_t min_dx, const int32_t max_dx,
1004                                            const int32_t min_dy, const int32_t max_dy,
1005                                            const int32_t iEdgedWidth,
1006                                            const int32_t iDiamondSize,
1007                                            const int32_t iFcode,
1008                                            const int32_t iQuant,
1009                                            int iFound)
1010    {
1011            int32_t iSAD;
1012            int32_t dx,dy;
1013            VECTOR backupMV;
1014            backupMV.x = startx;
1015            backupMV.y = starty;
1016    
1017            for (dx = min_dx; dx<=max_dx; dx+=iDiamondSize)
1018                    for (dy = min_dy; dy<= max_dy; dy+=iDiamondSize)
1019                            NOCHECK_MV8_CANDIDATE(dx,dy);
1020    
1021            return iMinSAD;
1022    }
1023    
1024    
1025    
1026    int32_t Halfpel16_Refine(
1027            const uint8_t * const pRef,
1028            const uint8_t * const pRefH,
1029            const uint8_t * const pRefV,
1030            const uint8_t * const pRefHV,
1031            const uint8_t * const cur,
1032            const int x, const int y,
1033            VECTOR * const currMV,
1034            int32_t iMinSAD,
1035            const VECTOR * const pmv,
1036            const int32_t min_dx, const int32_t max_dx,
1037            const int32_t min_dy, const int32_t max_dy,
1038            const int32_t iFcode,
1039            const int32_t iQuant,
1040            const int32_t iEdgedWidth)
1041    {
1042    /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */
1043    
1044            int32_t iSAD;
1045            VECTOR backupMV = *currMV;
1046    
1047            CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y-1);
1048            CHECK_MV16_CANDIDATE(backupMV.x  ,backupMV.y-1);
1049            CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y-1);
1050            CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y);
1051            CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y);
1052            CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y+1);
1053            CHECK_MV16_CANDIDATE(backupMV.x  ,backupMV.y+1);
1054            CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y+1);
1055    
1056            return iMinSAD;
1057    }
1058    
1059    #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)
1060    
1061    
1062    int32_t PMVfastSearch16(
1063                                            const uint8_t * const pRef,
1064                                            const uint8_t * const pRefH,
1065                                            const uint8_t * const pRefV,
1066                                            const uint8_t * const pRefHV,
1067                                            const IMAGE * const pCur,
1068                                            const int x, const int y,
1069                                            const uint32_t MotionFlags,
1070                                            const uint32_t iQuant,
1071                                            const uint32_t iFcode,
1072                                            const MBParam * const pParam,
1073                                            const MACROBLOCK * const pMBs,
1074                                            const MACROBLOCK * const prevMBs,
1075                                            VECTOR * const currMV,
1076                                            VECTOR * const currPMV)
1077    {
1078        const uint32_t iWcount = pParam->mb_width;
1079            const int32_t iWidth = pParam->width;
1080            const int32_t iHeight = pParam->height;
1081            const int32_t iEdgedWidth = pParam->edged_width;
1082    
1083            const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;
1084    
1085            int32_t iDiamondSize;
1086    
1087            int32_t min_dx;
1088            int32_t max_dx;
1089            int32_t min_dy;
1090            int32_t max_dy;
1091    
1092            int32_t iFound;
1093    
1094            VECTOR newMV;
1095            VECTOR backupMV;        /* just for PMVFAST */
1096    
1097            VECTOR pmv[4];
1098            int32_t psad[4];
1099    
1100            MainSearch16FuncPtr MainSearchPtr;
1101    
1102    //      const MACROBLOCK * const pMB = pMBs + x + y * iWcount;
1103            const MACROBLOCK * const prevMB = prevMBs + x + y * iWcount;
1104    
1105            static int32_t threshA,threshB;
1106            int32_t bPredEq;
1107            int32_t iMinSAD,iSAD;
1108    
1109    /* Get maximum range */
1110            get_range(&min_dx, &max_dx, &min_dy, &max_dy,
1111                      x, y, 16, iWidth, iHeight, iFcode);
1112    
1113    /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */
1114    
1115            if (!(MotionFlags & PMV_HALFPEL16 ))
1116            { min_dx = EVEN(min_dx);
1117            max_dx = EVEN(max_dx);
1118            min_dy = EVEN(min_dy);
1119            max_dy = EVEN(max_dy);
1120            }               /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */
1121    
1122    
1123            bPredEq  = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);
1124    
1125            if ((x==0) && (y==0) )
1126            {
1127                    threshA =  512;
1128                    threshB = 1024;
1129    
1130            }
1131            else
1132            {
1133                    threshA = psad[0];
1134                    threshB = threshA+256;
1135                    if (threshA< 512) threshA =  512;
1136                    if (threshA>1024) threshA = 1024;
1137                    if (threshB>1792) threshB = 1792;
1138            }
1139    
1140            iFound=0;
1141    
1142    /* Step 4: Calculate SAD around the Median prediction.
1143       MinSAD=SAD
1144       If Motion Vector equal to Previous frame motion vector
1145       and MinSAD<PrevFrmSAD goto Step 10.
1146       If SAD<=256 goto Step 10.
1147    */
1148    
1149            *currMV=pmv[0];         /* current best := prediction */
1150            if (!(MotionFlags & PMV_HALFPEL16 ))
1151            {       /* This should NOT be necessary! */
1152                    currMV->x = EVEN(currMV->x);
1153                    currMV->y = EVEN(currMV->y);
1154            }
1155    
1156            if (currMV->x > max_dx)
1157            {
1158                    currMV->x=max_dx;
1159            }
1160            if (currMV->x < min_dx)
1161            {
1162                    currMV->x=min_dx;
1163            }
1164            if (currMV->y > max_dy)
1165            {
1166                    currMV->y=max_dy;
1167            }
1168            if (currMV->y < min_dy)
1169            {
1170                    currMV->y=min_dy;
1171            }
1172    
1173            iMinSAD = sad16( cur,
1174                             get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV, iEdgedWidth),
1175                             iEdgedWidth, MV_MAX_ERROR);
1176            iMinSAD += calc_delta_16(currMV->x-pmv[0].x, currMV->y-pmv[0].y, (uint8_t)iFcode, iQuant);
1177    
1178            if ( (iMinSAD < 256 ) || ( (MVequal(*currMV,prevMB->mvs[0])) && ((uint32_t)iMinSAD < prevMB->sad16) ) )
1179            {
1180                    if (iMinSAD < 2*iQuant) // high chances for SKIP-mode
1181                    {
1182                            if (!MVzero(*currMV))
1183                            {
1184                                    iMinSAD += MV16_00_BIAS;
1185                                    CHECK_MV16_ZERO;                // (0,0) saves space for letterboxed pictures
1186                                    iMinSAD -= MV16_00_BIAS;
1187                            }
1188                    }
1189    
1190                    if (MotionFlags & PMV_QUICKSTOP16)
1191                            goto PMVfast16_Terminate_without_Refine;
1192                    if (MotionFlags & PMV_EARLYSTOP16)
1193                            goto PMVfast16_Terminate_with_Refine;
1194            }
1195    
1196    
1197    /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion
1198       vector of the median.
1199       If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2
1200    */
1201    
1202            if ((bPredEq) && (MVequal(pmv[0],prevMB->mvs[0]) ) )
1203                    iFound=2;
1204    
1205    /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.
1206       Otherwise select large Diamond Search.
1207    */
1208    
1209            if ( (!MVzero(pmv[0])) || (threshB<1536) || (bPredEq) )
1210                    iDiamondSize=1; // halfpel!
1211            else
1212                    iDiamondSize=2; // halfpel!
1213    
1214          if (!(MotionFlags & PMV_HALFPELDIAMOND16) )          if (!(MotionFlags & PMV_HALFPELDIAMOND16) )
1215                  iDiamondSize*=2;                  iDiamondSize*=2;
1216    
1217    /*
1218       Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.
1219       Also calculate (0,0) but do not subtract offset.
1220       Let MinSAD be the smallest SAD up to this point.
1221       If MV is (0,0) subtract offset.
1222    */
1223    
1224    // (0,0) is always possible
1225    
1226            if (!MVzero(pmv[0]))
1227                    CHECK_MV16_ZERO;
1228    
1229    // previous frame MV is always possible
1230    
1231            if (!MVzero(prevMB->mvs[0]))
1232            if (!MVequal(prevMB->mvs[0],pmv[0]))
1233                    CHECK_MV16_CANDIDATE(prevMB->mvs[0].x,prevMB->mvs[0].y);
1234    
1235    // left neighbour, if allowed
1236    
1237            if (!MVzero(pmv[1]))
1238            if (!MVequal(pmv[1],prevMB->mvs[0]))
1239            if (!MVequal(pmv[1],pmv[0]))
1240            {
1241                    if (!(MotionFlags & PMV_HALFPEL16 ))
1242                    {       pmv[1].x = EVEN(pmv[1].x);
1243                            pmv[1].y = EVEN(pmv[1].y);
1244                    }
1245    
1246                    CHECK_MV16_CANDIDATE(pmv[1].x,pmv[1].y);
1247            }
1248    
1249    // top neighbour, if allowed
1250            if (!MVzero(pmv[2]))
1251            if (!MVequal(pmv[2],prevMB->mvs[0]))
1252            if (!MVequal(pmv[2],pmv[0]))
1253            if (!MVequal(pmv[2],pmv[1]))
1254            {
1255                    if (!(MotionFlags & PMV_HALFPEL16 ))
1256                    {       pmv[2].x = EVEN(pmv[2].x);
1257                            pmv[2].y = EVEN(pmv[2].y);
1258                    }
1259                    CHECK_MV16_CANDIDATE(pmv[2].x,pmv[2].y);
1260    
1261    // top right neighbour, if allowed
1262                    if (!MVzero(pmv[3]))
1263                    if (!MVequal(pmv[3],prevMB->mvs[0]))
1264                    if (!MVequal(pmv[3],pmv[0]))
1265                    if (!MVequal(pmv[3],pmv[1]))
1266                    if (!MVequal(pmv[3],pmv[2]))
1267                    {
1268                            if (!(MotionFlags & PMV_HALFPEL16 ))
1269                            {       pmv[3].x = EVEN(pmv[3].x);
1270                                    pmv[3].y = EVEN(pmv[3].y);
1271                            }
1272                            CHECK_MV16_CANDIDATE(pmv[3].x,pmv[3].y);
1273                    }
1274            }
1275    
1276            if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96)*/ )
1277                    iMinSAD -= MV16_00_BIAS;
1278    
1279    
1280    /* Step 6: If MinSAD <= thresa goto Step 10.
1281       If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.
1282    */
1283    
1284            if ( (iMinSAD <= threshA) || ( MVequal(*currMV,prevMB->mvs[0]) && ((uint32_t)iMinSAD < prevMB->sad16) ) )
1285            {
1286                    if (MotionFlags & PMV_QUICKSTOP16)
1287                            goto PMVfast16_Terminate_without_Refine;
1288                    if (MotionFlags & PMV_EARLYSTOP16)
1289                            goto PMVfast16_Terminate_with_Refine;
1290            }
1291    
1292    
1293    /************ (Diamond Search)  **************/
1294    /*
1295       Step 7: Perform Diamond search, with either the small or large diamond.
1296       If Found=2 only examine one Diamond pattern, and afterwards goto step 10
1297       Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.
1298       If center then goto step 10.
1299       Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.
1300       Refine by using small diamond and goto step 10.
1301    */
1302    
1303            if (MotionFlags & PMV_USESQUARES16)
1304                    MainSearchPtr = Square16_MainSearch;
1305            else
1306                    if (MotionFlags & PMV_ADVANCEDDIAMOND16)
1307                            MainSearchPtr = AdvDiamond16_MainSearch;
1308                    else
1309                            MainSearchPtr = Diamond16_MainSearch;
1310    
1311            backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */
1312    
1313    /* default: use best prediction as starting point for one call of PMVfast_MainSearch */
1314            iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
1315                                              x, y,
1316                                              currMV->x, currMV->y, iMinSAD, &newMV,
1317                                              pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);
1318    
1319            if (iSAD < iMinSAD)
1320            {
1321                    *currMV = newMV;
1322                    iMinSAD = iSAD;
1323            }
1324    
1325            if (MotionFlags & PMV_EXTSEARCH16)
1326            {
1327    /* extended: search (up to) two more times: orignal prediction and (0,0) */
1328    
1329                    if (!(MVequal(pmv[0],backupMV)) )
1330                    {       iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
1331                                                              x, y,
1332                                                              pmv[0].x, pmv[0].y, iMinSAD, &newMV,
1333                                                              pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);
1334    
1335                    if (iSAD < iMinSAD)
1336                    {
1337                            *currMV = newMV;
1338                            iMinSAD = iSAD;
1339                    }
1340                    }
1341    
1342                    if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )
1343                    {       iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
1344                                                              x, y,
1345                                                              0, 0, iMinSAD, &newMV,
1346                                                              pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);
1347    
1348                    if (iSAD < iMinSAD)
1349                    {
1350                            *currMV = newMV;
1351                            iMinSAD = iSAD;
1352                    }
1353                    }
1354            }
1355    
1356    /*
1357       Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.
1358    */
1359    
1360    PMVfast16_Terminate_with_Refine:
1361            if (MotionFlags & PMV_HALFPELREFINE16)          // perform final half-pel step
1362                    iMinSAD = Halfpel16_Refine( pRef, pRefH, pRefV, pRefHV, cur,
1363                                      x, y,
1364                                      currMV, iMinSAD,
1365                                      pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);
1366    
1367    PMVfast16_Terminate_without_Refine:
1368            currPMV->x = currMV->x - pmv[0].x;
1369            currPMV->y = currMV->y - pmv[0].y;
1370            return iMinSAD;
1371    }
1372    
1373    
1374    
1375    
1376    
1377    
1378    int32_t Diamond8_MainSearch(
1379            const uint8_t * const pRef,
1380            const uint8_t * const pRefH,
1381            const uint8_t * const pRefV,
1382            const uint8_t * const pRefHV,
1383            const uint8_t * const cur,
1384            const int x, const int y,
1385            int32_t startx, int32_t starty,
1386            int32_t iMinSAD,
1387            VECTOR * const currMV,
1388            const VECTOR * const pmv,
1389            const int32_t min_dx, const int32_t max_dx,
1390            const int32_t min_dy, const int32_t max_dy,
1391            const int32_t iEdgedWidth,
1392            const int32_t iDiamondSize,
1393            const int32_t iFcode,
1394            const int32_t iQuant,
1395            int iFound)
1396    {
1397    /* Do a diamond search around given starting point, return SAD of best */
1398    
1399            int32_t iDirection=0;
1400            int32_t iSAD;
1401            VECTOR backupMV;
1402            backupMV.x = startx;
1403            backupMV.y = starty;
1404    
1405    /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */
1406    
1407            CHECK_MV8_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y,1);
1408            CHECK_MV8_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);
1409            CHECK_MV8_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);
1410            CHECK_MV8_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);
1411    
1412            if (iDirection)
1413                    while (!iFound)
1414                    {
1415                            iFound = 1;
1416                            backupMV=*currMV;       // since iDirection!=0, this is well defined!
1417    
1418                            if ( iDirection != 2)
1419                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x-iDiamondSize,backupMV.y,1);
1420                            if ( iDirection != 1)
1421                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x+iDiamondSize,backupMV.y,2);
1422                            if ( iDirection != 4)
1423                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x,backupMV.y-iDiamondSize,3);
1424                            if ( iDirection != 3)
1425                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x,backupMV.y+iDiamondSize,4);
1426                    }
1427            else
1428            {
1429                    currMV->x = startx;
1430                    currMV->y = starty;
1431            }
1432            return iMinSAD;
1433    }
1434    
1435    int32_t Halfpel8_Refine(
1436            const uint8_t * const pRef,
1437            const uint8_t * const pRefH,
1438            const uint8_t * const pRefV,
1439            const uint8_t * const pRefHV,
1440            const uint8_t * const cur,
1441            const int x, const int y,
1442            VECTOR * const currMV,
1443            int32_t iMinSAD,
1444            const VECTOR * const pmv,
1445            const int32_t min_dx, const int32_t max_dx,
1446            const int32_t min_dy, const int32_t max_dy,
1447            const int32_t iFcode,
1448            const int32_t iQuant,
1449            const int32_t iEdgedWidth)
1450    {
1451    /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */
1452    
1453            int32_t iSAD;
1454            VECTOR backupMV = *currMV;
1455    
1456            CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y-1);
1457            CHECK_MV8_CANDIDATE(backupMV.x  ,backupMV.y-1);
1458            CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y-1);
1459            CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y);
1460            CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y);
1461            CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y+1);
1462            CHECK_MV8_CANDIDATE(backupMV.x  ,backupMV.y+1);
1463            CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y+1);
1464    
1465            return iMinSAD;
1466    }
1467    
1468    
1469    #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)
1470    
1471    int32_t PMVfastSearch8(
1472                                            const uint8_t * const pRef,
1473                                            const uint8_t * const pRefH,
1474                                            const uint8_t * const pRefV,
1475                                            const uint8_t * const pRefHV,
1476                                            const IMAGE * const pCur,
1477                                            const int x, const int y,
1478                                            const int start_x, const int start_y,
1479                                            const uint32_t MotionFlags,
1480                                            const uint32_t iQuant,
1481                                            const uint32_t iFcode,
1482                                            const MBParam * const pParam,
1483                                            const MACROBLOCK * const pMBs,
1484                                            const MACROBLOCK * const prevMBs,
1485                                            VECTOR * const currMV,
1486                                            VECTOR * const currPMV)
1487    {
1488        const uint32_t iWcount = pParam->mb_width;
1489            const int32_t iWidth = pParam->width;
1490            const int32_t iHeight = pParam->height;
1491            const int32_t iEdgedWidth = pParam->edged_width;
1492    
1493            const uint8_t * cur = pCur->y + x*8 + y*8*iEdgedWidth;
1494    
1495            int32_t iDiamondSize;
1496    
1497            int32_t min_dx;
1498            int32_t max_dx;
1499            int32_t min_dy;
1500            int32_t max_dy;
1501    
1502            VECTOR pmv[4];
1503            int32_t psad[4];
1504            VECTOR newMV;
1505            VECTOR backupMV;
1506            VECTOR startMV;
1507    
1508    //      const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;
1509            const MACROBLOCK * const prevMB = prevMBs + (x>>1) + (y>>1) * iWcount;
1510    
1511            static int32_t threshA,threshB;
1512            int32_t iFound,bPredEq;
1513            int32_t iMinSAD,iSAD;
1514    
1515            int32_t iSubBlock = (y&1)+(y&1) + (x&1);
1516    
1517            MainSearch8FuncPtr MainSearchPtr;
1518    
1519            /* Init variables */
1520            startMV.x = start_x;
1521            startMV.y = start_y;
1522    
1523            /* Get maximum range */
1524            get_range(&min_dx, &max_dx, &min_dy, &max_dy,
1525                      x, y, 8, iWidth, iHeight, iFcode);
1526    
1527            if (!(MotionFlags & PMV_HALFPELDIAMOND8 ))
1528            { min_dx = EVEN(min_dx);
1529              max_dx = EVEN(max_dx);
1530              min_dy = EVEN(min_dy);
1531              max_dy = EVEN(max_dy);
1532            }               /* because we might use IF (dx>max_dx) THEN dx=max_dx; */
1533    
1534    
1535            bPredEq  = get_pmvdata(pMBs, (x>>1), (y>>1), iWcount, iSubBlock, pmv, psad);
1536    
1537            if ((x==0) && (y==0) )
1538            {
1539                    threshA =  512/4;
1540                    threshB = 1024/4;
1541    
1542            }
1543            else
1544            {
1545                    threshA = psad[0]/4;                    /* good estimate */
1546                    threshB = threshA+256/4;
1547                    if (threshA< 512/4) threshA =  512/4;
1548                    if (threshA>1024/4) threshA = 1024/4;
1549                    if (threshB>1792/4) threshB = 1792/4;
1550            }
1551    
1552            iFound=0;
1553    
1554    /* Step 4: Calculate SAD around the Median prediction.
1555       MinSAD=SAD
1556       If Motion Vector equal to Previous frame motion vector
1557       and MinSAD<PrevFrmSAD goto Step 10.
1558       If SAD<=256 goto Step 10.
1559    */
1560    
1561    
1562    // Prepare for main loop
1563    
1564    //      if (MotionFlags & PMV_USESQUARES8)
1565    //              MainSearchPtr = Square8_MainSearch;
1566    //      else
1567    
1568            if (MotionFlags & PMV_ADVANCEDDIAMOND8)
1569                    MainSearchPtr = AdvDiamond8_MainSearch;
1570            else
1571                    MainSearchPtr = Diamond8_MainSearch;
1572    
1573    
1574            *currMV = startMV;
1575    
1576            iMinSAD = sad8( cur,
1577                            get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV, iEdgedWidth),
1578                            iEdgedWidth);
1579            iMinSAD += calc_delta_8(currMV->x - pmv[0].x, currMV->y - pmv[0].y, (uint8_t)iFcode, iQuant);
1580    
1581            if ( (iMinSAD < 256/4 ) || ( (MVequal(*currMV,prevMB->mvs[iSubBlock]))
1582                                    && ((uint32_t)iMinSAD < prevMB->sad8[iSubBlock]) ) )
1583            {
1584                    if (MotionFlags & PMV_QUICKSTOP16)
1585                            goto PMVfast8_Terminate_without_Refine;
1586                    if (MotionFlags & PMV_EARLYSTOP16)
1587                            goto PMVfast8_Terminate_with_Refine;
1588            }
1589    
1590    /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion
1591       vector of the median.
1592       If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2
1593    */
1594    
1595            if ((bPredEq) && (MVequal(pmv[0],prevMB->mvs[iSubBlock]) ) )
1596                    iFound=2;
1597    
1598    /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.
1599       Otherwise select large Diamond Search.
1600    */
1601    
1602            if ( (!MVzero(pmv[0])) || (threshB<1536/4) || (bPredEq) )
1603                    iDiamondSize=1; // 1 halfpel!
1604            else
1605                    iDiamondSize=2; // 2 halfpel = 1 full pixel!
1606    
1607            if (!(MotionFlags & PMV_HALFPELDIAMOND8) )
1608                    iDiamondSize*=2;
1609    
1610    
1611    /*
1612       Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.
1613       Also calculate (0,0) but do not subtract offset.
1614       Let MinSAD be the smallest SAD up to this point.
1615       If MV is (0,0) subtract offset.
1616    */
1617    
1618    // the median prediction might be even better than mv16
1619    
1620            if (!MVequal(pmv[0],startMV))
1621                    CHECK_MV8_CANDIDATE(pmv[0].x,pmv[0].y);
1622    
1623    // (0,0) if needed
1624            if (!MVzero(pmv[0]))
1625            if (!MVzero(startMV))
1626            CHECK_MV8_ZERO;
1627    
1628    // previous frame MV if needed
1629            if (!MVzero(prevMB->mvs[iSubBlock]))
1630            if (!MVequal(prevMB->mvs[iSubBlock],startMV))
1631            if (!MVequal(prevMB->mvs[iSubBlock],pmv[0]))
1632            CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x,prevMB->mvs[iSubBlock].y);
1633    
1634            if ( (iMinSAD <= threshA) || ( MVequal(*currMV,prevMB->mvs[iSubBlock]) && ((uint32_t)iMinSAD < prevMB->sad8[iSubBlock]) ) )
1635            {
1636                    if (MotionFlags & PMV_QUICKSTOP16)
1637                            goto PMVfast8_Terminate_without_Refine;
1638                    if (MotionFlags & PMV_EARLYSTOP16)
1639                            goto PMVfast8_Terminate_with_Refine;
1640            }
1641    
1642    
1643    // left neighbour, if allowed and needed
1644            if (!MVzero(pmv[1]))
1645            if (!MVequal(pmv[1],startMV))
1646            if (!MVequal(pmv[1],prevMB->mvs[iSubBlock]))
1647            if (!MVequal(pmv[1],pmv[0]))
1648            {
1649                    if (!(MotionFlags & PMV_HALFPEL8 ))
1650                    {       pmv[1].x = EVEN(pmv[1].x);
1651                            pmv[1].y = EVEN(pmv[1].y);
1652                    }
1653                    CHECK_MV8_CANDIDATE(pmv[1].x,pmv[1].y);
1654            }
1655    
1656    // top neighbour, if allowed and needed
1657            if (!MVzero(pmv[2]))
1658            if (!MVequal(pmv[2],startMV))
1659            if (!MVequal(pmv[2],prevMB->mvs[iSubBlock]))
1660            if (!MVequal(pmv[2],pmv[0]))
1661            if (!MVequal(pmv[2],pmv[1]))
1662            {
1663                    if (!(MotionFlags & PMV_HALFPEL8 ))
1664                    {       pmv[2].x = EVEN(pmv[2].x);
1665                            pmv[2].y = EVEN(pmv[2].y);
1666                    }
1667                    CHECK_MV8_CANDIDATE(pmv[2].x,pmv[2].y);
1668    
1669    // top right neighbour, if allowed and needed
1670            if (!MVzero(pmv[3]))
1671            if (!MVequal(pmv[3],startMV))
1672            if (!MVequal(pmv[3],prevMB->mvs[iSubBlock]))
1673            if (!MVequal(pmv[3],pmv[0]))
1674            if (!MVequal(pmv[3],pmv[1]))
1675            if (!MVequal(pmv[3],pmv[2]))
1676                    {
1677                            if (!(MotionFlags & PMV_HALFPEL8 ))
1678                            {       pmv[3].x = EVEN(pmv[3].x);
1679                                    pmv[3].y = EVEN(pmv[3].y);
1680                            }
1681                            CHECK_MV8_CANDIDATE(pmv[3].x,pmv[3].y);
1682                    }
1683            }
1684    
1685            if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )
1686                    iMinSAD -= MV8_00_BIAS;
1687    
1688    
1689    /* Step 6: If MinSAD <= thresa goto Step 10.
1690       If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.
1691    */
1692    
1693            if ( (iMinSAD <= threshA) || ( MVequal(*currMV,prevMB->mvs[iSubBlock]) && ((uint32_t)iMinSAD < prevMB->sad8[iSubBlock]) ) )
1694            {
1695                    if (MotionFlags & PMV_QUICKSTOP16)
1696                            goto PMVfast8_Terminate_without_Refine;
1697                    if (MotionFlags & PMV_EARLYSTOP16)
1698                            goto PMVfast8_Terminate_with_Refine;
1699            }
1700    
1701    /************ (Diamond Search)  **************/
1702    /*
1703       Step 7: Perform Diamond search, with either the small or large diamond.
1704       If Found=2 only examine one Diamond pattern, and afterwards goto step 10
1705       Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.
1706       If center then goto step 10.
1707       Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.
1708       Refine by using small diamond and goto step 10.
1709    */
1710    
1711            backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */
1712    
1713    /* default: use best prediction as starting point for one call of PMVfast_MainSearch */
1714            iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
1715                                             x, y,
1716                                             currMV->x, currMV->y, iMinSAD, &newMV,
1717                                             pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);
1718    
1719            if (iSAD < iMinSAD)
1720            {
1721                    *currMV = newMV;
1722                    iMinSAD = iSAD;
1723            }
1724    
1725            if (MotionFlags & PMV_EXTSEARCH8)
1726            {
1727    /* extended: search (up to) two more times: orignal prediction and (0,0) */
1728    
1729                    if (!(MVequal(pmv[0],backupMV)) )
1730                    {       iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
1731                                                              x, y,
1732                                                              pmv[0].x, pmv[0].y, iMinSAD, &newMV,
1733                                                              pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);
1734    
1735                    if (iSAD < iMinSAD)
1736                    {
1737                            *currMV = newMV;
1738                            iMinSAD = iSAD;
1739                    }
1740                    }
1741    
1742                    if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )
1743                    {       iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
1744                                                              x, y,
1745                                                              0, 0, iMinSAD, &newMV,
1746                                                              pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);
1747    
1748                    if (iSAD < iMinSAD)
1749                    {
1750                            *currMV = newMV;
1751                            iMinSAD = iSAD;
1752                    }
1753                    }
1754            }
1755    
1756    /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.
1757       By performing an optional local half-pixel search, we can refine this result even further.
1758    */
1759    
1760    PMVfast8_Terminate_with_Refine:
1761            if (MotionFlags & PMV_HALFPELREFINE8)           // perform final half-pel step
1762                    iMinSAD = Halfpel8_Refine( pRef, pRefH, pRefV, pRefHV, cur,
1763                                                     x, y,
1764                                                     currMV, iMinSAD,
1765                                                     pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);
1766    
1767    
1768    PMVfast8_Terminate_without_Refine:
1769            currPMV->x = currMV->x - pmv[0].x;
1770            currPMV->y = currMV->y - pmv[0].y;
1771    
1772            return iMinSAD;
1773    }
1774    
1775    int32_t EPZSSearch16(
1776                                            const uint8_t * const pRef,
1777                                            const uint8_t * const pRefH,
1778                                            const uint8_t * const pRefV,
1779                                            const uint8_t * const pRefHV,
1780                                            const IMAGE * const pCur,
1781                                            const int x, const int y,
1782                                            const uint32_t MotionFlags,
1783                                            const uint32_t iQuant,
1784                                            const uint32_t iFcode,
1785                                            const MBParam * const pParam,
1786                                            const MACROBLOCK * const pMBs,
1787                                            const MACROBLOCK * const prevMBs,
1788                                            VECTOR * const currMV,
1789                                            VECTOR * const currPMV)
1790    {
1791        const uint32_t iWcount = pParam->mb_width;
1792        const uint32_t iHcount = pParam->mb_height;
1793    
1794            const int32_t iWidth = pParam->width;
1795            const int32_t iHeight = pParam->height;
1796            const int32_t iEdgedWidth = pParam->edged_width;
1797    
1798            const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;
1799    
1800            int32_t min_dx;
1801            int32_t max_dx;
1802            int32_t min_dy;
1803            int32_t max_dy;
1804    
1805            VECTOR newMV;
1806            VECTOR backupMV;
1807    
1808            VECTOR pmv[4];
1809            int32_t psad[8];
1810    
1811            static MACROBLOCK * oldMBs = NULL;
1812    //      const MACROBLOCK * const pMB = pMBs + x + y * iWcount;
1813            const MACROBLOCK * const prevMB = prevMBs + x + y * iWcount;
1814            MACROBLOCK * oldMB = NULL;
1815    
1816            static int32_t thresh2;
1817            int32_t bPredEq;
1818            int32_t iMinSAD,iSAD=9999;
1819    
1820            MainSearch16FuncPtr MainSearchPtr;
1821    
1822            if (oldMBs == NULL)
1823            {       oldMBs = (MACROBLOCK*) calloc(iWcount*iHcount,sizeof(MACROBLOCK));
1824    //              fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));
1825            }
1826            oldMB = oldMBs + x + y * iWcount;
1827    
1828    /* Get maximum range */
1829            get_range(&min_dx, &max_dx, &min_dy, &max_dy,
1830                            x, y, 16, iWidth, iHeight, iFcode);
1831    
1832            if (!(MotionFlags & PMV_HALFPEL16 ))
1833            { min_dx = EVEN(min_dx);
1834              max_dx = EVEN(max_dx);
1835              min_dy = EVEN(min_dy);
1836              max_dy = EVEN(max_dy);
1837            }               /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */
1838    
1839            bPredEq  = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);
1840    
1841  /* Step 4: Calculate SAD around the Median prediction.  /* Step 4: Calculate SAD around the Median prediction.
1842          MinSAD=SAD          MinSAD=SAD
1843          If Motion Vector equal to Previous frame motion vector          If Motion Vector equal to Previous frame motion vector
# Line 688  Line 1845 
1845          If SAD<=256 goto Step 10.          If SAD<=256 goto Step 10.
1846  */  */
1847    
   
1848  // Prepare for main loop  // Prepare for main loop
1849    
1850          *currMV=pmv[0];         /* current best := prediction */          *currMV=pmv[0];         /* current best := median prediction */
1851          if (!(MotionFlags & PMV_HALFPEL16 ))          if (!(MotionFlags & PMV_HALFPEL16 ))
1852          {       /* This should NOT be necessary! */          {
1853                  currMV->x = EVEN(currMV->x);                  currMV->x = EVEN(currMV->x);
1854                  currMV->y = EVEN(currMV->y);                  currMV->y = EVEN(currMV->y);
1855          }          }
1856    
1857          if (currMV->x > max_dx)          if (currMV->x > max_dx)
                 {  
1858                          currMV->x=max_dx;                          currMV->x=max_dx;
                 }  
1859          if (currMV->x < min_dx)          if (currMV->x < min_dx)
                 {  
1860                          currMV->x=min_dx;                          currMV->x=min_dx;
                 }  
1861          if (currMV->y > max_dy)          if (currMV->y > max_dy)
                 {  
1862                          currMV->y=max_dy;                          currMV->y=max_dy;
                 }  
1863          if (currMV->y < min_dy)          if (currMV->y < min_dy)
                 {  
1864                          currMV->y=min_dy;                          currMV->y=min_dy;
1865                  }  
1866    /***************** This is predictor SET A: only median prediction ******************/
1867    
1868          iMinSAD = sad16( cur,          iMinSAD = sad16( cur,
1869                  get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV, iEdgedWidth),                  get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV, iEdgedWidth),
1870                  iEdgedWidth, MV_MAX_ERROR);                  iEdgedWidth, MV_MAX_ERROR);
1871          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);
1872    
1873          if ( (iMinSAD < 256 ) || ( (MVequal(*currMV,pMB->mvs[0])) && (iMinSAD < pMB->sad16) ) )  // thresh1 is fixed to 256
1874            if ( (iMinSAD < 256 ) || ( (MVequal(*currMV, prevMB->mvs[0])) && ((uint32_t)iMinSAD < prevMB->sad16) ) )
1875                  {                  {
   
1876                          if (MotionFlags & PMV_QUICKSTOP16)                          if (MotionFlags & PMV_QUICKSTOP16)
1877                                  goto step10b;                                  goto EPZS16_Terminate_without_Refine;
1878                          if (MotionFlags & PMV_EARLYSTOP16)                          if (MotionFlags & PMV_EARLYSTOP16)
1879                                  goto step10;                                  goto EPZS16_Terminate_with_Refine;
1880                  }                  }
1881    
1882  /*  /************** 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' ??? ***********  
 */  
1883    
1884  // (0,0) is always possible  // previous frame MV
1885            CHECK_MV16_CANDIDATE(prevMB->mvs[0].x,prevMB->mvs[0].y);
1886    
1887    // set threshhold based on Min of Prediction and SAD of collocated block
1888    // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want
1889    
1890            if ((x==0) && (y==0) )
1891            {
1892                    thresh2 =  512;
1893            }
1894            else
1895            {
1896    /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */
1897    
1898                    thresh2 = MIN(psad[0],iSAD)*6/5 + 128;
1899            }
1900    
1901    // MV=(0,0) is often a good choice
1902    
1903          CHECK_MV16_ZERO;          CHECK_MV16_ZERO;
1904    
 // previous frame MV is always possible  
         CHECK_MV16_CANDIDATE(pMB->mvs[0].x,pMB->mvs[0].y);  
1905    
1906  // left neighbour, if allowed  // left neighbour, if allowed
1907          if (x != 0)          if (x != 0)
# Line 763  Line 1923 
1923                  CHECK_MV16_CANDIDATE(pmv[2].x,pmv[2].y);                  CHECK_MV16_CANDIDATE(pmv[2].x,pmv[2].y);
1924    
1925  // top right neighbour, if allowed  // top right neighbour, if allowed
1926                  if (x != (iWcount-1))                  if ((uint32_t)x != (iWcount-1))
1927                  {                  {
1928                          if (!(MotionFlags & PMV_HALFPEL16 ))                          if (!(MotionFlags & PMV_HALFPEL16 ))
1929                          {       pmv[3].x = EVEN(pmv[3].x);                          {       pmv[3].x = EVEN(pmv[3].x);
# Line 773  Line 1933 
1933                  }                  }
1934          }          }
1935    
1936  /* Step 6: If MinSAD <= thresa goto Step 10.  /* Terminate if MinSAD <= T_2
1937     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]
1938  */  */
1939    
1940          if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[0]) && (iMinSAD < pMB->sad16) ) )          if ( (iMinSAD <= thresh2)
1941                    || ( MVequal(*currMV,prevMB->mvs[0]) && ((uint32_t)iMinSAD <= prevMB->sad16) ) )
1942                  {                  {
1943                          if (MotionFlags & PMV_QUICKSTOP16)                          if (MotionFlags & PMV_QUICKSTOP16)
1944                                  goto step10b;                                  goto EPZS16_Terminate_without_Refine;
1945                          if (MotionFlags & PMV_EARLYSTOP16)                          if (MotionFlags & PMV_EARLYSTOP16)
1946                                  goto step10;                                  goto EPZS16_Terminate_with_Refine;
1947                  }                  }
1948    
1949    /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/
1950    
1951  /************ (Diamond Search)  **************/          backupMV = prevMB->mvs[0];              // collocated MV
1952  /*          backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x );    // acceleration X
1953  Step 7: Perform Diamond search, with either the small or large diamond.          backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y );    // acceleration Y
1954          If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
1955  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);
1956          If center then goto step 10.  
1957  Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  // left neighbour
1958          Refine by using small diamond and goto step 10.          if (x != 0)
1959  */                  CHECK_MV16_CANDIDATE((prevMB-1)->mvs[0].x,(prevMB-1)->mvs[0].y);
1960    
1961    // top neighbour
1962            if (y != 0)
1963                    CHECK_MV16_CANDIDATE((prevMB-iWcount)->mvs[0].x,(prevMB-iWcount)->mvs[0].y);
1964    
1965    // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs
1966    
1967            if ((uint32_t)x != iWcount-1)
1968                    CHECK_MV16_CANDIDATE((prevMB+1)->mvs[0].x,(prevMB+1)->mvs[0].y);
1969    
1970    // bottom neighbour, dito
1971            if ((uint32_t)y != iHcount-1)
1972                    CHECK_MV16_CANDIDATE((prevMB+iWcount)->mvs[0].x,(prevMB+iWcount)->mvs[0].y);
1973    
1974    /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */
1975            if (iMinSAD <= thresh2)
1976                    {
1977                            if (MotionFlags & PMV_QUICKSTOP16)
1978                                    goto EPZS16_Terminate_without_Refine;
1979                            if (MotionFlags & PMV_EARLYSTOP16)
1980                                    goto EPZS16_Terminate_with_Refine;
1981                    }
1982    
1983    /************ (if Diamond Search)  **************/
1984    
1985          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */
1986    
1987            if (MotionFlags & PMV_USESQUARES8)
1988                    MainSearchPtr = Square16_MainSearch;
1989            else
1990    
1991            if (MotionFlags & PMV_ADVANCEDDIAMOND8)
1992                    MainSearchPtr = AdvDiamond16_MainSearch;
1993            else
1994                    MainSearchPtr = Diamond16_MainSearch;
1995    
1996  /* 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 */
1997          iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,  
1998            iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
1999                  x, y,                  x, y,
2000                  currMV->x, currMV->y, iMinSAD, &newMV,                          currMV->x, currMV->y, iMinSAD, &newMV, pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth,
2001                  pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);                          2, iFcode, iQuant, 0);
2002    
2003          if (iSAD < iMinSAD)          if (iSAD < iMinSAD)
2004          {          {
# Line 810  Line 2006 
2006                  iMinSAD = iSAD;                  iMinSAD = iSAD;
2007          }          }
2008    
2009    
2010          if (MotionFlags & PMV_EXTSEARCH16)          if (MotionFlags & PMV_EXTSEARCH16)
2011          {          {
2012  /* 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) */
2013    
2014                  if (!(MVequal(pmv[0],backupMV)) )                  if (!(MVequal(pmv[0],backupMV)) )
2015                  {       iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,                  {
2016                            iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
2017                                  x, y,                                  x, y,
2018                          pmv[0].x, pmv[0].y, iMinSAD, &newMV,                          pmv[0].x, pmv[0].y, iMinSAD, &newMV,
2019                          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);
2020                    }
2021    
2022                          if (iSAD < iMinSAD)                          if (iSAD < iMinSAD)
2023                          {                          {
2024                                  *currMV = newMV;                                  *currMV = newMV;
2025                                  iMinSAD = iSAD;                                  iMinSAD = iSAD;
2026                          }                          }
                 }  
2027    
2028                  if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )                  if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )
2029                  {       iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,                  {
2030                            iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
2031                                  x, y,                                  x, y,
2032                          0, 0, iMinSAD, &newMV,                          0, 0, iMinSAD, &newMV,
2033                          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);
2034    
2035                          if (iSAD < iMinSAD)                          if (iSAD < iMinSAD)
2036                          {                          {
# Line 841  Line 2040 
2040                  }                  }
2041          }          }
2042    
2043  /*  /***************        Choose best MV found     **************/
         Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  
 */  
2044    
2045  step10:  EPZS16_Terminate_with_Refine:
2046          if (MotionFlags & PMV_HALFPELREFINE16)          // perform final half-pel step          if (MotionFlags & PMV_HALFPELREFINE16)          // perform final half-pel step
2047                  iMinSAD = PMVfastSearch16_Refine( pRef, pRefH, pRefV, pRefHV, cur,                  iMinSAD = Halfpel16_Refine( pRef, pRefH, pRefV, pRefHV, cur,
2048                                  x, y,                                  x, y,
2049                                  currMV, iMinSAD,                                  currMV, iMinSAD,
2050                                  pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);                                  pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);
2051    
2052  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;  
2053    
2054          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);  
2055    
2056            currPMV->x = currMV->x - pmv[0].x;
2057            currPMV->y = currMV->y - pmv[0].y;
2058          return iMinSAD;          return iMinSAD;
2059  }  }
2060    
2061    
2062  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)  int32_t EPZSSearch8(
   
 int32_t PMVfastSearch8(  
2063                                          const uint8_t * const pRef,                                          const uint8_t * const pRef,
2064                                          const uint8_t * const pRefH,                                          const uint8_t * const pRefH,
2065                                          const uint8_t * const pRefV,                                          const uint8_t * const pRefV,
2066                                          const uint8_t * const pRefHV,                                          const uint8_t * const pRefHV,
2067                                          const IMAGE * const pCur,                                          const IMAGE * const pCur,
2068                                          const int x, const int y,                                          const int x, const int y,
2069                                          const int start_x, int start_y,                                          const int start_x, const int start_y,
2070                                          const uint32_t MotionFlags,                                          const uint32_t MotionFlags,
2071                                          MBParam * const pParam,                                          const uint32_t iQuant,
2072                                          MACROBLOCK * const pMBs,                                          const uint32_t iFcode,
2073                                            const MBParam * const pParam,
2074                                            const MACROBLOCK * const pMBs,
2075                                            const MACROBLOCK * const prevMBs,
2076                                          VECTOR * const currMV,                                          VECTOR * const currMV,
2077                                          VECTOR * const currPMV)                                          VECTOR * const currPMV)
2078  {  {
2079          const uint32_t iWcount = pParam->mb_width;  /* Please not that EPZS might not be a good choice for 8x8-block motion search ! */
2080    
2081          const int32_t iFcode = pParam->fixed_code;          const uint32_t iWcount = pParam->mb_width;
         const int32_t iQuant = pParam->quant;  
2082          const int32_t iWidth = pParam->width;          const int32_t iWidth = pParam->width;
2083          const int32_t iHeight = pParam->height;          const int32_t iHeight = pParam->height;
2084          const int32_t iEdgedWidth = pParam->edged_width;          const int32_t iEdgedWidth = pParam->edged_width;
2085    
2086          const uint8_t * cur = pCur->y + x*8 + y*8*iEdgedWidth;          const uint8_t * cur = pCur->y + x*8 + y*8*iEdgedWidth;
2087    
2088          int32_t iDiamondSize;          int32_t iDiamondSize=1;
2089    
2090          int32_t min_dx;          int32_t min_dx;
2091          int32_t max_dx;          int32_t max_dx;
2092          int32_t min_dy;          int32_t min_dy;
2093          int32_t max_dy;          int32_t max_dy;
2094    
         VECTOR pmv[4];  
         int32_t psad[4];  
2095          VECTOR newMV;          VECTOR newMV;
2096          VECTOR backupMV;          VECTOR backupMV;
2097    
2098          MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          VECTOR pmv[4];
2099            int32_t psad[8];
2100    
2101          static int32_t threshA,threshB;          const   int32_t iSubBlock = ((y&1)<<1) + (x&1);
2102          int32_t iFound,bPredEq;  
2103          int32_t iMinSAD,iSAD;  //      const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;
2104            const MACROBLOCK * const prevMB = prevMBs + (x>>1) + (y>>1) * iWcount;
2105    
2106            int32_t bPredEq;
2107            int32_t iMinSAD,iSAD=9999;
2108    
2109          int32_t iSubBlock = ((y&1)<<1) + (x&1);          MainSearch8FuncPtr MainSearchPtr;
2110    
2111  /* Get maximum range */  /* Get maximum range */
2112      get_range(&min_dx, &max_dx, &min_dy, &max_dy,      get_range(&min_dx, &max_dx, &min_dy, &max_dy,
2113                          x, y, 8, iWidth, iHeight, iFcode);                          x, y, 8, iWidth, iHeight, iFcode);
2114    
2115  /* 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 */
2116    
2117          if (!(MotionFlags & PMV_HALFPELDIAMOND8 ))          if (!(MotionFlags & PMV_HALFPEL8 ))
2118          { min_dx = EVEN(min_dx);          { min_dx = EVEN(min_dx);
2119            max_dx = EVEN(max_dx);            max_dx = EVEN(max_dx);
2120            min_dy = EVEN(min_dy);            min_dy = EVEN(min_dy);
2121            max_dy = EVEN(max_dy);            max_dy = EVEN(max_dy);
2122          }               /* 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.  
 */  
2123    
2124          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!  
2125    
         if (!(MotionFlags & PMV_HALFPELDIAMOND8) )  
                 iDiamondSize*=2;  
2126    
2127  /* Step 4: Calculate SAD around the Median prediction.  /* Step 4: Calculate SAD around the Median prediction.
2128          MinSAD=SAD          MinSAD=SAD
# Line 1060  Line 2131 
2131          If SAD<=256 goto Step 10.          If SAD<=256 goto Step 10.
2132  */  */
2133    
   
2134  // Prepare for main loop  // Prepare for main loop
2135    
2136          currMV->x=start_x;              /* start with mv16 */  
2137          currMV->y=start_y;          if (!(MotionFlags & PMV_HALFPEL8))
2138            {
2139                    currMV->x = EVEN(currMV->x);
2140                    currMV->y = EVEN(currMV->y);
2141            }
2142    
2143            if (currMV->x > max_dx)
2144                    currMV->x=max_dx;
2145            if (currMV->x < min_dx)
2146                    currMV->x=min_dx;
2147            if (currMV->y > max_dy)
2148                    currMV->y=max_dy;
2149            if (currMV->y < min_dy)
2150                    currMV->y=min_dy;
2151    
2152    /***************** This is predictor SET A: only median prediction ******************/
2153    
2154    
2155          iMinSAD = sad8( cur,          iMinSAD = sad8( cur,
2156                  get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV, iEdgedWidth),                  get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV, iEdgedWidth),
2157                  iEdgedWidth);                  iEdgedWidth);
2158          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);
2159    
2160          if ( (iMinSAD < 256/4 ) || ( (MVequal(*currMV,pMB->mvs[iSubBlock])) && (iMinSAD < pMB->sad8[iSubBlock]) ) )  
2161    // thresh1 is fixed to 256
2162            if (iMinSAD < 256/4 )
2163                  {                  {
2164                          if (MotionFlags & PMV_QUICKSTOP8)                          if (MotionFlags & PMV_QUICKSTOP8)
2165                                  goto step10_8b;                                  goto EPZS8_Terminate_without_Refine;
2166                          if (MotionFlags & PMV_EARLYSTOP8)                          if (MotionFlags & PMV_EARLYSTOP8)
2167                                  goto step10_8;                                  goto EPZS8_Terminate_with_Refine;
2168                  }                  }
2169    
2170  /*  /************** 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' ??? ***********  
 */  
2171    
 // the prediction might be even better than mv16  
         CHECK_MV8_CANDIDATE(pmv[0].x,pmv[0].y);  
2172    
2173  // (0,0) is always possible  // MV=(0,0) is often a good choice
2174          CHECK_MV8_ZERO;          CHECK_MV8_ZERO;
2175    
2176  // previous frame MV is always possible  // previous frame MV
2177          CHECK_MV8_CANDIDATE(pMB->mvs[iSubBlock].x,pMB->mvs[iSubBlock].y);          CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x,prevMB->mvs[iSubBlock].y);
2178    
2179  // left neighbour, if allowed  // left neighbour, if allowed
2180          if (psad[1] != MV_MAX_ERROR)          if (psad[1] != MV_MAX_ERROR)
# Line 1125  Line 2206 
2206                  }                  }
2207          }          }
2208    
2209  /* Step 6: If MinSAD <= thresa goto Step 10.  /*  // this bias is zero anyway, at the moment!
2210     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
2211            if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)
2212                    iMinSAD -= MV8_00_BIAS;
2213    
2214    */
2215    
2216    /* Terminate if MinSAD <= T_2
2217       Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]
2218  */  */
2219    
2220          if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[iSubBlock]) && (iMinSAD < pMB->sad8[iSubBlock]) ) )          if (iMinSAD < 512/4)    /* T_2 == 512/4 hardcoded */
2221                  {                  {
2222                          if (MotionFlags & PMV_QUICKSTOP8)                          if (MotionFlags & PMV_QUICKSTOP8)
2223                                  goto step10_8b;                                  goto EPZS8_Terminate_without_Refine;
2224                          if (MotionFlags & PMV_EARLYSTOP8)                          if (MotionFlags & PMV_EARLYSTOP8)
2225                                  goto step10_8;                                  goto EPZS8_Terminate_with_Refine;
2226                  }                  }
2227    
2228  /************ (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.  
 */  
2229    
2230          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */
2231    
2232  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          if (!(MotionFlags & PMV_HALFPELDIAMOND8))
2233          iSAD = PMVfastSearch8_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,                  iDiamondSize *= 2;
2234    
2235    /* default: use best prediction as starting point for one call of EPZS_MainSearch */
2236    
2237    // there is no EPZS^2 for inter4v at the moment
2238    
2239    //      if (MotionFlags & PMV_USESQUARES8)
2240    //              MainSearchPtr = Square8_MainSearch;
2241    //      else
2242    
2243            if (MotionFlags & PMV_ADVANCEDDIAMOND8)
2244                    MainSearchPtr = AdvDiamond8_MainSearch;
2245            else
2246                    MainSearchPtr = Diamond8_MainSearch;
2247    
2248            iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
2249                  x, y,                  x, y,
2250                  currMV->x, currMV->y, iMinSAD, &newMV,                  currMV->x, currMV->y, iMinSAD, &newMV,
2251                  pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);                  pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth,
2252                    iDiamondSize, iFcode, iQuant, 0);
2253    
2254    
2255          if (iSAD < iMinSAD)          if (iSAD < iMinSAD)
2256          {          {
# Line 1163  Line 2260 
2260    
2261          if (MotionFlags & PMV_EXTSEARCH8)          if (MotionFlags & PMV_EXTSEARCH8)
2262          {          {
2263  /* 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) */
2264    
2265                  if (!(MVequal(pmv[0],backupMV)) )                  if (!(MVequal(pmv[0],backupMV)) )
2266                  {       iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,                  {
2267                            iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
2268                                  x, y,                                  x, y,
2269                          pmv[0].x, pmv[0].y, iMinSAD, &newMV,                          pmv[0].x, pmv[0].y, iMinSAD, &newMV,
2270                          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);
2271    
2272                          if (iSAD < iMinSAD)                          if (iSAD < iMinSAD)
2273                          {                          {
# Line 1179  Line 2277 
2277                  }                  }
2278    
2279                  if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )                  if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )
2280                  {       iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,                  {
2281                            iSAD = (*MainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,
2282                                  x, y,                                  x, y,
2283                          0, 0, iMinSAD, &newMV,                          0, 0, iMinSAD, &newMV,
2284                          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);
2285    
2286                          if (iSAD < iMinSAD)                          if (iSAD < iMinSAD)
2287                          {                          {
# Line 1192  Line 2291 
2291                  }                  }
2292          }          }
2293    
2294  /* 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.  
 */  
2295    
2296  step10_8:  EPZS8_Terminate_with_Refine:
2297          if (MotionFlags & PMV_HALFPELREFINE8)           // perform final half-pel step          if (MotionFlags & PMV_HALFPELREFINE8)           // perform final half-pel step
2298                  iMinSAD = PMVfastSearch8_Refine( pRef, pRefH, pRefV, pRefHV, cur,                  iMinSAD = Halfpel8_Refine( pRef, pRefH, pRefV, pRefHV, cur,
2299                                  x, y,                                  x, y,
2300                                  currMV, iMinSAD,                                  currMV, iMinSAD,
2301                                  pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);                                  pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);
2302    
2303  step10_8b:  EPZS8_Terminate_without_Refine:
2304    
2305          currPMV->x = currMV->x - pmv[0].x;          currPMV->x = currMV->x - pmv[0].x;
2306          currPMV->y = currMV->y - pmv[0].y;          currPMV->y = currMV->y - pmv[0].y;
   
2307          return iMinSAD;          return iMinSAD;
2308  }  }
2309    
2310    
2311    
2312    
2313    
2314    /* ***********************************************************
2315            bvop motion estimation
2316    // TODO: need to incorporate prediction here (eg. sad += calc_delta_16)
2317    ***************************************************************/
2318    
2319    
2320    void MotionEstimationBVOP(
2321                            MBParam * const pParam,
2322                            FRAMEINFO * const frame,
2323    
2324                            // forward (past) reference
2325                            const MACROBLOCK * const f_mbs,
2326                        const IMAGE * const f_ref,
2327                            const IMAGE * const f_refH,
2328                        const IMAGE * const f_refV,
2329                            const IMAGE * const f_refHV,
2330                            // backward (future) reference
2331                            const MACROBLOCK * const b_mbs,
2332                        const IMAGE * const b_ref,
2333                            const IMAGE * const b_refH,
2334                        const IMAGE * const b_refV,
2335                            const IMAGE * const b_refHV)
2336    {
2337        const uint32_t mb_width = pParam->mb_width;
2338        const uint32_t mb_height = pParam->mb_height;
2339            const int32_t edged_width = pParam->edged_width;
2340    
2341            uint32_t i,j;
2342    
2343            int32_t f_sad16;
2344            int32_t b_sad16;
2345            int32_t i_sad16;
2346            int32_t d_sad16;
2347            int32_t best_sad;
2348    
2349            VECTOR pmv_dontcare;
2350    
2351            // note: i==horizontal, j==vertical
2352        for (j = 0; j < mb_height; j++)
2353            {
2354                    for (i = 0; i < mb_width; i++)
2355                    {
2356                            MACROBLOCK *mb = &frame->mbs[i + j*mb_width];
2357                            const MACROBLOCK *f_mb = &f_mbs[i + j*mb_width];
2358                            const MACROBLOCK *b_mb = &b_mbs[i + j*mb_width];
2359    
2360                            if (b_mb->mode == MODE_INTER
2361                                    && b_mb->cbp == 0
2362                                    && b_mb->mvs[0].x == 0
2363                                    && b_mb->mvs[0].y == 0)
2364                            {
2365                                    mb->mode = MODE_NOT_CODED;
2366                                    mb->mvs[0].x = 0;
2367                                    mb->mvs[0].y = 0;
2368                                    mb->b_mvs[0].x = 0;
2369                                    mb->b_mvs[0].y = 0;
2370                                    continue;
2371                            }
2372    
2373    
2374                            // forward search
2375                            f_sad16 = SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
2376                                                    &frame->image,
2377                                                    i, j,
2378                                                    frame->motion_flags,  frame->quant, frame->fcode,
2379                                                    pParam,
2380                                                    f_mbs, f_mbs /* todo */,
2381                                                    &mb->mvs[0], &pmv_dontcare);    // ignore pmv
2382    
2383                            // backward search
2384                            b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
2385                                                    &frame->image,
2386                                                    i, j,
2387                                                    frame->motion_flags,  frame->quant, frame->bcode,
2388                                                    pParam,
2389                                                    b_mbs, b_mbs, /* todo */
2390                                                    &mb->b_mvs[0], &pmv_dontcare);  // ignore pmv
2391    
2392                            // interpolate search (simple, but effective)
2393                            i_sad16 = sad16bi_c(
2394                                            frame->image.y + i*16 + j*16*edged_width,
2395                                            get_ref(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
2396                                                    i, j, 16, mb->mvs[0].x, mb->mvs[0].y, edged_width),
2397                                            get_ref(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
2398                                                    i, j, 16, mb->b_mvs[0].x, mb->b_mvs[0].x, edged_width),
2399                                            edged_width);
2400    
2401                            // TODO: direct search
2402                            // predictor + range of [-32,32]
2403                            d_sad16 = 65535;
2404    
2405    
2406                            if (f_sad16 < b_sad16)
2407                            {
2408                                    best_sad = f_sad16;
2409                                    mb->mode = MODE_FORWARD;
2410                            }
2411                            else
2412                            {
2413                                    best_sad = b_sad16;
2414                                    mb->mode = MODE_BACKWARD;
2415                            }
2416    
2417                            if (i_sad16 < best_sad)
2418                            {
2419                                    best_sad = i_sad16;
2420                                    mb->mode = MODE_INTERPOLATE;
2421                            }
2422    
2423                            if (d_sad16 < best_sad)
2424                            {
2425                                    best_sad = d_sad16;
2426                                    mb->mode = MODE_DIRECT;
2427                            }
2428    
2429                    }
2430            }
2431    }

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

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