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

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

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

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

Legend:
Removed from v.167  
changed lines
  Added in v.580

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