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

Legend:
Removed from v.351  
changed lines
  Added in v.1074

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