[svn] / branches / dev-api-4 / xvidcore / src / motion / motion_est.c Repository:
ViewVC logotype

Diff of /branches/dev-api-4/xvidcore/src/motion/motion_est.c

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

trunk/xvidcore/src/motion/motion_est.c revision 348, Sun Jul 28 17:10:39 2002 UTC branches/dev-api-4/xvidcore/src/motion/motion_est.c revision 1054, Mon Jun 9 13:55:56 2003 UTC
# Line 1  Line 1 
1  /**************************************************************************  /*****************************************************************************
2   *   *
3   *      XVID MPEG-4 VIDEO CODEC   *      XVID MPEG-4 VIDEO CODEC
4   *      motion estimation   *  - Motion Estimation related code  -
5   *   *
6   *      This program is an implementation of a part of one or more MPEG-4   *  Copyright(C) 2002 Christoph Lampert <gruel@web.de>
7   *      Video tools as specified in ISO/IEC 14496-2 standard.  Those intending   *               2002 Michael Militzer <michael@xvid.org>
8   *      to use this software module in hardware or software products are   *               2002-2003 Radoslaw Czyz <xvid@syskin.cjb.net>
  *      advised that its use may infringe existing patents or copyrights, and  
  *      any such use would be at such party's own risk.  The original  
  *      developer of this software module and his/her company, and subsequent  
  *      editors and their companies, will have no liability for use of this  
  *      software or modifications or derivatives thereof.  
9   *   *
10   *      This program is free software; you can redistribute it and/or modify   *      This program is free software; you can redistribute it and/or modify
11   *      it under the terms of the GNU General Public License as published by   *      it under the terms of the GNU General Public License as published by
# Line 24  Line 19 
19   *   *
20   *      You should have received a copy of the GNU General Public License   *      You should have received a copy of the GNU General Public License
21   *      along with this program; if not, write to the Free Software   *      along with this program; if not, write to the Free Software
22   *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
23   *   *
24   *************************************************************************/   * $Id: motion_est.c,v 1.58.2.17 2003-06-09 13:54:37 edgomez Exp $
   
 /**************************************************************************  
  *  
  *  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.  
25   *   *
26   *  Michael Militzer <isibaar@videocoding.de>   ****************************************************************************/
  *  
  **************************************************************************/  
27    
28  #include <assert.h>  #include <assert.h>
29  #include <stdio.h>  #include <stdio.h>
30  #include <stdlib.h>  #include <stdlib.h>
31    #include <string.h>     /* memcpy */
32    #include <math.h>       /* lrint */
33    
34  #include "../encoder.h"  #include "../encoder.h"
35  #include "../utils/mbfunctions.h"  #include "../utils/mbfunctions.h"
36  #include "../prediction/mbprediction.h"  #include "../prediction/mbprediction.h"
37  #include "../global.h"  #include "../global.h"
38  #include "../utils/timer.h"  #include "../utils/timer.h"
39    #include "../image/interpolate8x8.h"
40    #include "motion_est.h"
41  #include "motion.h"  #include "motion.h"
42  #include "sad.h"  #include "sad.h"
43    #include "../utils/emms.h"
44    #include "../dct/fdct.h"
45    
46    /*****************************************************************************
47     * Modified rounding tables -- declared in motion.h
48  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
49  { 0, (int) (1.00235 + 0.5), (int) (1.15582 + 0.5), (int) (1.31976 + 0.5),   ****************************************************************************/
50                  (int) (1.49591 + 0.5), (int) (1.68601 + 0.5),  
51          (int) (1.89187 + 0.5), (int) (2.11542 + 0.5), (int) (2.35878 + 0.5),  const uint32_t roundtab[16] =
52                  (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 };
53          (int) (3.23253 + 0.5), (int) (3.58158 + 0.5), (int) (3.96555 + 0.5),  
54                  (int) (4.38887 + 0.5), (int) (4.85673 + 0.5),  /* K = 4 */
55          (int) (5.37519 + 0.5), (int) (5.95144 + 0.5), (int) (6.59408 + 0.5),  const uint32_t roundtab_76[16] =
56                  (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 };
57          (int) (9.03669 + 0.5), (int) (10.0763 + 0.5), (int) (11.2669 + 0.5),  
58                  (int) (12.6426 + 0.5), (int) (14.2493 + 0.5),  /* K = 2 */
59          (int) (16.1512 + 0.5), (int) (18.442 + 0.5), (int) (21.2656 + 0.5),  const uint32_t roundtab_78[8] =
60                  (int) (24.8580 + 0.5), (int) (29.6436 + 0.5),  { 0, 0, 1, 1, 0, 0, 0, 1  };
61          (int) (36.4949 + 0.5)  
62  };  /* K = 1 */
63    const uint32_t roundtab_79[4] =
64  static int32_t *lambda_vec8 = lambda_vec16;     /* same table for INTER and INTER4V for now */  { 0, 1, 0, 0 };
65    
66    #define INITIAL_SKIP_THRESH     (10)
67    #define FINAL_SKIP_THRESH       (50)
68  // mv.length table  #define MAX_SAD00_FOR_SKIP      (20)
69  static const uint32_t mvtab[33] = {  #define MAX_CHROMA_SAD_FOR_SKIP (22)
70          1, 2, 3, 4, 6, 7, 7, 7,  
71          9, 9, 9, 10, 10, 10, 10, 10,  #define CHECK_CANDIDATE(X,Y,D) { \
72          10, 10, 10, 10, 10, 10, 10, 10,  CheckCandidate((X),(Y), (D), &iDirection, data ); }
73          10, 11, 11, 11, 11, 11, 11, 12, 12  
74  };  /*****************************************************************************
75     * Code
76     ****************************************************************************/
 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));  
 }  
77    
78  static __inline uint32_t  static __inline uint32_t
79  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)  
80  {  {
81          const int32_t iEdgedWidth = pParam->edged_width;          int bits;
82          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);  
83    
84          iSAD = sad16( cur,          x <<= qpel;
85                  get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth),          y <<= qpel;
86                  iEdgedWidth, MV_MAX_ERROR);          if (rrv) { x = RRV_MV_SCALEDOWN(x); y = RRV_MV_SCALEDOWN(y); }
87          if (iSAD <= iQuant * 96)  
88                  iSAD -= MV16_00_BIAS;          x -= pred.x;
89            bits = (x != 0 ? iFcode:0);
90          currMV->x = 0;          x = abs(x);
91          currMV->y = 0;          x += q;
92          currPMV->x = -pred.x;          x >>= (iFcode - 1);
93          currPMV->y = -pred.y;          bits += mvtab[x];
94    
95          return iSAD;          y -= pred.y;
96            bits += (y != 0 ? iFcode:0);
97  }          y = abs(y);
98  */          y += q;
99            y >>= (iFcode - 1);
100  int32_t          bits += mvtab[y];
101  Diamond16_MainSearch(const uint8_t * const pRef,  
102                                           const uint8_t * const pRefH,          return bits;
103                                           const uint8_t * const pRefV,  }
104                                           const uint8_t * const pRefHV,  
105                                           const uint8_t * const cur,  static int32_t ChromaSAD2(const int fx, const int fy, const int bx, const int by,
106                                           const int x,                                                          const SearchData * const data)
107                                           const int y,  {
108                                     const int start_x,          int sad;
109                                     const int start_y,          const uint32_t stride = data->iEdgedWidth/2;
110                                     int iMinSAD,          uint8_t * f_refu = data->RefQ,
111                                     VECTOR * const currMV,                  * f_refv = data->RefQ + 8,
112                                     const int center_x,                  * b_refu = data->RefQ + 16,
113                                     const int center_y,                  * b_refv = data->RefQ + 24;
114                                           const int32_t min_dx,          int offset = (fx>>1) + (fy>>1)*stride;
115                                           const int32_t max_dx,  
116                                           const int32_t min_dy,          switch (((fx & 1) << 1) | (fy & 1))     {
117                                           const int32_t max_dy,                  case 0:
118                                           const int32_t iEdgedWidth,                          f_refu = (uint8_t*)data->RefP[4] + offset;
119                                           const int32_t iDiamondSize,                          f_refv = (uint8_t*)data->RefP[5] + offset;
120                                           const int32_t iFcode,                          break;
                                          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);  
   
   
         if (iDirection) {  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;  
   
                         switch (iDirection) {  
121                          case 1:                          case 1:
122                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          interpolate8x8_halfpel_v(f_refu, data->RefP[4] + offset, stride, data->rounding);
123                                                                                     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);  
124                                  break;                                  break;
125                          case 2:                          case 2:
126                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,                          interpolate8x8_halfpel_h(f_refu, data->RefP[4] + offset, stride, data->rounding);
127                                                                                   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);  
128                                  break;                                  break;
129                    default:
130                          case 3:                          interpolate8x8_halfpel_hv(f_refu, data->RefP[4] + offset, stride, data->rounding);
131                                  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);  
132                                  break;                                  break;
133            }
134    
135                          case 4:          offset = (bx>>1) + (by>>1)*stride;
136                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,          switch (((bx & 1) << 1) | (by & 1))     {
137                                                                                   3);                  case 0:
138                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          b_refu = (uint8_t*)data->b_RefP[4] + offset;
139                                                                                   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);  
   
140                                  break;                                  break;
141                    case 1:
142                          case 7:                          interpolate8x8_halfpel_v(b_refu, data->b_RefP[4] + offset, stride, data->rounding);
143                                  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);  
144                                  break;                                  break;
145                    case 2:
146                          case 8:                          interpolate8x8_halfpel_h(b_refu, data->b_RefP[4] + offset, stride, data->rounding);
147                                  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);  
148                                  break;                                  break;
149                          default:                          default:
150                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,                          interpolate8x8_halfpel_hv(b_refu, data->b_RefP[4] + offset, stride, data->rounding);
151                                                                                   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);  
152                                  break;                                  break;
153                          }                          }
                 }  
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
         }  
         return iMinSAD;  
 }  
154    
155            sad = sad8bi(data->CurU, b_refu, f_refu, stride);
156            sad += sad8bi(data->CurV, b_refv, f_refv, stride);
157    
158  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;  
159  }  }
160    
161  int32_t  static int32_t
162  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)  
163  {  {
164            int sad;
165            const uint32_t stride = data->iEdgedWidth/2;
166            int offset = (dx>>1) + (dy>>1)*stride;
167    
168          int32_t iSAD;          if (dx == data->temp[5] && dy == data->temp[6]) return data->temp[7]; /* it has been checked recently */
169            data->temp[5] = dx; data->temp[6] = dy; /* backup */
170    
171  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */          switch (((dx & 1) << 1) | (dy & 1))     {
172                    case 0:
173          if (iDirection) {                          sad = sad8(data->CurU, data->RefP[4] + offset, stride);
174                  CHECK_MV16_CANDIDATE(start_x - iDiamondSize, start_y);                          sad += sad8(data->CurV, data->RefP[5] + offset, stride);
                 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);  
   
                         if (bDirection & 8)  
                                 CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
   
                         /* now we're doing diagonal checks near our candidate */  
   
                         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);  
175                                          break;                                          break;
176                                  case 1:                                  case 1:
177                            sad = sad8bi(data->CurU, data->RefP[4] + offset, data->RefP[4] + offset + stride, stride);
178                                          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);  
179                                          break;                                          break;
180                                  case 2 + 4:                  case 2:
181                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                          sad = sad8bi(data->CurU, data->RefP[4] + offset, data->RefP[4] + offset + 1, stride);
182                                                                                           start_y - iDiamondSize, 1 + 4);                          sad += sad8bi(data->CurV, data->RefP[5] + offset, data->RefP[5] + offset + 1, stride);
                                         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);  
                                         break;  
                                 case 8:  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         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);  
183                                          break;                                          break;
184                                  case 1 + 8:                  default:
185                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                          interpolate8x8_halfpel_hv(data->RefQ, data->RefP[4] + offset, stride, data->rounding);
186                                                                                           start_y - iDiamondSize, 2 + 4);                          sad = sad8(data->CurU, data->RefQ, stride);
187                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
188                                                                                           start_y + iDiamondSize, 2 + 8);                          interpolate8x8_halfpel_hv(data->RefQ, data->RefP[5] + offset, stride, data->rounding);
189                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                          sad += sad8(data->CurV, data->RefQ, stride);
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         break;  
                                 default:                //1+2+4+8 == we didn't find anything at all  
                                         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 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
190                                          break;                                          break;
191                                  }                                  }
192                                  if (!iDirection)          data->temp[7] = sad; /* backup, part 2 */
193                                          break;          //ok, the end. really          return sad;
                                 else {  
                                         bDirection = iDirection;  
                                         start_x = currMV->x;  
                                         start_y = currMV->y;  
                                 }  
                         }  
194                  }                  }
                 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,  
   
                                          const int x,  
                                          const int y,  
   
                                    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,  
195    
196                                          const int32_t iEdgedWidth,  static __inline const uint8_t *
197                                          const int32_t iDiamondSize,  GetReferenceB(const int x, const int y, const uint32_t dir, const SearchData * const data)
   
                                         const int32_t iQuant,  
                                         int iFound)  
198  {  {
199  /* Do a diamond search around given starting point, return SAD of best */          /* dir : 0 = forward, 1 = backward */
200            const uint8_t *const *const direction = ( dir == 0 ? data->RefP : data->b_RefP );
201          int32_t iSAD;          const int picture = ((x&1)<<1) | (y&1);
202            const int offset = (x>>1) + (y>>1)*data->iEdgedWidth;
203          VECTOR backupMV;          return direction[picture] + offset;
204    }
         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 */  
205    
206          do  /* this is a simpler copy of GetReferenceB, but as it's __inline anyway, we can keep the two separate */
207    static __inline const uint8_t *
208    GetReference(const int x, const int y, const SearchData * const data)
209          {          {
210                  iFound = 1;          const int picture = ((x&1)<<1) | (y&1);
211            const int offset = (x>>1) + (y>>1)*data->iEdgedWidth;
212                  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;  
213  }  }
214    
215    static uint8_t *
216  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)  
217  {  {
218            /* create or find a qpel-precision reference picture; return pointer to it */
219            uint8_t * Reference = data->RefQ + 16*dir;
220            const uint32_t iEdgedWidth = data->iEdgedWidth;
221            const uint32_t rounding = data->rounding;
222            const int halfpel_x = x/2;
223            const int halfpel_y = y/2;
224            const uint8_t *ref1, *ref2, *ref3, *ref4;
225    
226          int32_t iSAD;          ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
227            ref1 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
228  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */          switch( ((x&1)<<1) + (y&1) ) {
229            case 3: /* x and y in qpel resolution - the "corners" (top left/right and */
230          if (iDirection) {                          /* bottom left/right) during qpel refinement */
231                  CHECK_MV8_CANDIDATE(start_x - iDiamondSize, start_y);                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
232                  CHECK_MV8_CANDIDATE(start_x + iDiamondSize, start_y);                  ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
233                  CHECK_MV8_CANDIDATE(start_x, start_y - iDiamondSize);                  ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);
234                  CHECK_MV8_CANDIDATE(start_x, start_y + iDiamondSize);                  ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
235          } else {                  ref3 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
236                  int bDirection = 1 + 2 + 4 + 8;                  ref4 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
237                    interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
238                  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);  
239    
240                          if (bDirection & 2)          case 1: /* x halfpel, y qpel - top or bottom during qpel refinement */
241                                  CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
242                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
243                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
244                    break;
245    
246                          if (bDirection & 4)          case 2: /* x qpel, y halfpel - left or right during qpel refinement */
247                                  CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);                  ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
248                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
249                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
250                    break;
251    
252                          if (bDirection & 8)          default: /* pure halfpel position */
253                                  CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);                  return (uint8_t *) ref1;
254    
                         /* now we're doing diagonal checks near our candidate */  
   
                         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);  
255                                  }                                  }
256            return Reference;
                                 if (iDirection) {  
                                         bDirection += iDirection;  
                                         start_x = currMV->x;  
                                         start_y = currMV->y;  
257                                  }                                  }
258                          } else                          //about to quit, eh? not so fast....  
259    static uint8_t *
260    Interpolate16x16qpel(const int x, const int y, const uint32_t dir, const SearchData * const data)
261                          {                          {
262                                  switch (bDirection) {          /* create or find a qpel-precision reference picture; return pointer to it */
263                                  case 2:          uint8_t * Reference = data->RefQ + 16*dir;
264                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,          const uint32_t iEdgedWidth = data->iEdgedWidth;
265                                                                                          start_y - iDiamondSize, 2 + 4);          const uint32_t rounding = data->rounding;
266                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,          const int halfpel_x = x/2;
267                                                                                          start_y + iDiamondSize, 2 + 8);          const int halfpel_y = y/2;
268                                          break;          const uint8_t *ref1, *ref2, *ref3, *ref4;
269                                  case 1:  
270                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,          ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
271                                                                                          start_y - iDiamondSize, 1 + 4);          switch( ((x&1)<<1) + (y&1) ) {
272                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,          case 3:
273                                                                                          start_y + iDiamondSize, 1 + 8);                  /*
274                                          break;                   * x and y in qpel resolution - the "corners" (top left/right and
275                                  case 2 + 4:                   * bottom left/right) during qpel refinement
276                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                   */
277                                                                                          start_y - iDiamondSize, 1 + 4);                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
278                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                  ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
279                                                                                          start_y - iDiamondSize, 2 + 4);                  ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);
280                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                  interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
281                                                                                          start_y + iDiamondSize, 2 + 8);                  interpolate8x8_avg4(Reference+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, rounding);
282                                          break;                  interpolate8x8_avg4(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, rounding);
283                                  case 4:                  interpolate8x8_avg4(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, rounding);
                                         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          int32_t iSAD;          VECTOR * current;
316          VECTOR backupMV = *currMV;          int32_t sad; uint32_t t;
317    
318          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y - 1);          if ( (x > data->max_dx) || (x < data->min_dx)
319          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y - 1);                  || (y > data->max_dy) || (y < data->min_dy) ) return;
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y - 1);  
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y + 1);  
         CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y + 1);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y + 1);  
320    
321          return iMinSAD;          if (!data->qpel_precision) {
322                    Reference = GetReference(x, y, data);
323                    current = data->currentMV;
324                    xc = x; yc = y;
325            } else { /* x and y are in 1/4 precision */
326                    Reference = Interpolate16x16qpel(x, y, 0, data);
327                    xc = x/2; yc = y/2; /* for chroma sad */
328                    current = data->currentQMV;
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,          }
345                                  const IMAGE * const pCur,  
346                                  const int x,          if (data->temp[1] < data->iMinSAD[1]) {
347                                  const int y,                  data->iMinSAD[1] = data->temp[1]; current[1].x = x; current[1].y = y; }
348                                  const int start_x,      /* start is searched first, so it should contain the most */          if (data->temp[2] < data->iMinSAD[2]) {
349                                  const int start_y,  /* likely motion vector for this block */                  data->iMinSAD[2] = data->temp[2]; current[2].x = x; current[2].y = y; }
350                                  const int center_x,     /* center is from where length of MVs is measured */          if (data->temp[3] < data->iMinSAD[3]) {
351                                  const int center_y,                  data->iMinSAD[3] = data->temp[3]; current[3].x = x; current[3].y = y; }
352                                  const uint32_t MotionFlags,          if (data->temp[4] < data->iMinSAD[4]) {
353                                  const uint32_t iQuant,                  data->iMinSAD[4] = data->temp[4]; current[4].x = x; current[4].y = y; }
354                                  const uint32_t iFcode,  }
355                                  const MBParam * const pParam,  
356                                  const MACROBLOCK * const pMBs,  static void
357                                  const MACROBLOCK * const prevMBs,  CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                                 VECTOR * const currMV,  
                                 VECTOR * const currPMV)  
358  {  {
359          const uint32_t iWcount = pParam->mb_width;          int32_t sad; uint32_t t;
360          const int32_t iWidth = pParam->width;          const uint8_t * Reference;
361          const int32_t iHeight = pParam->height;          VECTOR * current;
         const int32_t iEdgedWidth = pParam->edged_width;  
362    
363          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          if ( (x > data->max_dx) || (x < data->min_dx)
364                    || (y > data->max_dy) || (y < data->min_dy) ) return;
365    
366          int32_t iDiamondSize;          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          int32_t min_dx;          sad = sad8(data->Cur, Reference, data->iEdgedWidth);
375          int32_t max_dx;          t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
         int32_t min_dy;  
         int32_t max_dy;  
376    
377          int32_t iFound;          sad += (data->lambda8 * t * (sad+NEIGH_8X8_BIAS))>>10;
378    
379          VECTOR newMV;          if (sad < *(data->iMinSAD)) {
380          VECTOR backupMV;                        /* just for PMVFAST */                  *(data->iMinSAD) = sad;
381                    current->x = x; current->y = y;
382                    *dir = Direction;
383            }
384    }
385    
386          VECTOR pmv[4];  static void
387          int32_t psad[4];  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          MainSearch16FuncPtr MainSearchPtr;          if ( (!(x&1) && x !=0) || (!(y&1) && y !=0) || /* non-zero even value */
393                    (x > data->max_dx) || (x < data->min_dx)
394                    || (y > data->max_dy) || (y < data->min_dy) ) return;
395    
396          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;          Reference = GetReference(x, y, data);
397            t = d_mv_bits(x, y, data->predMV, data->iFcode, 0, 1);
398    
399          int32_t threshA, threshB;          data->temp[0] = sad32v_c(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD;  
400    
401  /* Get maximum range */          data->temp[0] += (data->lambda16 * t * data->temp[0]) >> 10;
402          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;
                           iFcode);  
403    
404  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          if (data->temp[0] < data->iMinSAD[0]) {
405                    data->iMinSAD[0] = data->temp[0];
406                    data->currentMV[0].x = x; data->currentMV[0].y = y;
407                    *dir = Direction; }
408    
409          if (!(MotionFlags & PMV_HALFPEL16)) {          if (data->temp[1] < data->iMinSAD[1]) {
410                  min_dx = EVEN(min_dx);                  data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
411                  max_dx = EVEN(max_dx);          if (data->temp[2] < data->iMinSAD[2]) {
412                  min_dy = EVEN(min_dy);                  data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
413                  max_dy = EVEN(max_dy);          if (data->temp[3] < data->iMinSAD[3]) {
414                    data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
415            if (data->temp[4] < data->iMinSAD[4]) {
416                    data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
417          }          }
418    
419          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  static void
420          //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  CheckCandidate16no4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
421          bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);  {
422            int32_t sad, xc, yc;
423            const uint8_t * Reference;
424            uint32_t t;
425            VECTOR * current;
426    
427          if ((x == 0) && (y == 0)) {          if ( (x > data->max_dx) || ( x < data->min_dx)
428                  threshA = 512;                  || (y > data->max_dy) || (y < data->min_dy) ) return;
429                  threshB = 1024;  
430            if (data->rrv && (!(x&1) && x !=0) | (!(y&1) && y !=0) ) return; /* non-zero even value */
431    
432            if (data->qpel_precision) { /* x and y are in 1/4 precision */
433                    Reference = Interpolate16x16qpel(x, y, 0, data);
434                    current = data->currentQMV;
435                    xc = x/2; yc = y/2;
436          } else {          } else {
437                  threshA = psad[0];                  Reference = GetReference(x, y, data);
438                  threshB = threshA + 256;                  current = data->currentMV;
439                  if (threshA < 512)                  xc = x; yc = y;
                         threshA = 512;  
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
440          }          }
441            t = d_mv_bits(x, y, data->predMV, data->iFcode,
442                                            data->qpel^data->qpel_precision, data->rrv);
443    
444          iFound = 0;          sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
445            sad += (data->lambda16 * t * sad)>>10;
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
   
         currMV->x = start_x;  
         currMV->y = start_y;  
446    
447          if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */          if (data->chroma) sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
448                  currMV->x = EVEN(currMV->x);                                                                                  (yc >> 1) + roundtab_79[yc & 0x3], data);
                 currMV->y = EVEN(currMV->y);  
         }  
449    
450          if (currMV->x > max_dx) {          if (sad < *(data->iMinSAD)) {
451                  currMV->x = max_dx;                  *(data->iMinSAD) = sad;
452          }                  current->x = x; current->y = y;
453          if (currMV->x < min_dx) {                  *dir = Direction;
                 currMV->x = min_dx;  
         }  
         if (currMV->y > max_dy) {  
                 currMV->y = max_dy;  
454          }          }
         if (currMV->y < min_dy) {  
                 currMV->y = min_dy;  
455          }          }
456    
457          iMinSAD =  static void
458                  sad16(cur,  CheckCandidate32I(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                           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);  
   
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
459                  {                  {
460                          if (!MVzero(*currMV)) {          /* maximum speed - for P/B/I decision */
461                                  iMinSAD += MV16_00_BIAS;          int32_t sad;
                                 CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures  
                                 iMinSAD -= MV16_00_BIAS;  
                         }  
                 }  
462    
463                  if (MotionFlags & PMV_QUICKSTOP16)          if ( (x > data->max_dx) || (x < data->min_dx)
464                          goto PMVfast16_Terminate_without_Refine;                  || (y > data->max_dy) || (y < data->min_dy) ) return;
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
         }  
465    
466            sad = sad32v_c(data->Cur, data->RefP[0] + (x>>1) + (y>>1)*(data->iEdgedWidth),
467                                            data->iEdgedWidth, data->temp+1);
468    
469  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion          if (sad < *(data->iMinSAD)) {
470     vector of the median.                  *(data->iMinSAD) = sad;
471     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2                  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          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[0])))  }
                 iFound = 2;  
484    
485  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.  static void
486     Otherwise select large Diamond Search.  CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)
487  */  {
488            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 ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))          if ((xf > data->max_dx) || (xf < data->min_dx) ||
494                  iDiamondSize = 1;               // halfpel!                  (yf > data->max_dy) || (yf < data->min_dy))
495          else                  return;
                 iDiamondSize = 2;               // halfpel!  
496    
497          if (!(MotionFlags & PMV_HALFPELDIAMOND16))          if (!data->qpel_precision) {
498                  iDiamondSize *= 2;                  ReferenceF = GetReference(xf, yf, data);
499                    xb = data->currentMV[1].x; yb = data->currentMV[1].y;
500                    ReferenceB = GetReferenceB(xb, yb, 1, data);
501                    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     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.                   + d_mv_bits(xb, yb, data->bpredMV, data->iFcode, data->qpel^data->qpel_precision, 0);
    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.  
 */  
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.  
 */  
   
         if (MotionFlags & PMV_USESQUARES16)  
                 MainSearchPtr = Square16_MainSearch;  
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
600    
601          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          mvs.x = data->directmvF[0].x + x;
602            b_mvs.x = ((x == 0) ?
603                    data->directmvB[0].x
604                    : mvs.x - data->referencemv[0].x);
605    
606            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  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          if ( (mvs.x > data->max_dx) || (mvs.x < data->min_dx)
612          iSAD =                  || (mvs.y > data->max_dy) || (mvs.y < data->min_dy)
613                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                  || (b_mvs.x > data->max_dx) || (b_mvs.x < data->min_dx)
614                                                    currMV->x, currMV->y, iMinSAD, &newMV, center_x, center_y,                  || (b_mvs.y > data->max_dy) || (b_mvs.y < data->min_dy) ) return;
                                                   min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
615    
616          if (iSAD < iMinSAD) {          if (data->qpel) {
617                  *currMV = newMV;                  xcf = 4*(mvs.x/2); ycf = 4*(mvs.y/2);
618                  iMinSAD = iSAD;                  xcb = 4*(b_mvs.x/2); ycb = 4*(b_mvs.y/2);
619                    ReferenceF = Interpolate16x16qpel(mvs.x, mvs.y, 0, data);
620                    ReferenceB = Interpolate16x16qpel(b_mvs.x, b_mvs.y, 1, data);
621            } else {
622                    xcf = 4*mvs.x; ycf = 4*mvs.y;
623                    xcb = 4*b_mvs.x; ycb = 4*b_mvs.y;
624                    ReferenceF = GetReference(mvs.x, mvs.y, data);
625                    ReferenceB = GetReferenceB(b_mvs.x, b_mvs.y, 1, data);
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->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:          bits += BITS_MULT*xvid_cbpy_tab[15-(cbp>>2)].len;
         if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step  
                 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);  
676    
677    PMVfast16_Terminate_without_Refine:          if (bits >= data->iMinSAD[0]) return;
         currPMV->x = currMV->x - center_x;  
         currPMV->y = currMV->y - center_y;  
         return iMinSAD;  
 }  
678    
679            /* chroma */
680            xc = (xc >> 1) + roundtab_79[xc & 0x3];
681            yc = (yc >> 1) + roundtab_79[yc & 0x3];
682    
683            /* chroma U */
684            ptr = interpolate8x8_switch2(data->RefQ + 64, data->RefP[4], 0, 0, xc, yc,  data->iEdgedWidth/2, data->rounding);
685            transfer_8to16subro(in, ptr, data->CurU, data->iEdgedWidth/2);
686            bits += Block_CalcBits(coeff, in, data->iQuant, data->quant_type, &cbp, 4);
687            if (bits >= data->iMinSAD[0]) return;
688    
689            /* chroma V */
690            ptr = interpolate8x8_switch2(data->RefQ + 64, data->RefP[5], 0, 0, xc, yc,  data->iEdgedWidth/2, data->rounding);
691            transfer_8to16subro(in, ptr, data->CurV, data->iEdgedWidth/2);
692            bits += Block_CalcBits(coeff, in, data->iQuant, data->quant_type, &cbp, 5);
693    
694            bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTER & 7) | ((cbp & 3) << 3)].len;
695    
696            if (bits < data->iMinSAD[0]) {
697                    data->iMinSAD[0] = bits;
698                    current[0].x = x; current[0].y = y;
699                    *dir = Direction;
700            }
701    
702  int32_t          if (data->temp[0] + t < data->iMinSAD[1]) {
703  Diamond8_MainSearch(const uint8_t * const pRef,                  data->iMinSAD[1] = data->temp[0] + t; current[1].x = x; current[1].y = y; }
704                                          const uint8_t * const pRefH,          if (data->temp[1] < data->iMinSAD[2]) {
705                                          const uint8_t * const pRefV,                  data->iMinSAD[2] = data->temp[1]; current[2].x = x; current[2].y = y; }
706                                          const uint8_t * const pRefHV,          if (data->temp[2] < data->iMinSAD[3]) {
707                                          const uint8_t * const cur,                  data->iMinSAD[3] = data->temp[2]; current[3].x = x; current[3].y = y; }
708                                          const int x,          if (data->temp[3] < data->iMinSAD[4]) {
709                                          const int y,                  data->iMinSAD[4] = data->temp[3]; current[4].x = x; current[4].y = 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 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);  
710    
         if (iDirection) {  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;     // since iDirection!=0, this is well defined!  
                         iDirectionBackup = iDirection;  
   
                         if (iDirectionBackup != 2)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                   backupMV.y, 1);  
                         if (iDirectionBackup != 1)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                   backupMV.y, 2);  
                         if (iDirectionBackup != 4)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y - iDiamondSize, 3);  
                         if (iDirectionBackup != 3)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y + iDiamondSize, 4);  
711                  }                  }
712          } else {  static void
713                  currMV->x = start_x;  CheckCandidateBits8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
714                  currMV->y = start_y;  {
715    
716            int16_t *in = data->dctSpace, *coeff = data->dctSpace + 64;
717            int32_t bits;
718            VECTOR * current;
719            const uint8_t * ptr;
720            int cbp = 0;
721    
722            if ( (x > data->max_dx) || (x < data->min_dx)
723                    || (y > data->max_dy) || (y < data->min_dy) ) return;
724    
725            if (!data->qpel_precision) {
726                    ptr = GetReference(x, y, data);
727                    current = data->currentMV;
728            } else { /* x and y are in 1/4 precision */
729                    ptr = Interpolate8x8qpel(x, y, 0, 0, data);
730                    current = data->currentQMV;
731            }
732    
733            transfer_8to16subro(in, data->Cur, ptr, data->iEdgedWidth);
734            bits = Block_CalcBits(coeff, in, 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 VopFlags,
953                            const uint32_t VolFlags,
954                            const IMAGE * const pCurrent,
955                            const IMAGE * const pRef)
956    {
957            int mode = MODE_INTER;
958            int inter4v = (VopFlags & XVID_VOP_INTER4V) && (pMB->dquant == 0);
959            const uint32_t iQuant = pMB->quant;
960    
961            const int skip_possible = (!(VolFlags & XVID_VOL_GMC)) && (pMB->dquant == 0);
962    
963            if (!(VopFlags & XVID_VOP_MODEDECISION_BITS)) { /* normal, fast, SAD-based mode decision */
964                    int sad;
965                    int InterBias = MV16_INTER_BIAS;
966                    if (inter4v == 0 || Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
967                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant) {
968                            mode = MODE_INTER;
969                            sad = Data->iMinSAD[0];
970          } else {          } else {
971                  threshA = psad[0] / 4;  /* good estimate? */                          mode = MODE_INTER4V;
972                  threshB = threshA + 256 / 4;                          sad = Data->iMinSAD[1] + Data->iMinSAD[2] +
973                  if (threshA < 512 / 4)                                                  Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant;
974                          threshA = 512 / 4;                          Data->iMinSAD[0] = sad;
975                  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.  
 */  
976    
977                    /* final skip decision, a.k.a. "the vector you found, really that good?" */
978                    if (skip_possible && (pMB->sad16 < (int)iQuant * MAX_SAD00_FOR_SKIP))
979                            if ( (100*sad)/(pMB->sad16+1) > FINAL_SKIP_THRESH)
980                                    if (Data->chroma || SkipDecisionP(pCurrent, pRef, x, y, Data->iEdgedWidth/2, iQuant, Data->rrv)) {
981                                            mode = MODE_NOT_CODED;
982                                            sad = 0;
983                                    }
984    
985  // Prepare for main loop                  /* intra decision */
986    
987    if (MotionFlags & PMV_USESQUARES8)                  if (iQuant > 8) InterBias += 100 * (iQuant - 8); /* to make high quants work */
988        MainSearchPtr = Square8_MainSearch;                  if (y != 0)
989    else                          if ((pMB - pParam->mb_width)->mode == MODE_INTRA ) InterBias -= 80;
990                    if (x != 0)
991                            if ((pMB - 1)->mode == MODE_INTRA ) InterBias -= 80;
992    
993          if (MotionFlags & PMV_ADVANCEDDIAMOND8)                  if (Data->chroma) InterBias += 50; /* dev8(chroma) ??? */
994                  MainSearchPtr = AdvDiamond8_MainSearch;                  if (Data->rrv) InterBias *= 4;
         else  
                 MainSearchPtr = Diamond8_MainSearch;  
995    
996                    if (InterBias < pMB->sad16) {
997                            int32_t deviation;
998                            if (!Data->rrv) deviation = dev16(Data->Cur, Data->iEdgedWidth);
999                            else deviation = dev16(Data->Cur, Data->iEdgedWidth) +
1000                                    dev16(Data->Cur+16, Data->iEdgedWidth) +
1001                                    dev16(Data->Cur + 16*Data->iEdgedWidth, Data->iEdgedWidth) +
1002                                    dev16(Data->Cur+16+16*Data->iEdgedWidth, Data->iEdgedWidth);
1003    
1004          *currMV = startMV;                          if (deviation < (sad - InterBias)) mode = MODE_INTRA;
1005                    }
1006    
1007          iMinSAD =          } else { /* BITS */
                 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  
 */  
1008    
1009          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[iSubBlock])))                  int bits, intra, i;
1010                  iFound = 2;                  VECTOR backup[5], *v;
1011                    Data->iQuant = iQuant;
1012    
1013  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.                  v = Data->qpel ? Data->currentQMV : Data->currentMV;
1014     Otherwise select large Diamond Search.                  for (i = 0; i < 5; i++) {
1015  */                          Data->iMinSAD[i] = 256*4096;
1016                            backup[i] = v[i];
1017                    }
1018    
1019          if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))                  bits = CountMBBitsInter(Data, pMBs, x, y, pParam, MotionFlags);
1020                  iDiamondSize = 1;               // 1 halfpel!                  if (bits == 0)
1021          else                          mode = MODE_INTER; /* quick stop */
1022                  iDiamondSize = 2;               // 2 halfpel = 1 full pixel!                  else {
1023                            if (inter4v) {
1024                                    int bits_inter4v = CountMBBitsInter4v(Data, pMB, pMBs, x, y, pParam, MotionFlags, backup);
1025                                    if (bits_inter4v < bits) { Data->iMinSAD[0] = bits = bits_inter4v; mode = MODE_INTER4V; }
1026                            }
1027    
1028          if (!(MotionFlags & PMV_HALFPELDIAMOND8))                          intra = CountMBBitsIntra(Data);
                 iDiamondSize *= 2;  
1029    
1030                            if (intra < bits) { *Data->iMinSAD = bits = intra; mode = MODE_INTRA; }
1031                    }
1032            }
1033    
1034  /*          if (Data->rrv) {
1035     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.                          Data->currentMV[0].x = RRV_MV_SCALEDOWN(Data->currentMV[0].x);
1036     Also calculate (0,0) but do not subtract offset.                          Data->currentMV[0].y = RRV_MV_SCALEDOWN(Data->currentMV[0].y);
1037     Let MinSAD be the smallest SAD up to this point.          }
    If MV is (0,0) subtract offset.  
 */  
1038    
1039  // the median prediction might be even better than mv16          if (mode == MODE_INTER) {
1040                    pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
1041                    pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = Data->iMinSAD[0];
1042    
1043          if (!MVequal(pmv[0], startMV))                  if(Data->qpel) {
1044                  CHECK_MV8_CANDIDATE(center_x, center_y);                          pMB->qmvs[0] = pMB->qmvs[1]
1045                                    = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1046                            pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1047                            pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;
1048                    } else {
1049                            pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1050                            pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
1051                    }
1052    
1053  // (0,0) if needed          } else if (mode == MODE_INTER4V)
1054          if (!MVzero(pmv[0]))                  pMB->sad16 = Data->iMinSAD[0];
1055                  if (!MVzero(startMV))          else /* INTRA, NOT_CODED */
1056                          CHECK_MV8_ZERO;                  SkipMacroblockP(pMB, 0);
   
 // previous frame MV if needed  
         if (!MVzero(prevMB->mvs[iSubBlock]))  
                 if (!MVequal(prevMB->mvs[iSubBlock], startMV))  
                         if (!MVequal(prevMB->mvs[iSubBlock], pmv[0]))  
                                 CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x,  
                                                                         prevMB->mvs[iSubBlock].y);  
   
         if ((iMinSAD <= threshA) ||  
                 (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&  
                  ((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;  
1057    
1058            pMB->mode = mode;
1059    }
1060    
1061  /* Step 6: If MinSAD <= thresa goto Step 10.  bool
1062     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  MotionEstimation(MBParam * const pParam,
1063  */                                   FRAMEINFO * const current,
1064                                     FRAMEINFO * const reference,
1065                                     const IMAGE * const pRefH,
1066                                     const IMAGE * const pRefV,
1067                                     const IMAGE * const pRefHV,
1068                                     const uint32_t iLimit)
1069    {
1070            MACROBLOCK *const pMBs = current->mbs;
1071            const IMAGE *const pCurrent = &current->image;
1072            const IMAGE *const pRef = &reference->image;
1073    
1074          if ((iMinSAD <= threshA) ||          uint32_t mb_width = pParam->mb_width;
1075                  (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&          uint32_t mb_height = pParam->mb_height;
1076                   ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {          const uint32_t iEdgedWidth = pParam->edged_width;
1077                  if (MotionFlags & PMV_QUICKSTOP16)          const uint32_t MotionFlags = MakeGoodMotionFlags(current->motion_flags, current->vop_flags, current->vol_flags);
1078                          goto PMVfast8_Terminate_without_Refine;  
1079                  if (MotionFlags & PMV_EARLYSTOP16)          uint32_t x, y;
1080                          goto PMVfast8_Terminate_with_Refine;          uint32_t iIntra = 0;
1081            int32_t quant = current->quant, sad00;
1082            int skip_thresh = \
1083                    INITIAL_SKIP_THRESH * \
1084                    (current->vop_flags & XVID_VOP_REDUCED ? 4:1) * \
1085                    (current->vop_flags & XVID_VOP_MODEDECISION_BITS ? 2:1);
1086    
1087            /* some pre-initialized thingies for SearchP */
1088            int32_t temp[8];
1089            VECTOR currentMV[5];
1090            VECTOR currentQMV[5];
1091            int32_t iMinSAD[5];
1092            DECLARE_ALIGNED_MATRIX(dct_space, 2, 64, int16_t, CACHE_LINE);
1093            SearchData Data;
1094            memset(&Data, 0, sizeof(SearchData));
1095            Data.iEdgedWidth = iEdgedWidth;
1096            Data.currentMV = currentMV;
1097            Data.currentQMV = currentQMV;
1098            Data.iMinSAD = iMinSAD;
1099            Data.temp = temp;
1100            Data.iFcode = current->fcode;
1101            Data.rounding = pParam->m_rounding_type;
1102            Data.qpel = (current->vol_flags & XVID_VOL_QUARTERPEL ? 1:0);
1103            Data.chroma = MotionFlags & XVID_ME_CHROMA16;
1104            Data.rrv = (current->vop_flags & XVID_VOP_REDUCED ? 1:0);
1105            Data.dctSpace = dct_space;
1106            Data.quant_type = !(pParam->vol_flags & XVID_VOL_MPEGQUANT);
1107    
1108            if ((current->vop_flags & XVID_VOP_REDUCED)) {
1109                    mb_width = (pParam->width + 31) / 32;
1110                    mb_height = (pParam->height + 31) / 32;
1111                    Data.qpel = 0;
1112            }
1113    
1114            Data.RefQ = pRefV->u; /* a good place, also used in MC (for similar purpose) */
1115            if (sadInit) (*sadInit) ();
1116    
1117            for (y = 0; y < mb_height; y++) {
1118                    for (x = 0; x < mb_width; x++)  {
1119                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1120    
1121                            if (!Data.rrv) pMB->sad16 =
1122                                    sad16v(pCurrent->y + (x + y * iEdgedWidth) * 16,
1123                                                            pRef->y + (x + y * iEdgedWidth) * 16,
1124                                                            pParam->edged_width, pMB->sad8 );
1125    
1126                            else pMB->sad16 =
1127                                    sad32v_c(pCurrent->y + (x + y * iEdgedWidth) * 32,
1128                                                            pRef->y + (x + y * iEdgedWidth) * 32,
1129                                                            pParam->edged_width, pMB->sad8 );
1130    
1131                            if (Data.chroma) {
1132                                    Data.temp[7] = sad8(pCurrent->u + x*8 + y*(iEdgedWidth/2)*8,
1133                                                                            pRef->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2)
1134                                                                    + sad8(pCurrent->v + (x + y*(iEdgedWidth/2))*8,
1135                                                                            pRef->v + (x + y*(iEdgedWidth/2))*8, iEdgedWidth/2);
1136                                    pMB->sad16 += Data.temp[7];
1137                            }
1138    
1139                            sad00 = pMB->sad16;
1140    
1141                            if (pMB->dquant != 0) {
1142                                    quant += DQtab[pMB->dquant];
1143                                    if (quant > 31) quant = 31;
1144                                    else if (quant < 1) quant = 1;
1145                            }
1146                            pMB->quant = quant;
1147    
1148                            /* initial skip decision */
1149                            /* no early skip for GMC (global vector = skip vector is unknown!)  */
1150                            if (!(current->vol_flags & XVID_VOL_GMC))       { /* no fast SKIP for S(GMC)-VOPs */
1151                                    if (pMB->dquant == 0 && sad00 < pMB->quant * skip_thresh)
1152                                            if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, iEdgedWidth/2, pMB->quant, Data.rrv)) {
1153                                                    SkipMacroblockP(pMB, sad00);
1154                                                    continue;
1155                                            }
1156          }          }
1157    
1158  /************ (Diamond Search)  **************/                          SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1159  /*                                          y, MotionFlags, current->vop_flags, current->vol_flags,
1160     Step 7: Perform Diamond search, with either the small or large diamond.                                          &Data, pParam, pMBs, reference->mbs, pMB);
    If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
    Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
    If center then goto step 10.  
    Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
    Refine by using small diamond and goto step 10.  
 */  
   
         backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  
1161    
1162  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                          ModeDecision(&Data, pMB, pMBs, x, y, pParam,
1163          iSAD =                                                   MotionFlags, current->vop_flags, current->vol_flags,
1164                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,                                                   pCurrent, pRef);
                                                   currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
1165    
1166          if (iSAD < iMinSAD) {                          if (pMB->mode == MODE_INTRA)
1167                  *currMV = newMV;                                  if (++iIntra > iLimit) return 1;
1168                  iMinSAD = iSAD;                  }
1169          }          }
1170    
1171          if (MotionFlags & PMV_EXTSEARCH8) {          if (current->vol_flags & XVID_VOL_GMC ) /* GMC only for S(GMC)-VOPs */
1172  /* extended: search (up to) two more times: orignal prediction and (0,0) */          {
1173                    current->warp = GlobalMotionEst( pMBs, pParam, current, reference, pRefH, pRefV, pRefHV);
                 if (!(MVequal(pmv[0], backupMV))) {  
                         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, iFound);  
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
1174                          }                          }
1175            return 0;
1176                  }                  }
1177    
                 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);  
1178    
1179                          if (iSAD < iMinSAD) {  static __inline int
1180                                  *currMV = newMV;  make_mask(const VECTOR * const pmv, const int i)
1181                                  iMinSAD = iSAD;  {
1182            int mask = 255, j;
1183            for (j = 0; j < i; j++) {
1184                    if (MVequal(pmv[i], pmv[j])) return 0; /* same vector has been checked already */
1185                    if (pmv[i].x == pmv[j].x) {
1186                            if (pmv[i].y == pmv[j].y + iDiamondSize) mask &= ~4;
1187                            else if (pmv[i].y == pmv[j].y - iDiamondSize) mask &= ~8;
1188                    } else
1189                            if (pmv[i].y == pmv[j].y) {
1190                                    if (pmv[i].x == pmv[j].x + iDiamondSize) mask &= ~1;
1191                                    else if (pmv[i].x == pmv[j].x - iDiamondSize) mask &= ~2;
1192                          }                          }
1193                  }                  }
1194            return mask;
1195          }          }
1196    
1197  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.  static __inline void
1198     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,
1199  */                          int iHcount, const MACROBLOCK * const prevMB, int rrv)
1200    {
1201            /* this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself */
1202            if (rrv) { iWcount /= 2; iHcount /= 2; }
1203    
1204            if ( (y != 0) && (x < (iWcount-1)) ) {          /* [5] top-right neighbour */
1205                    pmv[5].x = EVEN(pmv[3].x);
1206                    pmv[5].y = EVEN(pmv[3].y);
1207            } else pmv[5].x = pmv[5].y = 0;
1208    
1209    PMVfast8_Terminate_with_Refine:          if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }/* pmv[3] is left neighbour */
1210          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step          else pmv[3].x = pmv[3].y = 0;
                 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);  
1211    
1212            if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }/* [4] top neighbour */
1213            else pmv[4].x = pmv[4].y = 0;
1214    
1215    PMVfast8_Terminate_without_Refine:          /* [1] median prediction */
1216          currPMV->x = currMV->x - center_x;          pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
         currPMV->y = currMV->y - center_y;  
1217    
1218          return iMinSAD;          pmv[0].x = pmv[0].y = 0; /* [0] is zero; not used in the loop (checked before) but needed here for make_mask */
1219    
1220            pmv[2].x = EVEN(prevMB->mvs[0].x); /* [2] is last frame */
1221            pmv[2].y = EVEN(prevMB->mvs[0].y);
1222    
1223            if ((x < iWcount-1) && (y < iHcount-1)) {
1224                    pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); /* [6] right-down neighbour in last frame */
1225                    pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
1226            } else pmv[6].x = pmv[6].y = 0;
1227    
1228            if (rrv) {
1229                    int i;
1230                    for (i = 0; i < 7; i++) {
1231                            pmv[i].x = RRV_MV_SCALEUP(pmv[i].x);
1232                            pmv[i].y = RRV_MV_SCALEUP(pmv[i].y);
1233                    }
1234            }
1235  }  }
1236    
1237  int32_t  static void
1238  EPZSSearch16(const uint8_t * const pRef,  SearchP(const IMAGE * const pRef,
1239                           const uint8_t * const pRefH,                           const uint8_t * const pRefH,
1240                           const uint8_t * const pRefV,                           const uint8_t * const pRefV,
1241                           const uint8_t * const pRefHV,                           const uint8_t * const pRefHV,
1242                           const IMAGE * const pCur,                           const IMAGE * const pCur,
1243                           const int x,                           const int x,
1244                           const int y,                           const int y,
                         const int start_x,  
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
1245                           const uint32_t MotionFlags,                           const uint32_t MotionFlags,
1246                           const uint32_t iQuant,                  const uint32_t VopFlags,
1247                           const uint32_t iFcode,                  const uint32_t VolFlags,
1248                    SearchData * const Data,
1249                           const MBParam * const pParam,                           const MBParam * const pParam,
1250                           const MACROBLOCK * const pMBs,                           const MACROBLOCK * const pMBs,
1251                           const MACROBLOCK * const prevMBs,                           const MACROBLOCK * const prevMBs,
1252                           VECTOR * const currMV,                  MACROBLOCK * const pMB)
                          VECTOR * const currPMV)  
1253  {  {
         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;  
1254    
1255          int32_t min_dx;          int i, iDirection = 255, mask, threshA;
1256          int32_t max_dx;          VECTOR pmv[7];
1257          int32_t min_dy;          int inter4v = (VopFlags & XVID_VOP_INTER4V) && (pMB->dquant == 0);
1258          int32_t max_dy;  
1259            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1260          VECTOR newMV;                                                  pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
1261          VECTOR backupMV;  
1262            get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);
1263    
1264            Data->temp[5] = Data->temp[6] = 0; /* chroma-sad cache */
1265            i = Data->rrv ? 2 : 1;
1266            Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16*i;
1267            Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1268            Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1269    
1270            Data->RefP[0] = pRef->y + (x + Data->iEdgedWidth*y) * 16*i;
1271            Data->RefP[2] = pRefH + (x + Data->iEdgedWidth*y) * 16*i;
1272            Data->RefP[1] = pRefV + (x + Data->iEdgedWidth*y) * 16*i;
1273            Data->RefP[3] = pRefHV + (x + Data->iEdgedWidth*y) * 16*i;
1274            Data->RefP[4] = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1275            Data->RefP[5] = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1276    
1277            Data->lambda16 = lambda_vec16[pMB->quant];
1278            Data->lambda8 = lambda_vec8[pMB->quant];
1279            Data->qpel_precision = 0;
1280    
1281            memset(Data->currentMV, 0, 5*sizeof(VECTOR));
1282    
1283            if (Data->qpel) Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1284            else Data->predMV = pmv[0];
1285    
1286            i = d_mv_bits(0, 0, Data->predMV, Data->iFcode, 0, 0);
1287            Data->iMinSAD[0] = pMB->sad16 + ((Data->lambda16 * i * pMB->sad16)>>10);
1288            Data->iMinSAD[1] = pMB->sad8[0] + ((Data->lambda8 * i * (pMB->sad8[0]+NEIGH_8X8_BIAS)) >> 10);
1289            Data->iMinSAD[2] = pMB->sad8[1];
1290            Data->iMinSAD[3] = pMB->sad8[2];
1291            Data->iMinSAD[4] = pMB->sad8[3];
1292    
1293            if ((!(VopFlags & XVID_VOP_MODEDECISION_BITS)) || (x | y)) {
1294                    threshA = Data->temp[0]; /* that's where we keep this SAD atm */
1295                    if (threshA < 512) threshA = 512;
1296                    else if (threshA > 1024) threshA = 1024;
1297            } else
1298                    threshA = 512;
1299    
1300          VECTOR pmv[4];          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
1301          int32_t psad[8];                                          prevMBs + x + y * pParam->mb_width, Data->rrv);
1302    
1303          static MACROBLOCK *oldMBs = NULL;          if (!Data->rrv) {
1304                    if (inter4v | Data->chroma) CheckCandidate = CheckCandidate16;
1305                            else CheckCandidate = CheckCandidate16no4v; /* for extra speed */
1306            } else CheckCandidate = CheckCandidate32;
1307    
1308    /* main loop. checking all predictions (but first, which is 0,0 and has been checked in MotionEstimation())*/
1309    
1310            for (i = 1; i < 7; i++) {
1311                    if (!(mask = make_mask(pmv, i)) ) continue;
1312                    CheckCandidate(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1313                    if (Data->iMinSAD[0] <= threshA) break;
1314            }
1315    
1316            if ((Data->iMinSAD[0] <= threshA) ||
1317                            (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
1318                            (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16)))
1319                    inter4v = 0;
1320            else {
1321    
1322  //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;                  MainSearchFunc * MainSearchPtr;
1323          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;                  if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1324          MACROBLOCK *oldMB = NULL;                  else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1325                            else MainSearchPtr = DiamondSearch;
1326    
1327           int32_t thresh2;                  MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD = 9999;  
1328    
1329          MainSearch16FuncPtr MainSearchPtr;  /* extended search, diamond starting in 0,0 and in prediction.
1330            note that this search is/might be done in halfpel positions,
1331            which makes it more different than the diamond above */
1332    
1333          if (oldMBs == NULL) {                  if (MotionFlags & XVID_ME_EXTSEARCH16) {
1334                  oldMBs = (MACROBLOCK *) calloc(iWcount * iHcount, sizeof(MACROBLOCK));                          int32_t bSAD;
1335  //      fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));                          VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
1336                            if (Data->rrv) {
1337                                    startMV.x = RRV_MV_SCALEUP(startMV.x);
1338                                    startMV.y = RRV_MV_SCALEUP(startMV.y);
1339          }          }
1340          oldMB = oldMBs + x + y * iWcount;                          if (!(MVequal(startMV, backupMV))) {
1341                                    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);  
1342    
1343          if (!(MotionFlags & PMV_HALFPEL16)) {                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1344                  min_dx = EVEN(min_dx);                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1345                  max_dx = EVEN(max_dx);                                  if (bSAD < Data->iMinSAD[0]) {
1346                  min_dy = EVEN(min_dy);                                          Data->currentMV[0] = backupMV;
1347                  max_dy = EVEN(max_dy);                                          Data->iMinSAD[0] = bSAD; }
1348          }          }
         /* 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);  
1349    
1350  /* Step 4: Calculate SAD around the Median prediction.                          backupMV = Data->currentMV[0];
1351          MinSAD=SAD                          startMV.x = startMV.y = 1;
1352          If Motion Vector equal to Previous frame motion vector                          if (!(MVequal(startMV, backupMV))) {
1353                  and MinSAD<PrevFrmSAD goto Step 10.                                  bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
         If SAD<=256 goto Step 10.  
 */  
   
 // Prepare for main loop  
   
         currMV->x = start_x;  
         currMV->y = start_y;  
   
         if (!(MotionFlags & PMV_HALFPEL16)) {  
                 currMV->x = EVEN(currMV->x);  
                 currMV->y = EVEN(currMV->y);  
         }  
   
         if (currMV->x > max_dx)  
                 currMV->x = max_dx;  
         if (currMV->x < min_dx)  
                 currMV->x = min_dx;  
         if (currMV->y > max_dy)  
                 currMV->y = max_dy;  
         if (currMV->y < min_dy)  
                 currMV->y = min_dy;  
   
 /***************** 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 **************/  
1354    
1355  // previous frame MV                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1356          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);                                  MainSearchPtr(startMV.x, startMV.y, Data, 255);
1357                                    if (bSAD < Data->iMinSAD[0]) {
1358                                            Data->currentMV[0] = backupMV;
1359                                            Data->iMinSAD[0] = bSAD; }
1360                            }
1361                    }
1362            }
1363    
1364  // set threshhold based on Min of Prediction and SAD of collocated block          if (MotionFlags & XVID_ME_HALFPELREFINE16)
1365  // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want                          SubpelRefine(Data);
1366    
1367          if ((x == 0) && (y == 0)) {          for(i = 0; i < 5; i++) {
1368                  thresh2 = 512;                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; /* initialize qpel vectors */
1369          } else {                  Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
1370  /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */          }
1371    
1372                  thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;          if (Data->qpel) {
1373                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1374                                    pParam->width, pParam->height, Data->iFcode, 1, 0);
1375                    Data->qpel_precision = 1;
1376                    if (MotionFlags & XVID_ME_QUARTERPELREFINE16)
1377                            SubpelRefine(Data);
1378          }          }
1379    
1380  // MV=(0,0) is often a good choice          if (Data->iMinSAD[0] < (int32_t)pMB->quant * 30)
1381                    inter4v = 0;
1382    
1383          CHECK_MV16_ZERO;          if (inter4v) {
1384                    SearchData Data8;
1385                    memcpy(&Data8, Data, sizeof(SearchData)); /* quick copy of common data */
1386    
1387                    Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
1388                    Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
1389                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
1390                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
1391    
1392  // left neighbour, if allowed                  if ((Data->chroma) && (!(VopFlags & XVID_VOP_MODEDECISION_BITS))) {
1393          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 */
1394                  if (!(MotionFlags & PMV_HALFPEL16)) {                          int sumx = 0, sumy = 0;
1395                          pmv[1].x = EVEN(pmv[1].x);  
1396                          pmv[1].y = EVEN(pmv[1].y);                          if (Data->qpel)
1397                  }                                  for (i = 1; i < 5; i++) {
1398                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);                                          sumx += Data->currentQMV[i].x/2;
1399                                            sumy += Data->currentQMV[i].y/2;
1400          }          }
1401  // top neighbour, if allowed                          else
1402          if (y != 0) {                                  for (i = 1; i < 5; i++) {
1403                  if (!(MotionFlags & PMV_HALFPEL16)) {                                          sumx += Data->currentMV[i].x;
1404                          pmv[2].x = EVEN(pmv[2].x);                                          sumy += Data->currentMV[i].y;
                         pmv[2].y = EVEN(pmv[2].y);  
1405                  }                  }
                 CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
1406    
1407  // top right neighbour, if allowed                          Data->iMinSAD[1] += ChromaSAD(  (sumx >> 3) + roundtab_76[sumx & 0xf],
1408                  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);  
1409                          }                          }
1410                          CHECK_MV16_CANDIDATE(pmv[3].x, pmv[3].y);          } else Data->iMinSAD[1] = 4096*256;
1411                  }                  }
1412    
1413    static void
1414    Search8(const SearchData * const OldData,
1415                    const int x, const int y,
1416                    const uint32_t MotionFlags,
1417                    const MBParam * const pParam,
1418                    MACROBLOCK * const pMB,
1419                    const MACROBLOCK * const pMBs,
1420                    const int block,
1421                    SearchData * const Data)
1422    {
1423            int i = 0;
1424            Data->iMinSAD = OldData->iMinSAD + 1 + block;
1425            Data->currentMV = OldData->currentMV + 1 + block;
1426            Data->currentQMV = OldData->currentQMV + 1 + block;
1427    
1428            if(Data->qpel) {
1429                    Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1430                    if (block != 0) i = d_mv_bits(  Data->currentQMV->x, Data->currentQMV->y,
1431                                                                                    Data->predMV, Data->iFcode, 0, 0);
1432            } else {
1433                    Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1434                    if (block != 0) i = d_mv_bits(  Data->currentMV->x, Data->currentMV->y,
1435                                                                                    Data->predMV, Data->iFcode, 0, Data->rrv);
1436          }          }
1437    
1438  /* Terminate if MinSAD <= T_2          *(Data->iMinSAD) += (Data->lambda8 * i * (*Data->iMinSAD + NEIGH_8X8_BIAS))>>10;
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
1439    
1440          if ((iMinSAD <= thresh2)          if (MotionFlags & (XVID_ME_EXTSEARCH8|XVID_ME_HALFPELREFINE8|XVID_ME_QUARTERPELREFINE8)) {
                 || (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;  
         }  
1441    
1442  /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/                  if (Data->rrv) i = 16; else i = 8;
1443    
1444          backupMV = prevMB->mvs[0];      // collocated MV                  Data->RefP[0] = OldData->RefP[0] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1445          backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x);     // acceleration X                  Data->RefP[1] = OldData->RefP[1] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1446          backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y);     // acceleration Y                  Data->RefP[2] = OldData->RefP[2] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1447                    Data->RefP[3] = OldData->RefP[3] + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1448    
1449          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y);                  Data->Cur = OldData->Cur + i * ((block&1) + Data->iEdgedWidth*(block>>1));
1450                    Data->qpel_precision = 0;
1451    
1452  // left neighbour                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1453          if (x != 0)                                          pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
                 CHECK_MV16_CANDIDATE((prevMB - 1)->mvs[0].x, (prevMB - 1)->mvs[0].y);  
1454    
1455  // top neighbour                  if (!Data->rrv) CheckCandidate = CheckCandidate8;
1456          if (y != 0)                  else CheckCandidate = CheckCandidate16no4v;
                 CHECK_MV16_CANDIDATE((prevMB - iWcount)->mvs[0].x,  
                                                          (prevMB - iWcount)->mvs[0].y);  
1457    
1458  // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs                  if (MotionFlags & XVID_ME_EXTSEARCH8 && (!(MotionFlags & XVID_ME_EXTSEARCH_BITS))) {
1459                            int32_t temp_sad = *(Data->iMinSAD); /* store current MinSAD */
1460    
1461          if ((uint32_t) x != iWcount - 1)                          MainSearchFunc *MainSearchPtr;
1462                  CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);                          if (MotionFlags & XVID_ME_USESQUARES8) MainSearchPtr = SquareSearch;
1463                                    else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1464                                            else MainSearchPtr = DiamondSearch;
1465    
1466  // bottom neighbour, dito                          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, 255);
         if ((uint32_t) y != iHcount - 1)  
                 CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,  
                                                          (prevMB + iWcount)->mvs[0].y);  
1467    
1468  /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */                          if(*(Data->iMinSAD) < temp_sad) {
1469          if (iMinSAD <= thresh2) {                                          Data->currentQMV->x = 2 * Data->currentMV->x; /* update our qpel vector */
1470                  if (MotionFlags & PMV_QUICKSTOP16)                                          Data->currentQMV->y = 2 * Data->currentMV->y;
1471                          goto EPZS16_Terminate_without_Refine;                          }
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
1472          }          }
1473    
1474  /************ (if Diamond Search)  **************/                  if (MotionFlags & XVID_ME_HALFPELREFINE8) {
1475                            int32_t temp_sad = *(Data->iMinSAD); /* store current MinSAD */
1476    
1477          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                          SubpelRefine(Data); /* perform halfpel refine of current best vector */
1478    
1479          if (MotionFlags & PMV_USESQUARES16)                          if(*(Data->iMinSAD) < temp_sad) { /* we have found a better match */
1480                  MainSearchPtr = Square16_MainSearch;                                  Data->currentQMV->x = 2 * Data->currentMV->x; /* update our qpel vector */
1481          else                                  Data->currentQMV->y = 2 * Data->currentMV->y;
1482           if (MotionFlags & PMV_ADVANCEDDIAMOND16)                          }
1483                  MainSearchPtr = AdvDiamond16_MainSearch;                  }
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
1484    
1485  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                  if (Data->qpel && MotionFlags & XVID_ME_QUARTERPELREFINE8) {
1486                                    Data->qpel_precision = 1;
1487                                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1488                                            pParam->width, pParam->height, Data->iFcode, 1, 0);
1489                                    SubpelRefine(Data);
1490                    }
1491            }
1492    
1493          iSAD =          if (Data->rrv) {
1494                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,                          Data->currentMV->x = RRV_MV_SCALEDOWN(Data->currentMV->x);
1495                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,                          Data->currentMV->y = RRV_MV_SCALEDOWN(Data->currentMV->y);
1496                                                    min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);          }
1497    
1498          if (iSAD < iMinSAD) {          if(Data->qpel) {
1499                  *currMV = newMV;                  pMB->pmvs[block].x = Data->currentQMV->x - Data->predMV.x;
1500                  iMinSAD = iSAD;                  pMB->pmvs[block].y = Data->currentQMV->y - Data->predMV.y;
1501                    pMB->qmvs[block] = *Data->currentQMV;
1502            } else {
1503                    pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1504                    pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
1505          }          }
1506    
1507            pMB->mvs[block] = *Data->currentMV;
1508            pMB->sad8[block] = 4 * *Data->iMinSAD;
1509    }
1510    
1511          if (MotionFlags & PMV_EXTSEARCH16) {  /* motion estimation for B-frames */
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
1512    
1513                  if (!(MVequal(pmv[0], backupMV))) {  static __inline VECTOR
1514                          iSAD =  ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1515                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  {
1516                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,  /* the stupidiest function ever */
1517                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,          return (mode == MODE_FORWARD ? pMB->mvs[0] : pMB->b_mvs[0]);
                                                                   2, iFcode, iQuant, 0);  
1518                  }                  }
1519    
1520                  if (iSAD < iMinSAD) {  static void __inline
1521                          *currMV = newMV;  PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
1522                          iMinSAD = iSAD;                                                          const uint32_t iWcount,
1523                  }                                                          const MACROBLOCK * const pMB,
1524                                                            const uint32_t mode_curr)
1525    {
1526    
1527                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          /* [0] is prediction */
1528                          iSAD =          pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
                                 (*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);  
1529    
1530                          if (iSAD < iMinSAD) {          pmv[1].x = pmv[1].y = 0; /* [1] is zero */
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
                 }  
         }  
1531    
1532  /***************        Choose best MV found     **************/          pmv[2] = ChoosePred(pMB, mode_curr);
1533            pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
1534    
1535    EPZS16_Terminate_with_Refine:          if ((y != 0)&&(x != (int)(iWcount+1))) {                        /* [3] top-right neighbour */
1536          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step                  pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
1537                  iMinSAD =                  pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
1538                          Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,          } else pmv[3].x = pmv[3].y = 0;
                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
1539    
1540    EPZS16_Terminate_without_Refine:          if (y != 0) {
1541                    pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
1542                    pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
1543            } else pmv[4].x = pmv[4].y = 0;
1544    
1545          *oldMB = *prevMB;          if (x != 0) {
1546                    pmv[5] = ChoosePred(pMB-1, mode_curr);
1547                    pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1548            } else pmv[5].x = pmv[5].y = 0;
1549    
1550          currPMV->x = currMV->x - center_x;          if (x != 0 && y != 0) {
1551          currPMV->y = currMV->y - center_y;                  pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
1552          return iMinSAD;                  pmv[6].x = EVEN(pmv[6].x); pmv[6].y = EVEN(pmv[6].y);
1553            } else pmv[6].x = pmv[6].y = 0;
1554  }  }
1555    
1556    
1557  int32_t  /* search backward or forward */
1558  EPZSSearch8(const uint8_t * const pRef,  static void
1559    SearchBF(       const IMAGE * const pRef,
1560                          const uint8_t * const pRefH,                          const uint8_t * const pRefH,
1561                          const uint8_t * const pRefV,                          const uint8_t * const pRefV,
1562                          const uint8_t * const pRefHV,                          const uint8_t * const pRefHV,
1563                          const IMAGE * const pCur,                          const IMAGE * const pCur,
1564                          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,  
1565                          const uint32_t MotionFlags,                          const uint32_t MotionFlags,
                         const uint32_t iQuant,  
1566                          const uint32_t iFcode,                          const uint32_t iFcode,
1567                          const MBParam * const pParam,                          const MBParam * const pParam,
1568                          const MACROBLOCK * const pMBs,                          MACROBLOCK * const pMB,
1569                          const MACROBLOCK * const prevMBs,                          const VECTOR * const predMV,
1570                          VECTOR * const currMV,                          int32_t * const best_sad,
1571                          VECTOR * const currPMV)                          const int32_t mode_current,
1572                            SearchData * const Data)
1573  {  {
 /* Please not that EPZS might not be a good choice for 8x8-block motion search ! */  
1574    
1575          const uint32_t iWcount = pParam->mb_width;          int i, iDirection = 255, mask;
1576          const int32_t iWidth = pParam->width;          VECTOR pmv[7];
1577          const int32_t iHeight = pParam->height;          MainSearchFunc *MainSearchPtr;
1578          const int32_t iEdgedWidth = pParam->edged_width;          *Data->iMinSAD = MV_MAX_ERROR;
1579            Data->iFcode = iFcode;
1580            Data->qpel_precision = 0;
1581            Data->temp[5] = Data->temp[6] = Data->temp[7] = 256*4096; /* reset chroma-sad cache */
1582    
1583          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;          Data->RefP[0] = pRef->y + (x + Data->iEdgedWidth*y) * 16;
1584            Data->RefP[2] = pRefH + (x + Data->iEdgedWidth*y) * 16;
1585            Data->RefP[1] = pRefV + (x + Data->iEdgedWidth*y) * 16;
1586            Data->RefP[3] = pRefHV + (x + Data->iEdgedWidth*y) * 16;
1587            Data->RefP[4] = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8;
1588            Data->RefP[5] = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8;
1589    
1590          int32_t iDiamondSize = 1;          Data->predMV = *predMV;
1591    
1592          int32_t min_dx;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1593          int32_t max_dx;                                  pParam->width, pParam->height, iFcode - Data->qpel, 0, 0);
         int32_t min_dy;  
         int32_t max_dy;  
1594    
1595          VECTOR newMV;          pmv[0] = Data->predMV;
1596          VECTOR backupMV;          if (Data->qpel) { pmv[0].x /= 2; pmv[0].y /= 2; }
1597    
1598          VECTOR pmv[4];          PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);
         int32_t psad[8];  
1599    
1600          const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);          Data->currentMV->x = Data->currentMV->y = 0;
1601            CheckCandidate = CheckCandidate16no4v;
1602    
1603  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          /* main loop. checking all predictions */
1604          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;          for (i = 0; i < 7; i++) {
1605                    if (!(mask = make_mask(pmv, i)) ) continue;
1606          int32_t bPredEq;                  CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
         int32_t iMinSAD, iSAD = 9999;  
   
         MainSearch8FuncPtr MainSearchPtr;  
   
 /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,  
                           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);  
1607          }          }
         /* 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);  
   
1608    
1609  /* Step 4: Calculate SAD around the Median prediction.          if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1610          MinSAD=SAD          else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1611          If Motion Vector equal to Previous frame motion vector                  else MainSearchPtr = DiamondSearch;
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
 */  
1612    
1613  // Prepare for main loop          MainSearchPtr(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
1614    
1615            SubpelRefine(Data);
1616    
1617          if (!(MotionFlags & PMV_HALFPEL8)) {          if (Data->qpel && *Data->iMinSAD < *best_sad + 300) {
1618                  currMV->x = EVEN(currMV->x);                  Data->currentQMV->x = 2*Data->currentMV->x;
1619                  currMV->y = EVEN(currMV->y);                  Data->currentQMV->y = 2*Data->currentMV->y;
1620                    Data->qpel_precision = 1;
1621                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1622                                            pParam->width, pParam->height, iFcode, 1, 0);
1623                    SubpelRefine(Data);
1624          }          }
1625    
1626          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;  
1627    
1628  /***************** This is predictor SET A: only median prediction ******************/          if (mode_current == MODE_FORWARD) *Data->iMinSAD += 4 * Data->lambda16;
1629            else *Data->iMinSAD += 3 * Data->lambda16;
1630    
1631            if (*Data->iMinSAD < *best_sad) {
1632                    *best_sad = *Data->iMinSAD;
1633                    pMB->mode = mode_current;
1634                    if (Data->qpel) {
1635                            pMB->pmvs[0].x = Data->currentQMV->x - predMV->x;
1636                            pMB->pmvs[0].y = Data->currentQMV->y - predMV->y;
1637                            if (mode_current == MODE_FORWARD)
1638                                    pMB->qmvs[0] = *Data->currentQMV;
1639                            else
1640                                    pMB->b_qmvs[0] = *Data->currentQMV;
1641                    } else {
1642                            pMB->pmvs[0].x = Data->currentMV->x - predMV->x;
1643                            pMB->pmvs[0].y = Data->currentMV->y - predMV->y;
1644                    }
1645                    if (mode_current == MODE_FORWARD) pMB->mvs[0] = *Data->currentMV;
1646                    else pMB->b_mvs[0] = *Data->currentMV;
1647            }
1648    
1649          iMinSAD =          if (mode_current == MODE_FORWARD) *(Data->currentMV+2) = *Data->currentMV;
1650                  sad8(cur,          else *(Data->currentMV+1) = *Data->currentMV; /* we store currmv for interpolate search */
1651                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  }
1652                                                  iEdgedWidth), iEdgedWidth);  
1653          iMinSAD +=  static void
1654                  calc_delta_8(currMV->x - center_x, currMV->y - center_y,  SkipDecisionB(const IMAGE * const pCur,
1655                                           (uint8_t) iFcode, iQuant);                                  const IMAGE * const f_Ref,
1656                                    const IMAGE * const b_Ref,
1657                                    MACROBLOCK * const pMB,
1658                                    const uint32_t x, const uint32_t y,
1659                                    const SearchData * const Data)
1660    {
1661            int dx = 0, dy = 0, b_dx = 0, b_dy = 0;
1662            int32_t sum;
1663            const int div = 1 + Data->qpel;
1664            int k;
1665            const uint32_t stride = Data->iEdgedWidth/2;
1666            /* this is not full chroma compensation, only it's fullpel approximation. should work though */
1667    
1668            for (k = 0; k < 4; k++) {
1669                    dy += Data->directmvF[k].y / div;
1670                    dx += Data->directmvF[k].x / div;
1671                    b_dy += Data->directmvB[k].y / div;
1672                    b_dx += Data->directmvB[k].x / div;
1673            }
1674    
1675            dy = (dy >> 3) + roundtab_76[dy & 0xf];
1676            dx = (dx >> 3) + roundtab_76[dx & 0xf];
1677            b_dy = (b_dy >> 3) + roundtab_76[b_dy & 0xf];
1678            b_dx = (b_dx >> 3) + roundtab_76[b_dx & 0xf];
1679    
1680            sum = sad8bi(pCur->u + 8 * x + 8 * y * stride,
1681                                            f_Ref->u + (y*8 + dy/2) * stride + x*8 + dx/2,
1682                                            b_Ref->u + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1683                                            stride);
1684    
1685            if (sum >= 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) return; /* no skip */
1686    
1687            sum += sad8bi(pCur->v + 8*x + 8 * y * stride,
1688                                            f_Ref->v + (y*8 + dy/2) * stride + x*8 + dx/2,
1689                                            b_Ref->v + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1690                                            stride);
1691    
1692  // thresh1 is fixed to 256          if (sum < 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) {
1693          if (iMinSAD < 256 / 4) {                  pMB->mode = MODE_DIRECT_NONE_MV; /* skipped */
1694                  if (MotionFlags & PMV_QUICKSTOP8)                  for (k = 0; k < 4; k++) {
1695                          goto EPZS8_Terminate_without_Refine;                          pMB->qmvs[k] = pMB->mvs[k];
1696                  if (MotionFlags & PMV_EARLYSTOP8)                          pMB->b_qmvs[k] = pMB->b_mvs[k];
1697                          goto EPZS8_Terminate_with_Refine;                  }
1698            }
1699          }          }
1700    
1701  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/  static __inline uint32_t
1702    SearchDirect(const IMAGE * const f_Ref,
1703                                    const uint8_t * const f_RefH,
1704                                    const uint8_t * const f_RefV,
1705                                    const uint8_t * const f_RefHV,
1706                                    const IMAGE * const b_Ref,
1707                                    const uint8_t * const b_RefH,
1708                                    const uint8_t * const b_RefV,
1709                                    const uint8_t * const b_RefHV,
1710                                    const IMAGE * const pCur,
1711                                    const int x, const int y,
1712                                    const uint32_t MotionFlags,
1713                                    const int32_t TRB, const int32_t TRD,
1714                                    const MBParam * const pParam,
1715                                    MACROBLOCK * const pMB,
1716                                    const MACROBLOCK * const b_mb,
1717                                    int32_t * const best_sad,
1718                                    SearchData * const Data)
1719    
1720    {
1721            int32_t skip_sad;
1722            int k = (x + Data->iEdgedWidth*y) * 16;
1723            MainSearchFunc *MainSearchPtr;
1724    
1725            *Data->iMinSAD = 256*4096;
1726            Data->RefP[0] = f_Ref->y + k;
1727            Data->RefP[2] = f_RefH + k;
1728            Data->RefP[1] = f_RefV + k;
1729            Data->RefP[3] = f_RefHV + k;
1730            Data->b_RefP[0] = b_Ref->y + k;
1731            Data->b_RefP[2] = b_RefH + k;
1732            Data->b_RefP[1] = b_RefV + k;
1733            Data->b_RefP[3] = b_RefHV + k;
1734            Data->RefP[4] = f_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1735            Data->RefP[5] = f_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1736            Data->b_RefP[4] = b_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1737            Data->b_RefP[5] = b_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1738    
1739            k = Data->qpel ? 4 : 2;
1740            Data->max_dx = k * (pParam->width - x * 16);
1741            Data->max_dy = k * (pParam->height - y * 16);
1742            Data->min_dx = -k * (16 + x * 16);
1743            Data->min_dy = -k * (16 + y * 16);
1744    
1745            Data->referencemv = Data->qpel ? b_mb->qmvs : b_mb->mvs;
1746            Data->qpel_precision = 0;
1747    
1748  // MV=(0,0) is often a good choice          for (k = 0; k < 4; k++) {
1749          CHECK_MV8_ZERO;                  pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);
1750                    pMB->b_mvs[k].x = Data->directmvB[k].x = ((TRB - TRD) * Data->referencemv[k].x) / TRD;
1751                    pMB->mvs[k].y = Data->directmvF[k].y = ((TRB * Data->referencemv[k].y) / TRD);
1752                    pMB->b_mvs[k].y = Data->directmvB[k].y = ((TRB - TRD) * Data->referencemv[k].y) / TRD;
1753    
1754  // previous frame MV                  if ( (pMB->b_mvs[k].x > Data->max_dx) | (pMB->b_mvs[k].x < Data->min_dx)
1755          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) ) {
1756    
1757  // left neighbour, if allowed                          *best_sad = 256*4096; /* in that case, we won't use direct mode */
1758          if (psad[1] != MV_MAX_ERROR) {                          pMB->mode = MODE_DIRECT; /* just to make sure it doesn't say "MODE_DIRECT_NONE_MV" */
1759                  if (!(MotionFlags & PMV_HALFPEL8)) {                          pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;
1760                          pmv[1].x = EVEN(pmv[1].x);                          return 256*4096;
                         pmv[1].y = EVEN(pmv[1].y);  
1761                  }                  }
1762                  CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);                  if (b_mb->mode != MODE_INTER4V) {
1763                            pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mvs[0];
1764                            pMB->b_mvs[1] = pMB->b_mvs[2] = pMB->b_mvs[3] = pMB->b_mvs[0];
1765                            Data->directmvF[1] = Data->directmvF[2] = Data->directmvF[3] = Data->directmvF[0];
1766                            Data->directmvB[1] = Data->directmvB[2] = Data->directmvB[3] = Data->directmvB[0];
1767                            break;
1768          }          }
 // 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);  
1769                  }                  }
                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
1770    
1771  // top right neighbour, if allowed          CheckCandidate = b_mb->mode == MODE_INTER4V ? CheckCandidateDirect : CheckCandidateDirectno4v;
                 if (psad[3] != MV_MAX_ERROR) {  
                         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);  
                 }  
         }  
1772    
1773  /*  // this bias is zero anyway, at the moment!          CheckCandidate(0, 0, 255, &k, Data);
1774    
1775          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)          /* initial (fast) skip decision */
1776                  iMinSAD -= MV8_00_BIAS;          if (*Data->iMinSAD < pMB->quant * INITIAL_SKIP_THRESH * (Data->chroma?3:2)) {
1777                    /* possible skip */
1778                    if (Data->chroma) {
1779                            pMB->mode = MODE_DIRECT_NONE_MV;
1780                            return *Data->iMinSAD; /* skip. */
1781                    } else {
1782                            SkipDecisionB(pCur, f_Ref, b_Ref, pMB, x, y, Data);
1783                            if (pMB->mode == MODE_DIRECT_NONE_MV) return *Data->iMinSAD; /* skip. */
1784                    }
1785            }
1786    
1787  */          *Data->iMinSAD += Data->lambda16;
1788            skip_sad = *Data->iMinSAD;
1789    
1790  /* Terminate if MinSAD <= T_2          /*
1791     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]           * DIRECT MODE DELTA VECTOR SEARCH.
1792             * This has to be made more effective, but at the moment I'm happy it's running at all
1793  */  */
1794    
1795          if (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */          if (MotionFlags & XVID_ME_USESQUARES16) MainSearchPtr = SquareSearch;
1796                  if (MotionFlags & PMV_QUICKSTOP8)                  else if (MotionFlags & XVID_ME_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1797                          goto EPZS8_Terminate_without_Refine;                          else MainSearchPtr = DiamondSearch;
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
         }  
1798    
1799  /************ (Diamond Search)  **************/          MainSearchPtr(0, 0, Data, 255);
1800    
1801          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          SubpelRefine(Data);
1802    
1803          if (!(MotionFlags & PMV_HALFPELDIAMOND8))          *best_sad = *Data->iMinSAD;
                 iDiamondSize *= 2;  
1804    
1805  /* default: use best prediction as starting point for one call of EPZS_MainSearch */          if (Data->qpel || b_mb->mode == MODE_INTER4V) pMB->mode = MODE_DIRECT;
1806            else pMB->mode = MODE_DIRECT_NO4V; /* for faster compensation */
1807    
1808  // there is no EPZS^2 for inter4v at the moment          pMB->pmvs[3] = *Data->currentMV;
1809    
1810    if (MotionFlags & PMV_USESQUARES8)          for (k = 0; k < 4; k++) {
1811        MainSearchPtr = Square8_MainSearch;                  pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
1812    else                  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          if (MotionFlags & PMV_ADVANCEDDIAMOND8)  {
                 MainSearchPtr = AdvDiamond8_MainSearch;  
         else  
                 MainSearchPtr = Diamond8_MainSearch;  
1859    
1860          iSAD =          int iDirection, i, j;
1861                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,          SearchData bData;
1862                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,  
1863                                                    min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,          fData->qpel_precision = 0;
1864                                                    iQuant, 0);          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            CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, 255, &iDirection, fData);
1902    
1903          if (iSAD < iMinSAD) {          /* diamond */
1904                  *currMV = newMV;          do {
1905                  iMinSAD = iSAD;                  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_EXTSEARCH8) {  void
1965  /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  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                  if (!(MVequal(pmv[0], backupMV))) {          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
                         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);  
1989    
1990                          if (iSAD < iMinSAD) {          const int32_t TRB = time_pp - time_bp;
1991                                  *currMV = newMV;          const int32_t TRD = time_pp;
                                 iMinSAD = iSAD;  
                         }  
                 }  
1992    
1993                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          /* some pre-inintialized data for the rest of the search */
                         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, 0);  
1994    
1995                          if (iSAD < iMinSAD) {          SearchData Data;
1996                                  *currMV = newMV;          int32_t iMinSAD;
1997                                  iMinSAD = iSAD;          VECTOR currentMV[3];
1998                          }          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->vol_flags & XVID_VOL_QUARTERPEL;
2006            Data.rounding = 0;
2007            Data.chroma = frame->motion_flags & XVID_ME_CHROMA8;
2008            Data.temp = temp;
2009    
2010            Data.RefQ = f_refV->u; /* a good place, also used in MC (for similar purpose) */
2011    
2012            /* note: i==horizontal, j==vertical */
2013            for (j = 0; j < pParam->mb_height; j++) {
2014    
2015                    f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
2016    
2017                    for (i = 0; i < pParam->mb_width; i++) {
2018                            MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
2019                            const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
2020    
2021    /* special case, if collocated block is SKIPed in P-VOP: encoding is forward (0,0), cpb=0 without further ado */
2022                            if (b_reference->coding_type != S_VOP)
2023                                    if (b_mb->mode == MODE_NOT_CODED) {
2024                                            pMB->mode = MODE_NOT_CODED;
2025                                            continue;
2026          }          }
2027    
2028  /***************        Choose best MV found     **************/                          Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
2029                            Data.CurU = frame->image.u + (j * Data.iEdgedWidth/2 + i) * 8;
2030    EPZS8_Terminate_with_Refine:                          Data.CurV = frame->image.v + (j * Data.iEdgedWidth/2 + i) * 8;
2031          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step                          pMB->quant = frame->quant;
2032                  iMinSAD =  
2033                          Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  /* direct search comes first, because it (1) checks for SKIP-mode
2034                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,          and (2) sets very good predictions for forward and backward search */
2035                                                          iFcode, iQuant, iEdgedWidth);                          skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2036                                                                            b_ref, b_refH->y, b_refV->y, b_refHV->y,
2037                                                                            &frame->image,
2038                                                                            i, j,
2039                                                                            frame->motion_flags,
2040                                                                            TRB, TRD,
2041                                                                            pParam,
2042                                                                            pMB, b_mb,
2043                                                                            &best_sad,
2044                                                                            &Data);
2045    
2046    EPZS8_Terminate_without_Refine:                          if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
2047    
2048          currPMV->x = currMV->x - center_x;                          /* forward search */
2049          currPMV->y = currMV->y - center_y;                          SearchBF(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2050          return iMinSAD;                                                  &frame->image, i, j,
2051  }                                                  frame->motion_flags,
2052                                                    frame->fcode, pParam,
2053                                                    pMB, &f_predMV, &best_sad,
2054                                                    MODE_FORWARD, &Data);
2055    
2056                            /* backward search */
2057                            SearchBF(b_ref, b_refH->y, b_refV->y, b_refHV->y,
2058                                                    &frame->image, i, j,
2059                                                    frame->motion_flags,
2060                                                    frame->bcode, pParam,
2061                                                    pMB, &b_predMV, &best_sad,
2062                                                    MODE_BACKWARD, &Data);
2063    
2064                            /* interpolate search comes last, because it uses data from forward and backward as prediction */
2065                            SearchInterpolate(f_ref, f_refH->y, f_refV->y, f_refHV->y,
2066                                                    b_ref, b_refH->y, b_refV->y, b_refHV->y,
2067                                                    &frame->image,
2068                                                    i, j,
2069                                                    frame->fcode, frame->bcode,
2070                                                    frame->motion_flags,
2071                                                    pParam,
2072                                                    &f_predMV, &b_predMV,
2073                                                    pMB, &best_sad,
2074                                                    &Data);
2075    
2076                            /* final skip decision */
2077                            if ( (skip_sad < frame->quant * MAX_SAD00_FOR_SKIP * 2)
2078                                            && ((100*best_sad)/(skip_sad+1) > FINAL_SKIP_THRESH) )
2079                                    SkipDecisionB(&frame->image, f_ref, b_ref, pMB, i, j, &Data);
2080    
2081                            switch (pMB->mode) {
2082                                    case MODE_FORWARD:
2083                                            f_count++;
2084                                            f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2085                                            break;
2086                                    case MODE_BACKWARD:
2087                                            b_count++;
2088                                            b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2089                                            break;
2090                                    case MODE_INTERPOLATE:
2091                                            i_count++;
2092                                            f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
2093                                            b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
2094                                            break;
2095                                    case MODE_DIRECT:
2096                                    case MODE_DIRECT_NO4V:
2097                                            d_count++;
2098                                    default:
2099                                            break;
2100                            }
2101                    }
2102            }
2103    }
2104    
2105  int32_t  static __inline void
2106  PMVfastIntSearch16(const uint8_t * const pRef,  MEanalyzeMB (   const uint8_t * const pRef,
2107                                  const uint8_t * const pRefH,                                  const uint8_t * const pCur,
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const IMAGE * const pCur,  
2108                                  const int x,                                  const int x,
2109                                  const int y,                                  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,  
2110                                  const MBParam * const pParam,                                  const MBParam * const pParam,
2111                                  const MACROBLOCK * const pMBs,                                  MACROBLOCK * const pMBs,
2112                                  const MACROBLOCK * const prevMBs,                                  SearchData * const Data)
                                 VECTOR * const currMV,  
                                 VECTOR * const currPMV)  
2113  {  {
         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;  
2114    
2115          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          int i, mask;
2116          const VECTOR zeroMV = { 0, 0 };          int quarterpel = (pParam->vol_flags & XVID_VOL_QUARTERPEL)? 1: 0;
2117            VECTOR pmv[3];
2118            MACROBLOCK * const pMB = &pMBs[x + y * pParam->mb_width];
2119    
2120          int32_t iDiamondSize;          for (i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;
2121    
2122          int32_t min_dx;          /* median is only used as prediction. it doesn't have to be real */
2123          int32_t max_dx;          if (x == 1 && y == 1) Data->predMV.x = Data->predMV.y = 0;
2124          int32_t min_dy;          else
2125          int32_t max_dy;                  if (x == 1) /* left macroblock does not have any vector now */
2126                            Data->predMV = (pMB - pParam->mb_width)->mvs[0]; /* top instead of median */
2127                    else if (y == 1) /* top macroblock doesn't have it's vector */
2128                            Data->predMV = (pMB - 1)->mvs[0]; /* left instead of median */
2129                            else Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); /* else median */
2130    
2131          int32_t iFound;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2132            pParam->width, pParam->height, Data->iFcode - quarterpel, 0, 0);
2133    
2134          VECTOR newMV;          Data->Cur = pCur + (x + y * pParam->edged_width) * 16;
2135          VECTOR backupMV;          Data->RefP[0] = pRef + (x + y * pParam->edged_width) * 16;
2136    
2137          VECTOR pmv[4];          pmv[1].x = EVEN(pMB->mvs[0].x);
2138          int32_t psad[4];          pmv[1].y = EVEN(pMB->mvs[0].y);
2139            pmv[2].x = EVEN(Data->predMV.x);
2140            pmv[2].y = EVEN(Data->predMV.y);
2141            pmv[0].x = pmv[0].y = 0;
2142    
2143          MainSearch16FuncPtr MainSearchPtr;          CheckCandidate32I(0, 0, 255, &i, Data);
2144    
2145          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;          if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP) {
         MACROBLOCK *const pMB = pMBs + x + y * iWcount;  
2146    
2147          int32_t threshA, threshB;                  if (!(mask = make_mask(pmv, 1)))
2148          int32_t bPredEq;                          CheckCandidate32I(pmv[1].x, pmv[1].y, mask, &i, Data);
2149          int32_t iMinSAD, iSAD;                  if (!(mask = make_mask(pmv, 2)))
2150                            CheckCandidate32I(pmv[2].x, pmv[2].y, mask, &i, Data);
2151    
2152                    if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP) /* diamond only if needed */
2153                            DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, i);
2154            }
2155    
2156  /* Get maximum range */          for (i = 0; i < 4; i++) {
2157          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,                  MACROBLOCK * MB = &pMBs[x + (i&1) + (y+(i>>1)) * pParam->mb_width];
2158                            iFcode);                  MB->mvs[0] = MB->mvs[1] = MB->mvs[2] = MB->mvs[3] = Data->currentMV[i];
2159                    MB->mode = MODE_INTER;
2160                    MB->sad16 = Data->iMinSAD[i+1];
2161            }
2162    }
2163    
2164  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  #define INTRA_THRESH    1700
2165    #define INTER_THRESH    1200
2166    
2167          if ((x == 0) && (y == 0)) {  int
2168                  threshA = 512;  MEanalysis(     const IMAGE * const pRef,
2169                  threshB = 1024;                          const FRAMEINFO * const Current,
2170                            const MBParam * const pParam,
2171                            const int maxIntra, /* maximum number if non-I frames */
2172                            const int intraCount, /* number of non-I frames after last I frame; 0 if we force P/B frame */
2173                            const int bCount,  /* number of B frames in a row */
2174                            const int b_thresh)
2175    {
2176            uint32_t x, y, intra = 0;
2177            int sSAD = 0;
2178            MACROBLOCK * const pMBs = Current->mbs;
2179            const IMAGE * const pCurrent = &Current->image;
2180            int IntraThresh = INTRA_THRESH, InterThresh = INTER_THRESH + 10*b_thresh;
2181            int s = 0, blocks = 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            if (intraCount != 0) {
2194                    if (intraCount < 10) /* we're right after an I frame */
2195                            IntraThresh += 15* (intraCount - 10) * (intraCount - 10);
2196                    else
2197                            if ( 5*(maxIntra - intraCount) < maxIntra) /* we're close to maximum. 2 sec when max is 10 sec */
2198                                    IntraThresh -= (IntraThresh * (maxIntra - 8*(maxIntra - intraCount)))/maxIntra;
2199            }
2200    
2201                  bPredEq = 0;          InterThresh -= (350 - 8*b_thresh) * bCount;
2202                  psad[0] = psad[1] = psad[2] = psad[3] = 0;          if (InterThresh < 300 + 5*b_thresh) InterThresh = 300 + 5*b_thresh;
                 *currMV = pmv[0] = pmv[1] = pmv[2] = pmv[3] = zeroMV;  
2203    
2204          } else {          if (sadInit) (*sadInit) ();
2205                  threshA = psad[0];  
2206                  threshB = threshA + 256;          for (y = 1; y < pParam->mb_height-1; y += 2) {
2207                  if (threshA < 512)                  for (x = 1; x < pParam->mb_width-1; x += 2) {
2208                          threshA = 512;                          int i;
2209                  if (threshA > 1024)                          blocks += 4;
2210                          threshA = 1024;  
2211                  if (threshB > 1792)                          if (bCount == 0) pMBs[x + y * pParam->mb_width].mvs[0] = zeroMV;
2212                          threshB = 1792;                          else { /* extrapolation of the vector found for last frame */
2213                                    pMBs[x + y * pParam->mb_width].mvs[0].x =
2214                  bPredEq = get_ipmvdata(pMBs, iWcount, 0, x, y, 0, pmv, psad);                                          (pMBs[x + y * pParam->mb_width].mvs[0].x * (bCount+1) ) / bCount;
2215                  *currMV = pmv[0];                       /* current best := prediction */                                  pMBs[x + y * pParam->mb_width].mvs[0].y =
2216          }                                          (pMBs[x + y * pParam->mb_width].mvs[0].y * (bCount+1) ) / bCount;
2217                            }
2218          iFound = 0;  
2219                            MEanalyzeMB(pRef->y, pCurrent->y, x, y, pParam, pMBs, &Data);
 /* 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.  
 */  
2220    
2221          if (currMV->x > max_dx) {                          for (i = 0; i < 4; i++) {
2222                  currMV->x = EVEN(max_dx);                                  int dev;
2223                                    MACROBLOCK *pMB = &pMBs[x+(i&1) + (y+(i>>1)) * pParam->mb_width];
2224                                    if (pMB->sad16 > IntraThresh) {
2225                                            dev = dev16(pCurrent->y + (x + (i&1) + (y + (i>>1)) * pParam->edged_width) * 16,
2226                                                                            pParam->edged_width);
2227                                            if (dev + IntraThresh < pMB->sad16) {
2228                                                    pMB->mode = MODE_INTRA;
2229                                                    if (++intra > ((pParam->mb_height-2)*(pParam->mb_width-2))/2) return I_VOP;
2230          }          }
         if (currMV->x < min_dx) {  
                 currMV->x = EVEN(min_dx);  
2231          }          }
2232          if (currMV->y > max_dy) {                                  if (pMB->mvs[0].x == 0 && pMB->mvs[0].y == 0) s++;
2233                  currMV->y = EVEN(max_dy);  
2234                                    sSAD += pMB->sad16;
2235                            }
2236          }          }
         if (currMV->y < min_dy) {  
                 currMV->y = EVEN(min_dy);  
2237          }          }
2238    
2239          iMinSAD =          sSAD /= blocks;
                 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);  
2240    
2241          if ((iMinSAD < 256) ||          if (b_thresh < 20) {
2242                  ((MVequal(*currMV, prevMB->i_mvs[0])) &&                  s = (10*s) / blocks;
2243                   ((int32_t) iMinSAD < prevMB->i_sad16))) {                  if (s > 4) sSAD += (s - 2) * (40 - 2*b_thresh); /* static block - looks bad when in bframe... */
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
                 {  
                         if (!MVzero(*currMV)) {  
                                 iMinSAD += MV16_00_BIAS;  
                                 CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures  
                                 iMinSAD -= MV16_00_BIAS;  
                         }  
2244                  }                  }
2245    
2246                  if (MotionFlags & PMV_EARLYSTOP16)          if (sSAD > InterThresh ) return P_VOP;
2247                          goto PMVfastInt16_Terminate_with_Refine;          emms();
2248            return B_VOP;
2249          }          }
2250    
2251    
2252  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  static WARPPOINTS
2253     vector of the median.  GlobalMotionEst(const MACROBLOCK * const pMBs,
2254     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2                                  const MBParam * const pParam,
2255  */                                  const FRAMEINFO * const current,
2256                                    const FRAMEINFO * const reference,
2257                                    const IMAGE * const pRefH,
2258                                    const IMAGE * const pRefV,
2259                                    const IMAGE * const pRefHV      )
2260    {
2261    
2262          if ((bPredEq) && (MVequal(pmv[0], prevMB->i_mvs[0])))          const int deltax=8;             /* upper bound for difference between a MV and it's neighbour MVs */
2263                  iFound = 2;          const int deltay=8;
2264            const int grad=512;             /* lower bound for deviation in MB */
2265    
2266  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          WARPPOINTS gmc;
    Otherwise select large Diamond Search.  
 */  
2267    
2268          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))          uint32_t mx, my;
                 iDiamondSize = 2;               // halfpel units!  
         else  
                 iDiamondSize = 4;               // halfpel units!  
2269    
2270  /*          int MBh = pParam->mb_height;
2271     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.          int MBw = pParam->mb_width;
    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.  
 */  
2272    
2273  // (0,0) is often a good choice          int *MBmask= calloc(MBh*MBw,sizeof(int));
2274            double DtimesF[4] = { 0.,0., 0., 0. };
2275            double sol[4] = { 0., 0., 0., 0. };
2276            double a,b,c,n,denom;
2277            double meanx,meany;
2278            int num,oldnum;
2279    
2280          if (!MVzero(pmv[0]))          if (!MBmask) {  fprintf(stderr,"Mem error\n");
2281                  CHECK_MV16_ZERO;                                          gmc.duv[0].x= gmc.duv[0].y =
2282                                                    gmc.duv[1].x= gmc.duv[1].y =
2283                                                    gmc.duv[2].x= gmc.duv[2].y = 0;
2284                                            return gmc; }
2285    
2286  // previous frame MV is always possible          /* filter mask of all blocks */
2287    
2288          if (!MVzero(prevMB->i_mvs[0]))          for (my = 1; my < (uint32_t)MBh-1; my++)
2289                  if (!MVequal(prevMB->i_mvs[0], pmv[0]))          for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2290                          CHECK_MV16_CANDIDATE(prevMB->i_mvs[0].x, prevMB->i_mvs[0].y);          {
2291                    const int mbnum = mx + my * MBw;
2292  // left neighbour, if allowed                  const MACROBLOCK *pMB = &pMBs[mbnum];
2293                    const VECTOR mv = pMB->mvs[0];
         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;  
2294    
2295                    if (pMB->mode == MODE_INTRA || pMB->mode == MODE_NOT_CODED)
2296                            continue;
2297    
2298  /* Step 6: If MinSAD <= thresa goto Step 10.                  if ( ( (abs(mv.x -   (pMB-1)->mvs[0].x) < deltax) && (abs(mv.y -   (pMB-1)->mvs[0].y) < deltay) )
2299     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.                  &&   ( (abs(mv.x -   (pMB+1)->mvs[0].x) < deltax) && (abs(mv.y -   (pMB+1)->mvs[0].y) < deltay) )
2300  */                  &&   ( (abs(mv.x - (pMB-MBw)->mvs[0].x) < deltax) && (abs(mv.y - (pMB-MBw)->mvs[0].y) < deltay) )
2301                    &&   ( (abs(mv.x - (pMB+MBw)->mvs[0].x) < deltax) && (abs(mv.y - (pMB+MBw)->mvs[0].y) < deltay) ) )
2302                            MBmask[mbnum]=1;
2303            }
2304    
2305            for (my = 1; my < (uint32_t)MBh-1; my++)
2306            for (mx = 1; mx < (uint32_t)MBw-1; mx++)
2307            {
2308                    const uint8_t *const pCur = current->image.y + 16*my*pParam->edged_width + 16*mx;
2309    
2310                    const int mbnum = mx + my * MBw;
2311                    if (!MBmask[mbnum])
2312                            continue;
2313    
2314          if ((iMinSAD <= threshA) ||                  if (sad16 ( pCur, pCur+1 , pParam->edged_width, 65536) <= (uint32_t)grad )
2315                  (MVequal(*currMV, prevMB->i_mvs[0]) &&                          MBmask[mbnum] = 0;
2316                   ((int32_t) iMinSAD < prevMB->i_sad16))) {                  if (sad16 ( pCur, pCur+pParam->edged_width, pParam->edged_width, 65536) <= (uint32_t)grad )
2317                            MBmask[mbnum] = 0;
2318    
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfastInt16_Terminate_with_Refine;  
2319          }          }
2320    
2321            emms();
2322    
2323  /************ (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.  
 */  
2324    
2325          if (MotionFlags & PMV_USESQUARES16)          a = b = c = n = 0;
2326                  MainSearchPtr = Square16_MainSearch;          DtimesF[0] = DtimesF[1] = DtimesF[2] = DtimesF[3] = 0.;
2327          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)          for (my = 0; my < (uint32_t)MBh; my++)
2328                  MainSearchPtr = AdvDiamond16_MainSearch;                  for (mx = 0; mx < (uint32_t)MBw; mx++)
2329          else                  {
2330                  MainSearchPtr = Diamond16_MainSearch;                          const int mbnum = mx + my * MBw;
2331                            const MACROBLOCK *pMB = &pMBs[mbnum];
2332                            const VECTOR mv = pMB->mvs[0];
2333    
2334          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                          if (!MBmask[mbnum])
2335                                    continue;
2336    
2337                            n++;
2338                            a += 16*mx+8;
2339                            b += 16*my+8;
2340                            c += (16*mx+8)*(16*mx+8)+(16*my+8)*(16*my+8);
2341    
2342                            DtimesF[0] += (double)mv.x;
2343                            DtimesF[1] += (double)mv.x*(16*mx+8) + (double)mv.y*(16*my+8);
2344                            DtimesF[2] += (double)mv.x*(16*my+8) - (double)mv.y*(16*mx+8);
2345                            DtimesF[3] += (double)mv.y;
2346                    }
2347    
2348            denom = a*a+b*b-c*n;
2349    
2350    /* Solve the system:    sol = (D'*E*D)^{-1} D'*E*F   */
2351    /* D'*E*F has been calculated in the same loop as matrix */
2352    
2353            sol[0] = -c*DtimesF[0] + a*DtimesF[1] + b*DtimesF[2];
2354            sol[1] =  a*DtimesF[0] - n*DtimesF[1]                + b*DtimesF[3];
2355            sol[2] =  b*DtimesF[0]                - n*DtimesF[2] - a*DtimesF[3];
2356            sol[3] =                 b*DtimesF[1] - a*DtimesF[2] - c*DtimesF[3];
2357    
2358            sol[0] /= denom;
2359            sol[1] /= denom;
2360            sol[2] /= denom;
2361            sol[3] /= denom;
2362    
2363            meanx = meany = 0.;
2364            oldnum = 0;
2365            for (my = 0; my < (uint32_t)MBh; my++)
2366                    for (mx = 0; mx < (uint32_t)MBw; mx++)
2367                    {
2368                            const int mbnum = mx + my * MBw;
2369                            const MACROBLOCK *pMB = &pMBs[mbnum];
2370                            const VECTOR mv = pMB->mvs[0];
2371    
2372  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                          if (!MBmask[mbnum])
2373          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);  
2374    
2375          if (iSAD < iMinSAD) {                          oldnum++;
2376                  *currMV = newMV;                          meanx += fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - mv.x );
2377                  iMinSAD = iSAD;                          meany += fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - mv.y );
2378          }          }
2379    
2380          if (MotionFlags & PMV_EXTSEARCH16) {          if (4*meanx > oldnum)   /* better fit than 0.25 is useless */
2381  /* extended: search (up to) two more times: orignal prediction and (0,0) */                  meanx /= oldnum;
2382            else
2383                    meanx = 0.25;
2384    
2385                  if (!(MVequal(pmv[0], backupMV))) {          if (4*meany > oldnum)
2386                          iSAD =                  meany /= oldnum;
2387                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,          else
2388                                                                    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);  
2389    
2390                          if (iSAD < iMinSAD) {  /*      fprintf(stderr,"sol = (%8.5f, %8.5f, %8.5f, %8.5f)\n",sol[0],sol[1],sol[2],sol[3]);
2391                                  *currMV = newMV;          fprintf(stderr,"meanx = %8.5f  meany = %8.5f   %d\n",meanx,meany, oldnum);
2392                                  iMinSAD = iSAD;  */
2393                          }          num = 0;
2394                  }          for (my = 0; my < (uint32_t)MBh; my++)
2395                    for (mx = 0; mx < (uint32_t)MBw; mx++)
2396                    {
2397                            const int mbnum = mx + my * MBw;
2398                            const MACROBLOCK *pMB = &pMBs[mbnum];
2399                            const VECTOR mv = pMB->mvs[0];
2400    
2401                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                          if (!MBmask[mbnum])
2402                          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);  
2403    
2404                          if (iSAD < iMinSAD) {                          if  ( ( fabs(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - mv.x ) > meanx )
2405                                  *currMV = newMV;                                  || ( fabs(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - mv.y ) > meany ) )
2406                                  iMinSAD = iSAD;                                  MBmask[mbnum]=0;
2407                          }                          else
2408                  }                                  num++;
2409          }          }
2410    
2411  /*          } while ( (oldnum != num) && (num>=4) );
    Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  
 */  
   
 PMVfastInt16_Terminate_with_Refine:  
2412    
2413          pMB->i_mvs[0] = pMB->i_mvs[1] = pMB->i_mvs[2] = pMB->i_mvs[3] = pMB->i_mv16 = *currMV;          if (num < 4)
2414          pMB->i_sad8[0] = pMB->i_sad8[1] = pMB->i_sad8[2] = pMB->i_sad8[3] = pMB->i_sad16 = iMinSAD;          {
2415                    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;
2416            } else {
2417    
2418          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step                  gmc.duv[0].x=(int)(sol[0]+0.5);
2419                  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);  
2420    
2421          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);
2422                    gmc.duv[1].y=(int)(-sol[2]*pParam->width+0.5);
2423    
2424  PMVfastInt16_Terminate_without_Refine:                  gmc.duv[2].x=0;
2425          currPMV->x = currMV->x - center_x;                  gmc.duv[2].y=0;
         currPMV->y = currMV->y - center_y;  
         return iMinSAD;  
2426  }  }
2427    /*      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); */
2428    
2429            free(MBmask);
2430    
2431            return gmc;
2432    }
2433    
2434  /* ***********************************************************  /* functions which perform BITS-based search/bitcount */
         bvop motion estimation  
 ***************************************************************/  
2435    
2436  void  static int
2437  MotionEstimationBVOP(MBParam * const pParam,  CountMBBitsInter(SearchData * const Data,
2438                                           FRAMEINFO * const frame,                                  const MACROBLOCK * const pMBs, const int x, const int y,
2439                                           const int32_t time_bp,                                  const MBParam * const pParam,
2440                                           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)  
2441  {  {
2442          const int mb_width = pParam->mb_width;          int i, iDirection;
2443          const int mb_height = pParam->mb_height;          int32_t bsad[5];
         const int edged_width = pParam->edged_width;  
2444    
2445          const int32_t iWidth = pParam->width;          CheckCandidate = CheckCandidateBits16;
         const int32_t iHeight = pParam->height;  
2446    
2447          int i, j, k;          if (Data->qpel) {
2448                    for(i = 0; i < 5; i++) {
2449                            Data->currentMV[i].x = Data->currentQMV[i].x/2;
2450                            Data->currentMV[i].y = Data->currentQMV[i].y/2;
2451                    }
2452                    Data->qpel_precision = 1;
2453                    CheckCandidateBits16(Data->currentQMV[0].x, Data->currentQMV[0].y, 255, &iDirection, Data);
2454    
2455          static const VECTOR zeroMV={0,0};                  if (MotionFlags & (XVID_ME_HALFPELREFINE16_BITS | XVID_ME_EXTSEARCH_BITS)) { /* we have to prepare for halfpixel-precision search */
2456                            for(i = 0; i < 5; i++) bsad[i] = Data->iMinSAD[i];
2457                            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2458                                                    pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
2459                            Data->qpel_precision = 0;
2460                            if (Data->currentQMV->x & 1 || Data->currentQMV->y & 1)
2461                                    CheckCandidateBits16(Data->currentMV[0].x, Data->currentMV[0].y, 255, &iDirection, Data);
2462                    }
2463    
2464          int f_sad16;    /* forward (as usual) search */          } else { /* not qpel */
         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) */  
2465    
2466          int best_sad;                  CheckCandidateBits16(Data->currentMV[0].x, Data->currentMV[0].y, 255, &iDirection, Data);
2467            }
2468    
2469          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/          if (MotionFlags&XVID_ME_EXTSEARCH_BITS) SquareSearch(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
         VECTOR f_interpolMV, b_interpolMV;  
         VECTOR pmv_dontcare;  
2470    
2471          int min_dx, max_dx, min_dy, max_dy;          if (MotionFlags&XVID_ME_HALFPELREFINE16_BITS) SubpelRefine(Data);
         int f_min_dx, f_max_dx, f_min_dy, f_max_dy;  
         int b_min_dx, b_max_dx, b_min_dy, b_max_dy;  
2472    
2473          int f_count=0;          if (Data->qpel) {
2474          int b_count=0;                  if (MotionFlags&(XVID_ME_EXTSEARCH_BITS | XVID_ME_HALFPELREFINE16_BITS)) { /* there was halfpel-precision search */
2475          int i_count=0;                          for(i = 0; i < 5; i++) if (bsad[i] > Data->iMinSAD[i]) {
2476          int d_count=0;                                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; /* we have found a better match */
2477                                    Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
2478                            }
2479    
2480          const int64_t TRB = (int32_t)time_pp - (int32_t)time_bp;                          /* preparing for qpel-precision search */
2481      const int64_t TRD = (int32_t)time_pp;                          Data->qpel_precision = 1;
2482                            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2483                                            pParam->width, pParam->height, Data->iFcode, 1, 0);
2484                    }
2485                    if (MotionFlags&XVID_ME_QUARTERPELREFINE16_BITS) SubpelRefine(Data);
2486            }
2487    
2488          // fprintf(stderr,"TRB = %lld  TRD = %lld  time_bp =%d time_pp =%d\n\n",TRB,TRD,time_bp,time_pp);          if (MotionFlags&XVID_ME_CHECKPREDICTION_BITS) { /* let's check vector equal to prediction */
2489          // note: i==horizontal, j==vertical                  VECTOR * v = Data->qpel ? Data->currentQMV : Data->currentMV;
2490          for (j = 0; j < mb_height; j++) {                  if (!(Data->predMV.x == v->x && Data->predMV.y == v->y))
2491                            CheckCandidateBits16(Data->predMV.x, Data->predMV.y, 255, &iDirection, Data);
2492            }
2493            return Data->iMinSAD[0];
2494    }
2495    
2496                  f_predMV = zeroMV;      /* prediction is reset at left boundary */  static int
2497                  b_predMV = zeroMV;  CountMBBitsInter4v(const SearchData * const Data,
2498                                            MACROBLOCK * const pMB, const MACROBLOCK * const pMBs,
2499                                            const int x, const int y,
2500                                            const MBParam * const pParam, const uint32_t MotionFlags,
2501                                            const VECTOR * const backup)
2502    {
2503    
2504                  for (i = 0; i < mb_width; i++) {          int cbp = 0, bits = 0, t = 0, i, iDirection;
2505                          MACROBLOCK *mb = &frame->mbs[i + j * mb_width];          SearchData Data2, *Data8 = &Data2;
2506                          const MACROBLOCK *f_mb = &f_mbs[i + j * mb_width];          int sumx = 0, sumy = 0;
2507                          const MACROBLOCK *b_mb = &b_mbs[i + j * mb_width];          int16_t *in = Data->dctSpace, *coeff = Data->dctSpace + 64;
2508            uint8_t * ptr;
2509    
2510            memcpy(Data8, Data, sizeof(SearchData));
2511            CheckCandidate = CheckCandidateBits8;
2512    
2513            for (i = 0; i < 4; i++) { /* for all luma blocks */
2514    
2515                    Data8->iMinSAD = Data->iMinSAD + i + 1;
2516                    Data8->currentMV = Data->currentMV + i + 1;
2517                    Data8->currentQMV = Data->currentQMV + i + 1;
2518                    Data8->Cur = Data->Cur + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2519                    Data8->RefP[0] = Data->RefP[0] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2520                    Data8->RefP[2] = Data->RefP[2] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2521                    Data8->RefP[1] = Data->RefP[1] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2522                    Data8->RefP[3] = Data->RefP[3] + 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2523    
2524                    if(Data->qpel) {
2525                            Data8->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, i);
2526                            if (i != 0)     t = d_mv_bits(  Data8->currentQMV->x, Data8->currentQMV->y,
2527                                                                                    Data8->predMV, Data8->iFcode, 0, 0);
2528                    } else {
2529                            Data8->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, i);
2530                            if (i != 0)     t = d_mv_bits(  Data8->currentMV->x, Data8->currentMV->y,
2531                                                                                    Data8->predMV, Data8->iFcode, 0, 0);
2532                    }
2533    
2534                          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,
2535                                            pParam->width, pParam->height, Data8->iFcode, Data8->qpel, 0);
2536    
2537  /* special case, if collocated block is SKIPed: encoding is forward (0,0), cpb=0 without further ado */                  *Data8->iMinSAD += BITS_MULT*t;
2538    
2539                          if (b_mb->mode == MODE_INTER && b_mb->cbp == 0 &&                  Data8->qpel_precision = Data8->qpel;
2540                                  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) */
2541                                  mb->mode = MODE_NOT_CODED;                  {
2542                                  mb->b_mvs[0] = mb->mvs[0] = zeroMV;                          VECTOR *v = Data8->qpel ? Data8->currentQMV : Data8->currentMV;
2543                                  continue;                          if (!MVequal (*v, backup[i+1]) )
2544                                    CheckCandidateBits8(backup[i+1].x, backup[i+1].y, 255, &iDirection, Data8);
2545                          }                          }
2546    
2547                          if (b_mb->mode == MODE_INTER4V)                  if (Data8->qpel) {
2548                          {                          if (MotionFlags&XVID_ME_HALFPELREFINE8_BITS || (MotionFlags&XVID_ME_EXTSEARCH8 && MotionFlags&XVID_ME_EXTSEARCH_BITS)) { /* halfpixel motion search follows */
2549                                  d_sad16 = 0;                                  int32_t s = *Data8->iMinSAD;
2550                          /* same method of scaling as in decoder.c, so we copy from there */                                  Data8->currentMV->x = Data8->currentQMV->x/2;
2551                      for (k = 0; k < 4; k++) {                                  Data8->currentMV->y = Data8->currentQMV->y/2;
2552                                    Data8->qpel_precision = 0;
2553                                    get_range(&Data8->min_dx, &Data8->max_dx, &Data8->min_dy, &Data8->max_dy, 2*x + (i&1), 2*y + (i>>1), 8,
2554                                                            pParam->width, pParam->height, Data8->iFcode - 1, 0, 0);
2555    
2556                                          mb->directmv[k] = b_mb->mvs[k];                                  if (Data8->currentQMV->x & 1 || Data8->currentQMV->y & 1)
2557                                            CheckCandidateBits8(Data8->currentMV->x, Data8->currentMV->y, 255, &iDirection, Data8);
2558    
2559                                          mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);                                  if (MotionFlags & XVID_ME_EXTSEARCH8 && MotionFlags & XVID_ME_EXTSEARCH_BITS)
2560                      mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)                                          SquareSearch(Data8->currentMV->x, Data8->currentMV->x, Data8, 255);
2561                                                                                  ? ((TRB - TRD) * mb->directmv[k].x) / TRD  
2562                                              : mb->mvs[k].x - mb->directmv[k].x);                                  if (MotionFlags & XVID_ME_HALFPELREFINE8_BITS)
2563                                            SubpelRefine(Data8);
2564                      mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);  
2565                          mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)                                  if(s > *Data8->iMinSAD) { /* we have found a better match */
2566                                                                                  ? ((TRB - TRD) * mb->directmv[k].y) / TRD                                          Data8->currentQMV->x = 2*Data8->currentMV->x;
2567                                              : 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);  
                                 }  
2568                          }                          }
                         else  
                         {  
                                 mb->directmv[3] = mb->directmv[2] = mb->directmv[1] =  
                                         mb->directmv[0] = b_mb->mvs[0];  
2569    
2570                                  mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);                                  Data8->qpel_precision = 1;
2571                      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,
2572                                                                          ? ((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);  
2573    
2574              }              }
2575                      d_sad16 += calc_delta_16(mb->deltamv.x, mb->deltamv.y, 1, frame->quant);                          if (MotionFlags & XVID_ME_QUARTERPELREFINE8_BITS) SubpelRefine(Data8);
2576    
2577                          // 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);  
2578    
2579                            if (MotionFlags & XVID_ME_EXTSEARCH8 && MotionFlags & XVID_ME_EXTSEARCH_BITS) /* extsearch */
2580                                    SquareSearch(Data8->currentMV->x, Data8->currentMV->x, Data8, 255);
2581    
2582                          // backward search                          if (MotionFlags & XVID_ME_HALFPELREFINE8_BITS)
2583                          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;  
2584                          }                          }
2585    
2586                          if (i_sad16 < best_sad) {                  /* checking vector equal to predicion */
2587                                  best_sad = i_sad16;                  if (i != 0 && MotionFlags & XVID_ME_CHECKPREDICTION_BITS) {
2588                                  mb->mode = MODE_INTERPOLATE;                          const VECTOR * v = Data->qpel ? Data8->currentQMV : Data8->currentMV;
2589                            if (!MVequal(*v, Data8->predMV))
2590                                    CheckCandidateBits8(Data8->predMV.x, Data8->predMV.y, 255, &iDirection, Data8);
2591                          }                          }
2592    
2593                          if (d_sad16 < best_sad) {                  bits += *Data8->iMinSAD;
2594                    if (bits >= Data->iMinSAD[0]) return bits; /* no chances for INTER4V */
2595    
2596                                  if (b_mb->mode == MODE_INTER4V)                  /* MB structures for INTER4V mode; we have to set them here, we don't have predictor anywhere else */
2597                                  {                  if(Data->qpel) {
2598                            pMB->pmvs[i].x = Data8->currentQMV->x - Data8->predMV.x;
2599                            pMB->pmvs[i].y = Data8->currentQMV->y - Data8->predMV.y;
2600                            pMB->qmvs[i] = *Data8->currentQMV;
2601                            sumx += Data8->currentQMV->x/2;
2602                            sumy += Data8->currentQMV->y/2;
2603                    } else {
2604                            pMB->pmvs[i].x = Data8->currentMV->x - Data8->predMV.x;
2605                            pMB->pmvs[i].y = Data8->currentMV->y - Data8->predMV.y;
2606                            sumx += Data8->currentMV->x;
2607                            sumy += Data8->currentMV->y;
2608                    }
2609                    pMB->mvs[i] = *Data8->currentMV;
2610                    pMB->sad8[i] = 4 * *Data8->iMinSAD;
2611                    if (Data8->temp[0]) cbp |= 1 << (5 - i);
2612    
2613                                  /* 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 */  
2614    
2615                              for (k = 0; k < 4; k++) {          bits += BITS_MULT*xvid_cbpy_tab[15-(cbp>>2)].len;
2616    
2617                                                  mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);          /* let's check chroma */
2618                              mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)          sumx = (sumx >> 3) + roundtab_76[sumx & 0xf];
2619                                                                                          ? ((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);  
2620    
2621                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)          /* chroma U */
2622                                                                                  ? ((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);
2623                                          : mb->mvs[0].x - mb->directmv[0].x);          transfer_8to16subro(in, Data->CurU, ptr, Data->iEdgedWidth/2);
2624            bits += Block_CalcBits(coeff, in, Data->iQuant, Data->quant_type, &cbp, 4);
2625    
2626                              mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);          if (bits >= *Data->iMinSAD) return bits;
2627    
2628                          mb->b_mvs[0].y = (int32_t) ((mb->deltamv.y == 0)          /* chroma V */
2629                                                                                  ? ((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);
2630                                              : mb->mvs[0].y - mb->directmv[0].y);          transfer_8to16subro(in, Data->CurV, ptr, Data->iEdgedWidth/2);
2631            bits += Block_CalcBits(coeff, in, Data->iQuant, Data->quant_type, &cbp, 5);
2632    
2633                                          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];  
                 }  
2634    
2635                                  best_sad = d_sad16;          return bits;
                                 mb->mode = MODE_DIRECT;  
2636                          }                          }
2637    
2638                          switch (mb->mode)  static int
2639    CountMBBitsIntra(const SearchData * const Data)
2640                          {                          {
2641                                  case MODE_FORWARD:          int bits = BITS_MULT*1; /* this one is ac/dc prediction flag bit */
2642                                          f_count++;          int cbp = 0, i, dc = 0;
2643                                          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];  
2644    
2645                                          break;          for(i = 0; i < 4; i++) {
2646                                  case MODE_INTERPOLATE:                  int s = 8*((i&1) + (i>>1)*Data->iEdgedWidth);
2647                                          i_count++;                  transfer_8to16copy(in, Data->Cur + s, Data->iEdgedWidth);
2648                                          mb->mvs[0] = f_interpolMV;                  bits += Block_CalcBitsIntra(coeff, in, 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;  
                         }  
2649    
2650                    if (bits >= Data->iMinSAD[0]) return bits;
2651                  }                  }
         }  
2652    
2653  #ifdef _DEBUG_BFRAME_STAT          bits += BITS_MULT*xvid_cbpy_tab[cbp>>2].len;
2654          fprintf(stderr,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d\n",  
2655                                  f_count,b_count,i_count,d_count);          /*chroma U */
2656  #endif          transfer_8to16copy(in, Data->CurU, Data->iEdgedWidth/2);
2657            bits += Block_CalcBitsIntra(coeff, in, Data->iQuant, Data->quant_type, &cbp, 4, &dc);
2658    
2659            if (bits >= Data->iMinSAD[0]) return bits;
2660    
2661            /* chroma V */
2662            transfer_8to16copy(in, Data->CurV, Data->iEdgedWidth/2);
2663            bits += Block_CalcBitsIntra(coeff, in, Data->iQuant, Data->quant_type, &cbp, 5, &dc);
2664    
2665            bits += BITS_MULT*mcbpc_inter_tab[(MODE_INTRA & 7) | ((cbp & 3) << 3)].len;
2666    
2667            return bits;
2668  }  }

Legend:
Removed from v.348  
changed lines
  Added in v.1054

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