[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 132, Tue Apr 23 00:04:51 2002 UTC branches/dev-api-3/xvidcore/src/motion/motion_est.c revision 530, Mon Sep 23 20:36:02 2002 UTC
# Line 1  Line 1 
1  /**************************************************************************  /**************************************************************************
2   *   *
3   *  Modifications:   *      XVID MPEG-4 VIDEO CODEC
4     *      motion estimation
5   *   *
6   *  22.04.2002 remove some compile warning by chenm001 <chenm001@163.com>   *      This program is an implementation of a part of one or more MPEG-4
7   *  14.04.2002 added MotionEstimationBVOP()   *      Video tools as specified in ISO/IEC 14496-2 standard.  Those intending
8   *  02.04.2002 add EPZS(^2) as ME algorithm, use PMV_USESQUARES to choose between   *      to use this software module in hardware or software products are
9   *             EPZS and EPZS^2   *      advised that its use may infringe existing patents or copyrights, and
10   *  08.02.2002 split up PMVfast into three routines: PMVFast, PMVFast_MainLoop   *      any such use would be at such party's own risk.  The original
11   *             PMVFast_Refine to support multiple searches with different start points   *      developer of this software module and his/her company, and subsequent
12   *  07.01.2002 uv-block-based interpolation   *      editors and their companies, will have no liability for use of this
13   *  06.01.2002 INTER/INTRA-decision is now done before any SEARCH8 (speedup)   *      software or modifications or derivatives thereof.
  *             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 42  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 "motion_est.h"
41  #include "motion.h"  #include "motion.h"
42  #include "sad.h"  #include "sad.h"
43    
44  // very large value  #define INITIAL_SKIP_THRESH     (10)
45  #define MV_MAX_ERROR    (4096 * 256)  #define FINAL_SKIP_THRESH       (50)
46    #define MAX_SAD00_FOR_SKIP      (20)
47  // stop search if sdelta < THRESHOLD  #define MAX_CHROMA_SAD_FOR_SKIP (18)
48  #define MV16_THRESHOLD  192  #define SKIP_THRESH_B (10)
 #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)  
   
 /* INTER bias for INTER/INTRA decision; mpeg4 spec suggests 2*nb */  
 #define INTER_BIAS      512  
49    
50  /* Parameters which control inter/inter4v decision */  #define CHECK_CANDIDATE(X,Y,D) { \
51  #define IMV16X16                        5  (*CheckCandidate)((const int)(X),(const int)(Y), (D), &iDirection, data ); }
52    
53  /* vector map (vlc delta size) smoother parameters */  #define iDiamondSize 2
 #define NEIGH_TEND_16X16        2  
 #define NEIGH_TEND_8X8          2  
54    
55    //FILE * debug;
56    
57  // fast ((A)/2)*2  static __inline int
58  #define EVEN(A)         (((A)<0?(A)+1:(A)) & ~1)  d_mv_bits(int x, int y, const uint32_t iFcode)
   
   
 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 MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         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 MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         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, int start_y,  
                                         const uint32_t MotionFlags,  
                                         const MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         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, int start_y,  
                                         const uint32_t MotionFlags,  
                                         const MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         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;  
   
   
 typedef int32_t (MainSearch8Func)(  
         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 MainSearch8Func* MainSearch8FuncPtr;  
   
 // mv.length table  
 static const uint32_t mvtab[33] = {  
     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)  
59      {      {
60                  if (component > 32)          int xb, yb;
                     component = 32;  
61    
62                  return mvtab[component] + 1;          if (x == 0) xb = 1;
63            else {
64                    if (x < 0) x = -x;
65                    x += (1 << (iFcode - 1)) - 1;
66                    x >>= (iFcode - 1);
67                    if (x > 32) x = 32;
68                    xb = mvtab[x] + iFcode;
69      }      }
70    
71      component += (1 << (iFcode - 1)) - 1;          if (y == 0) yb = 1;
72      component >>= (iFcode - 1);          else {
73                    if (y < 0) y = -y;
74      if (component > 32)                  y += (1 << (iFcode - 1)) - 1;
75                  component = 32;                  y >>= (iFcode - 1);
76                    if (y > 32) y = 32;
77      return mvtab[component] + 1 + iFcode - 1;                  yb = mvtab[y] + iFcode;
 }  
   
   
 static __inline uint32_t calc_delta_16(const int32_t dx, const int32_t dy, const uint32_t iFcode)  
 {  
         return NEIGH_TEND_16X16 * (mv_bits(dx, iFcode) + mv_bits(dy, iFcode));  
78  }  }
79            return xb + yb;
 static __inline uint32_t calc_delta_8(const int32_t dx, const int32_t dy, const uint32_t iFcode)  
   
 {  
     return NEIGH_TEND_8X8 * (mv_bits(dx, iFcode) + mv_bits(dy, iFcode));  
80  }  }
81    
82    /* CHACK_CANDIATE FUNCTIONS START */
83    
84    static void
85    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(  
         MACROBLOCK * const pMBs,  
         MBParam * const pParam,  
         const IMAGE * const pRef,  
         const IMAGE * const pRefH,  
         const IMAGE * const pRefV,  
         const IMAGE * const pRefHV,  
         IMAGE * const pCurrent,  
         const uint32_t iLimit)  
   
 {  
         const uint32_t iWcount = pParam->mb_width;  
         const uint32_t iHcount = pParam->mb_height;  
   
         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];  
   
                         sad16 = SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,  
                                          j, i, pParam->motion_flags,  
                                          pParam, pMBs, &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))  
86                          {                          {
87                                  pMB->mode = MODE_INTRA;          int32_t * const sad = data->temp;
88                                  pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = 0;  //      static int32_t sad[5];
89                                  pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = 0;          int t;
90            const uint8_t * Reference;
91    
92                                  iIntra++;          if (( x > data->max_dx) || ( x < data->min_dx)
93                                  if(iIntra >= iLimit)                  || ( y > data->max_dy) || (y < data->min_dy)) return;
                                         return 1;  
94    
95                                  continue;          switch ( ((x&1)<<1) + (y&1) ) {
96                    case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
97                    case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;
98                    case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;
99                    default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
100                          }                          }
101    
102                          if (pParam->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, pParam->motion_flags,  
                                                        pParam, pMBs, &pMB->mvs[0], &pMB->pmvs[0]);  
103    
104                                  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);
105                                                         2 * j + 1, 2 * i, mv16.x, mv16.y, pParam->motion_flags,          data->temp[0] += lambda_vec16[data->iQuant] * t;
106                                                         pParam, pMBs, &pMB->mvs[1], &pMB->pmvs[1]);          data->temp[1] += lambda_vec8[data->iQuant] * t;
107    
108                                  pMB->sad8[2] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,          if (data->temp[0] < data->iMinSAD[0]) {
109                                                         2 * j, 2 * i + 1, mv16.x, mv16.y, pParam->motion_flags,                  data->iMinSAD[0] = data->temp[0];
110                                                         pParam, pMBs, &pMB->mvs[2], &pMB->pmvs[2]);                  data->currentMV[0].x = x; data->currentMV[0].y = y;
111                    *dir = Direction; }
112    
113                                  pMB->sad8[3] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,          if (data->temp[1] < data->iMinSAD[1]) {
114                                                         2 * j + 1, 2 * i + 1, mv16.x, mv16.y, pParam->motion_flags,                  data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
115                                                         pParam, pMBs, &pMB->mvs[3], &pMB->pmvs[3]);          if (data->temp[2] < data->iMinSAD[2]) {
116                    data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
117            if (data->temp[3] < data->iMinSAD[3]) {
118                    data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
119            if (data->temp[4] < data->iMinSAD[4]) {
120                    data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
121    
                                 sad8 = pMB->sad8[0] + pMB->sad8[1] + pMB->sad8[2] + pMB->sad8[3];  
122                          }                          }
123    
124    static void
125    CheckCandidate16no4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
126    {
127            int32_t sad;
128            const uint8_t * Reference;
129    
130                          /* decide: MODE_INTER or MODE_INTER4V          if (( x > data->max_dx) || ( x < data->min_dx)
131                             mpeg4:   if (sad8 < sad16 - nb/2+1) use_inter4v                  || ( y > data->max_dy) || (y < data->min_dy)) return;
                         */  
   
                         if (pMB->dquant == NO_CHANGE) {  
                                 if (((pParam->global_flags & XVID_INTER4V)==0) ||  
                                     (sad16 < (sad8 + (int32_t)(IMV16X16 * pParam->quant)))) {  
132    
133                                          sad8 = sad16;          switch ( ((x&1)<<1) + (y&1) )
                                         pMB->mode = MODE_INTER;  
                                         pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = mv16.x;  
                                         pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = mv16.y;  
                                         pMB->pmvs[0].x = pmv16.x;  
                                         pMB->pmvs[0].y = pmv16.y;  
                                 }  
                                 else  
                                         pMB->mode = MODE_INTER4V;  
                         }  
                         else  
134                          {                          {
135                                  sad8 = sad16;                  case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
136                                  pMB->mode = MODE_INTER;                  case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;
137                                  pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = mv16.x;                  case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;
138                                  pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = mv16.y;                  default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
                                 pMB->pmvs[0].x = pmv16.x;  
                                 pMB->pmvs[0].y = pmv16.y;  
                         }  
139                  }                  }
140    
141          return 0;          sad = lambda_vec16[data->iQuant] *
142  }                          d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
143            sad += sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
 #define MVzero(A) ( ((A).x)==(0) && ((A).y)==(0) )  
   
 #define MVequal(A,B) ( ((A).x)==((B).x) && ((A).y)==((B).y) )  
144    
145            if (sad < *(data->iMinSAD)) {
146  #define CHECK_MV16_ZERO {\                  *(data->iMinSAD) = sad;
147    if ( (0 <= max_dx) && (0 >= min_dx) \                  data->currentMV[0].x = x; data->currentMV[0].y = y;
148      && (0 <= max_dy) && (0 >= min_dy) ) \                  *dir = Direction; }
   { \  
     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 <= iQuant * 96)    \  
         iSAD -= MV16_00_BIAS; \  
     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); } } \  
 }  
   
 #define CHECK_MV16_CANDIDATE_DIR(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode) * iQuant;\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \  
 }  
   
 #define CHECK_MV16_CANDIDATE_FOUND(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode) * iQuant;\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
 }  
   
   
 #define CHECK_MV8_ZERO {\  
   iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, 0, 0 , iEdgedWidth), iEdgedWidth); \  
   iSAD += calc_delta_8(-pmv[0].x, -pmv[0].y, (uint8_t)iFcode) * iQuant;\  
   if (iSAD < iMinSAD) \  
   { iMinSAD=iSAD; currMV->x=0; currMV->y=0; } \  
 }  
   
 #define NOCHECK_MV8_CANDIDATE(X,Y) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode) * iQuant;\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \  
 }  
   
 #define CHECK_MV8_CANDIDATE(X,Y) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode) * iQuant;\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV8_CANDIDATE_DIR(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode) * iQuant;\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \  
 }  
   
 #define CHECK_MV8_CANDIDATE_FOUND(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode) * iQuant;\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
149  }  }
150    
151  /* too slow and not fully functional at the moment */  static void
152  /*  CheckCandidateInt(const int xf, const int yf, 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,  
                                         MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
153  {  {
154          const int32_t iEdgedWidth = pParam->edged_width;          int32_t sad;
155          const int32_t iQuant = pParam->quant;          const int xb = data->currentMV[1].x;
156          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;          const int yb = data->currentMV[1].y;
157          int32_t iSAD;          const uint8_t *ReferenceF, *ReferenceB;
         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;  
158    
159          return iSAD;          if (( xf > data->max_dx) || ( xf < data->min_dx)
160                    || ( yf > data->max_dy) || (yf < data->min_dy)) return;
161    
162            switch ( ((xf&1)<<1) + (yf&1) ) {
163                    case 0 : ReferenceF = data->Ref + xf/2 + (yf/2)*(data->iEdgedWidth); break;
164                    case 1 : ReferenceF = data->RefV + xf/2 + ((yf-1)/2)*(data->iEdgedWidth); break;
165                    case 2 : ReferenceF = data->RefH + (xf-1)/2 + (yf/2)*(data->iEdgedWidth); break;
166                    default : ReferenceF = data->RefHV + (xf-1)/2 + ((yf-1)/2)*(data->iEdgedWidth); break;
167  }  }
 */  
168    
169  int32_t Diamond16_MainSearch(          switch ( ((xb&1)<<1) + (yb&1) ) {
170          const uint8_t * const pRef,                  case 0 : ReferenceB = data->bRef + xb/2 + (yb/2)*(data->iEdgedWidth); break;
171          const uint8_t * const pRefH,                  case 1 : ReferenceB = data->bRefV + xb/2 + ((yb-1)/2)*(data->iEdgedWidth); break;
172          const uint8_t * const pRefV,                  case 2 : ReferenceB = data->bRefH + (xb-1)/2 + (yb/2)*(data->iEdgedWidth); break;
173          const uint8_t * const pRefHV,                  default : ReferenceB = data->bRefHV + (xb-1)/2 + ((yb-1)/2)*(data->iEdgedWidth); break;
         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);  
174                  }                  }
         else  
         {  
                 currMV->x = startx;  
                 currMV->y = starty;  
         }  
         return iMinSAD;  
 }  
   
 int32_t Square16_MainSearch(  
                                         const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x, const int y,  
                                         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);  
175    
176          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);          sad = lambda_vec16[data->iQuant] *
177          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);                          ( d_mv_bits(xf - data->predMV.x, yf - data->predMV.y, data->iFcode) +
178          CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);                            d_mv_bits(xb - data->bpredMV.x, yb - data->bpredMV.y, data->iFcode) );
         CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);  
179    
180            sad += sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
181    
182          if (iDirection)          if (sad < *(data->iMinSAD)) {
183                  while (!iFound)                  *(data->iMinSAD) = sad;
184                  {                  data->currentMV->x = xf; data->currentMV->y = yf;
185                          iFound = 1;                  *dir = Direction; }
186                          backupMV=*currMV;  }
187    
188                          switch (iDirection)  static void
189    CheckCandidateDirect(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
190                          {                          {
191                                  case 1:          int32_t sad;
192                                          CHECK_MV16_CANDIDATE_FOUND(backupMV.x-iDiamondSize,backupMV.y,1);          int k;
193                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);          const uint8_t *ReferenceF;
194                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);          const uint8_t *ReferenceB;
195                                          break;          VECTOR mvs, b_mvs;
                                 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;  
196    
197                                  case 3:          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
                                         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;  
198    
199                                  case 4:          sad = lambda_vec16[data->iQuant] * d_mv_bits(x, 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);  
                                         break;  
200    
201                                  case 5:          for (k = 0; k < 4; k++) {
202                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y,1);                  mvs.x = data->directmvF[k].x + x;
203                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);                  b_mvs.x = ((x == 0) ?
204                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y-iDiamondSize,5);                          data->directmvB[k].x
205                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);                          : mvs.x - data->referencemv[k].x);
                                         CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);  
                                         break;  
206    
207                                  case 6:                  mvs.y = data->directmvF[k].y + y;
208                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);                  b_mvs.y = ((y == 0) ?
209                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);                          data->directmvB[k].y
210                            : mvs.y - data->referencemv[k].y);
                                         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,8);  
211    
212                                          break;                  if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
213                            || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
214                                  case 7:                          || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
215                                          CHECK_MV16_CANDIDATE_FOUND(backupMV.x-iDiamondSize,backupMV.y,1);                          || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
                                         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,7);  
                                         CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);  
                                         break;  
216    
217                                  case 8:                  switch ( ((mvs.x&1)<<1) + (mvs.y&1) ) {
218                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);                          case 0 : ReferenceF = data->Ref + mvs.x/2 + (mvs.y/2)*(data->iEdgedWidth); break;
219                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);                          case 1 : ReferenceF = data->RefV + mvs.x/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
220                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y+iDiamondSize,6);                          case 2 : ReferenceF = data->RefH + (mvs.x-1)/2 + (mvs.y/2)*(data->iEdgedWidth); break;
221                                          CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y-iDiamondSize,7);                          default : ReferenceF = data->RefHV + (mvs.x-1)/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
                                         CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y+iDiamondSize,8);  
                                         break;  
                         default:  
                                         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);  
                                         break;  
222                          }                          }
                 }  
         else  
                 {  
                         currMV->x = startx;  
                         currMV->y = starty;  
                 }  
         return iMinSAD;  
 }  
   
   
 int32_t Full16_MainSearch(  
                                         const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x, const int y,  
                                         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);  
223    
224          return iMinSAD;                  switch ( ((b_mvs.x&1)<<1) + (b_mvs.y&1) ) {
225                            case 0 : ReferenceB = data->bRef + b_mvs.x/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
226                            case 1 : ReferenceB = data->bRefV + b_mvs.x/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
227                            case 2 : ReferenceB = data->bRefH + (b_mvs.x-1)/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
228                            default : ReferenceB = data->bRefHV + (b_mvs.x-1)/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
229  }  }
230    
231  int32_t Full8_MainSearch(                  sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
232                                          const uint8_t * const pRef,                                                  ReferenceF + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
233                                          const uint8_t * const pRefH,                                                  ReferenceB + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
234                                          const uint8_t * const pRefV,                                                  data->iEdgedWidth);
235                                          const uint8_t * const pRefHV,                  if (sad > *(data->iMinSAD)) return;
                                         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;  
236  }  }
237    
238            if (sad < *(data->iMinSAD)) {
239                    *(data->iMinSAD) = sad;
240  int32_t Halfpel16_Refine(                  data->currentMV->x = x; data->currentMV->y = y;
241          const uint8_t * const pRef,                  *dir = Direction; }
         const uint8_t * const pRefH,  
         const uint8_t * const pRefV,  
         const uint8_t * const pRefHV,  
         const uint8_t * const cur,  
         const int x, const int y,  
         VECTOR * const currMV,  
         int32_t iMinSAD,  
         const VECTOR * const pmv,  
         const int32_t min_dx, const int32_t max_dx,  
         const int32_t min_dy, const int32_t max_dy,  
         const int32_t iFcode,  
         const int32_t iQuant,  
         const int32_t iEdgedWidth)  
 {  
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
   
         int32_t iSAD;  
         VECTOR backupMV = *currMV;  
   
         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);  
         CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y+1);  
         CHECK_MV16_CANDIDATE(backupMV.x  ,backupMV.y+1);  
         CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y+1);  
   
         return iMinSAD;  
242  }  }
243    
244  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)  static void
245    CheckCandidateDirectno4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
   
 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 MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
 {  
     const uint32_t iWcount = pParam->mb_width;  
         const int32_t iFcode = pParam->fixed_code;  
         const int32_t iQuant = pParam->quant;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
   
         const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;  
   
         int32_t iDiamondSize;  
   
         int32_t min_dx;  
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
   
         int32_t iFound;  
   
         VECTOR newMV;  
         VECTOR backupMV;        /* just for PMVFAST */  
   
         VECTOR pmv[4];  
         int32_t psad[4];  
   
         MACROBLOCK * const pMB = pMBs + x + y * iWcount;  
   
         static int32_t threshA,threshB;  
         int32_t bPredEq;  
         int32_t iMinSAD,iSAD;  
   
 /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy,  
                   x, y, 16, iWidth, iHeight, iFcode);  
   
 /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  
   
         if (!(MotionFlags & PMV_HALFPEL16 ))  
         { min_dx = EVEN(min_dx);  
         max_dx = EVEN(max_dx);  
         min_dy = EVEN(min_dy);  
         max_dy = EVEN(max_dy);  
         }               /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
   
   
         bPredEq  = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  
   
         if ((x==0) && (y==0) )  
         {  
                 threshA =  512;  
                 threshB = 1024;  
   
         }  
         else  
246          {          {
247                  threshA = psad[0];          int32_t sad;
248                  threshB = threshA+256;          const uint8_t *ReferenceF;
249                  if (threshA< 512) threshA =  512;          const uint8_t *ReferenceB;
250                  if (threshA>1024) threshA = 1024;          VECTOR mvs, b_mvs;
                 if (threshB>1792) threshB = 1792;  
         }  
   
         iFound=0;  
   
 /* Step 2: Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  
    vector of the median.  
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
   
         if ((bPredEq) && (MVequal(pmv[0],pMB->mvs[0]) ) )  
                 iFound=2;  
251    
252  /* Step 3: If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          if (( x > 31) || ( x < -31) || ( y > 31) || (y < -31)) return;
    Otherwise select large Diamond Search.  
 */  
   
         if ( (pmv[0].x != 0) || (pmv[0].y != 0) || (threshB<1536) || (bPredEq) )  
                 iDiamondSize=1; // halfpel!  
         else  
                 iDiamondSize=2; // halfpel!  
253    
254          if (!(MotionFlags & PMV_HALFPELDIAMOND16) )                  sad = lambda_vec16[data->iQuant] * d_mv_bits(x, y, 1);
                 iDiamondSize*=2;  
255    
256  /* Step 4: Calculate SAD around the Median prediction.          mvs.x = data->directmvF[0].x + x;
257     MinSAD=SAD          b_mvs.x = ((x == 0) ?
258     If Motion Vector equal to Previous frame motion vector                  data->directmvB[0].x
259     and MinSAD<PrevFrmSAD goto Step 10.                  : mvs.x - data->referencemv[0].x);
    If SAD<=256 goto Step 10.  
 */  
260    
261            mvs.y = data->directmvF[0].y + y;
262            b_mvs.y = ((y == 0) ?
263                    data->directmvB[0].y
264                    : mvs.y - data->referencemv[0].y);
265    
266  // Prepare for main loop          if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
267                    || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
268                    || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
269                    || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
270    
271          *currMV=pmv[0];         /* current best := prediction */          switch ( ((mvs.x&1)<<1) + (mvs.y&1) ) {
272          if (!(MotionFlags & PMV_HALFPEL16 ))                  case 0 : ReferenceF = data->Ref + mvs.x/2 + (mvs.y/2)*(data->iEdgedWidth); break;
273          {       /* This should NOT be necessary! */                  case 1 : ReferenceF = data->RefV + mvs.x/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
274                  currMV->x = EVEN(currMV->x);                  case 2 : ReferenceF = data->RefH + (mvs.x-1)/2 + (mvs.y/2)*(data->iEdgedWidth); break;
275                  currMV->y = EVEN(currMV->y);                  default : ReferenceF = data->RefHV + (mvs.x-1)/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
276          }          }
277    
278          if (currMV->x > max_dx)          switch ( ((b_mvs.x&1)<<1) + (b_mvs.y&1) ) {
279          {                  case 0 : ReferenceB = data->bRef + b_mvs.x/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
280                  currMV->x=max_dx;                  case 1 : ReferenceB = data->bRefV + b_mvs.x/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
281          }                  case 2 : ReferenceB = data->bRefH + (b_mvs.x-1)/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
282          if (currMV->x < min_dx)                  default : ReferenceB = data->bRefHV + (b_mvs.x-1)/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
         {  
                 currMV->x=min_dx;  
         }  
         if (currMV->y > max_dy)  
         {  
                 currMV->y=max_dy;  
         }  
         if (currMV->y < min_dy)  
         {  
                 currMV->y=min_dy;  
283          }          }
284    
285          iMinSAD = sad16( cur,          sad += sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
                          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;  
   
         if ( (iMinSAD < 256 ) || ( (MVequal(*currMV,pMB->mvs[0])) && ((uint32_t)iMinSAD < pMB->sad16) ) )  
         {  
286    
287                  if (MotionFlags & PMV_QUICKSTOP16)          if (sad < *(data->iMinSAD)) {
288                          goto PMVfast16_Terminate_without_Refine;                  *(data->iMinSAD) = sad;
289                  if (MotionFlags & PMV_EARLYSTOP16)                  data->currentMV->x = x; data->currentMV->y = y;
290                          goto PMVfast16_Terminate_with_Refine;                  *dir = Direction; }
291          }          }
292    
293  /*  static void
294     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
    Also calculate (0,0) but do not subtract offset.  
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset. ******** WHAT'S THIS 'OFFSET' ??? ***********  
 */  
   
 // (0,0) is always possible  
   
         CHECK_MV16_ZERO;  
   
 // previous frame MV is always possible  
         CHECK_MV16_CANDIDATE(pMB->mvs[0].x,pMB->mvs[0].y);  
   
 // left neighbour, if allowed  
         if (x != 0)  
295          {          {
296                  if (!(MotionFlags & PMV_HALFPEL16 ))          int32_t sad;
297                  {       pmv[1].x = EVEN(pmv[1].x);          const uint8_t * Reference;
                 pmv[1].y = EVEN(pmv[1].y);  
                 }  
                 CHECK_MV16_CANDIDATE(pmv[1].x,pmv[1].y);  
         }  
298    
299  // top neighbour, if allowed          if (( x > data->max_dx) || ( x < data->min_dx)
300          if (y != 0)                  || ( y > data->max_dy) || (y < data->min_dy)) return;
         {  
                 if (!(MotionFlags & PMV_HALFPEL16 ))  
                 {       pmv[2].x = EVEN(pmv[2].x);  
                 pmv[2].y = EVEN(pmv[2].y);  
                 }  
                 CHECK_MV16_CANDIDATE(pmv[2].x,pmv[2].y);  
301    
302  // top right neighbour, if allowed          switch ( ((x&1)<<1) + (y&1) )
                 if ((uint32_t)x != (iWcount-1))  
303                  {                  {
304                          if (!(MotionFlags & PMV_HALFPEL16 ))                  case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
305                          {       pmv[3].x = EVEN(pmv[3].x);                  case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;
306                          pmv[3].y = EVEN(pmv[3].y);                  case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;
307                          }                  default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
                         CHECK_MV16_CANDIDATE(pmv[3].x,pmv[3].y);  
                 }  
308          }          }
309    
310  /* Step 6: If MinSAD <= thresa goto Step 10.          sad = sad8(data->Cur, Reference, data->iEdgedWidth);
311     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.          sad += lambda_vec8[data->iQuant] * d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
 */  
312    
313          if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[0]) && ((uint32_t)iMinSAD < pMB->sad16) ) )          if (sad < *(data->iMinSAD)) {
314          {                  *(data->iMinSAD) = sad;
315                  if (MotionFlags & PMV_QUICKSTOP16)                  data->currentMV->x = x; data->currentMV->y = y;
316                          goto PMVfast16_Terminate_without_Refine;                  *dir = Direction; }
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
317          }          }
318    
319    /* CHACK_CANDIATE FUNCTIONS END */
320    
321  /************ (Diamond Search)  **************/  /* MAINSEARCH FUNCTIONS START */
 /*  
    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.  
 */  
   
         backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */  
   
 /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  
         iSAD = Diamond16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,  
                                           x, y,  
                                           currMV->x, currMV->y, iMinSAD, &newMV,  
                                           pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);  
   
         if (iSAD < iMinSAD)  
         {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
322    
323          if (MotionFlags & PMV_EXTSEARCH16)  static void
324    AdvDiamondSearch(int x, int y, const SearchData * const data, int bDirection)
325          {          {
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
326    
327                  if (!(MVequal(pmv[0],backupMV)) )  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
                 {       iSAD = Diamond16_MainSearch(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, iDiamondSize, iFcode, iQuant, iFound);  
328    
329                  if (iSAD < iMinSAD)                  int iDirection;
                 {  
                         *currMV = newMV;  
                         iMinSAD = iSAD;  
                 }  
                 }  
330    
331                  if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )                  do {
332                  {       iSAD = Diamond16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,                          iDirection = 0;
333                                                            x, y,                          if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
334                                                            0, 0, iMinSAD, &newMV,                          if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
335                                                            pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);                          if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
336                            if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
337    
338                  if (iSAD < iMinSAD)                          /* now we're doing diagonal checks near our candidate */
                 {  
                         *currMV = newMV;  
                         iMinSAD = iSAD;  
                 }  
                 }  
         }  
339    
340  /*                          if (iDirection) {               //checking if anything found
341     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.                                  bDirection = iDirection;
342  */                                  iDirection = 0;
343                                    x = data->currentMV->x; y = data->currentMV->y;
344  PMVfast16_Terminate_with_Refine:                                  if (bDirection & 3) {   //our candidate is left or right
345          if (MotionFlags & PMV_HALFPELREFINE16)          // perform final half-pel step                                          CHECK_CANDIDATE(x, y + iDiamondSize, 8);
346                  iMinSAD = Halfpel16_Refine( pRef, pRefH, pRefV, pRefHV, cur,                                          CHECK_CANDIDATE(x, y - iDiamondSize, 4);
347                                    x, y,                                  } else {                        // what remains here is up or down
348                                    currMV, iMinSAD,                                          CHECK_CANDIDATE(x + iDiamondSize, y, 2);
349                                    pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);                                          CHECK_CANDIDATE(x - iDiamondSize, y, 1); }
350    
351  PMVfast16_Terminate_without_Refine:                                  if (iDirection) {
352          currPMV->x = currMV->x - pmv[0].x;                                          bDirection += iDirection;
353          currPMV->y = currMV->y - pmv[0].y;                                          x = data->currentMV->x; y = data->currentMV->y; }
354          return iMinSAD;                          } else {                                //about to quit, eh? not so fast....
355                                    switch (bDirection) {
356                                    case 2:
357                                            CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
358                                            CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
359                                            break;
360                                    case 1:
361                                            CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
362                                            CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
363                                            break;
364                                    case 2 + 4:
365                                            CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
366                                            CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
367                                            CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
368                                            break;
369                                    case 4:
370                                            CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
371                                            CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
372                                            break;
373                                    case 8:
374                                            CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
375                                            CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
376                                            break;
377                                    case 1 + 4:
378                                            CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
379                                            CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
380                                            CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
381                                            break;
382                                    case 2 + 8:
383                                            CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
384                                            CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
385                                            CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
386                                            break;
387                                    case 1 + 8:
388                                            CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
389                                            CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
390                                            CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
391                                            break;
392                                    default:                //1+2+4+8 == we didn't find anything at all
393                                            CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
394                                            CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
395                                            CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
396                                            CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
397                                            break;
398  }  }
399                                    if (!iDirection) break;         //ok, the end. really
400                                    bDirection = iDirection;
401                                    x = data->currentMV->x; y = data->currentMV->y;
   
   
   
 int32_t Diamond8_MainSearch(  
         const uint8_t * const pRef,  
         const uint8_t * const pRefH,  
         const uint8_t * const pRefV,  
         const uint8_t * const pRefHV,  
         const uint8_t * const cur,  
         const int x, const int y,  
         int32_t startx, int32_t starty,  
         int32_t iMinSAD,  
         VECTOR * const currMV,  
         const VECTOR * const pmv,  
         const int32_t min_dx, const int32_t max_dx,  
         const int32_t min_dy, const int32_t max_dy,  
         const int32_t iEdgedWidth,  
         const int32_t iDiamondSize,  
         const int32_t iFcode,  
         const int32_t iQuant,  
         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iDirection=0;  
         int32_t iSAD;  
         VECTOR backupMV;  
         backupMV.x = startx;  
         backupMV.y = starty;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         CHECK_MV8_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y,1);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);  
   
         if (iDirection)  
                 while (!iFound)  
                 {  
                         iFound = 1;  
                         backupMV=*currMV;       // since iDirection!=0, this is well defined!  
   
                         if ( iDirection != 2)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x-iDiamondSize,backupMV.y,1);  
                         if ( iDirection != 1)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x+iDiamondSize,backupMV.y,2);  
                         if ( iDirection != 4)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,backupMV.y-iDiamondSize,3);  
                         if ( iDirection != 3)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,backupMV.y+iDiamondSize,4);  
402                  }                  }
         else  
         {  
                 currMV->x = startx;  
                 currMV->y = starty;  
403          }          }
404          return iMinSAD;                  while (1);                              //forever
405  }  }
406    
407  int32_t Halfpel8_Refine(  static void
408          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)  
409  {  {
410  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */          int iDirection;
   
         int32_t iSAD;  
         VECTOR backupMV = *currMV;  
411    
412          CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y-1);          do {
413          CHECK_MV8_CANDIDATE(backupMV.x  ,backupMV.y-1);                  iDirection = 0;
414          CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y-1);                  if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);
415          CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y);                  if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);
416          CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y);                  if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);
417          CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y+1);                  if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128);
418          CHECK_MV8_CANDIDATE(backupMV.x  ,backupMV.y+1);                  if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64);
419          CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y+1);                  if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128);
420                    if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128);
421                    if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128);
422    
423          return iMinSAD;                  bDirection = iDirection;
424                    x = data->currentMV->x; y = data->currentMV->y;
425            } while (iDirection);
426  }  }
427    
428    static void
429    DiamondSearch(int x, int y, const SearchData * const data, int bDirection)
430    {
431    
432  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
433    
434  int32_t PMVfastSearch8(                  int iDirection;
                                         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, int start_y,  
                                         const uint32_t MotionFlags,  
                                         const MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
 {  
         const uint32_t iWcount = pParam->mb_width;  
   
         const int32_t iFcode = pParam->fixed_code;  
         const int32_t iQuant = pParam->quant;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
435    
436          const uint8_t * cur = pCur->y + x*8 + y*8*iEdgedWidth;                  do {
437                            iDirection = 0;
438                            if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
439                            if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
440                            if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
441                            if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
442    
443          int32_t iDiamondSize;                          /* now we're doing diagonal checks near our candidate */
444    
445          int32_t min_dx;                          if (iDirection) {               //checking if anything found
446          int32_t max_dx;                                  bDirection = iDirection;
447          int32_t min_dy;                                  iDirection = 0;
448          int32_t max_dy;                                  x = data->currentMV->x; y = data->currentMV->y;
449                                    if (bDirection & 3) {   //our candidate is left or right
450                                            CHECK_CANDIDATE(x, y + iDiamondSize, 8);
451                                            CHECK_CANDIDATE(x, y - iDiamondSize, 4);
452                                    } else {                        // what remains here is up or down
453                                            CHECK_CANDIDATE(x + iDiamondSize, y, 2);
454                                            CHECK_CANDIDATE(x - iDiamondSize, y, 1); }
455    
456          VECTOR pmv[4];                                  bDirection += iDirection;
457          int32_t psad[4];                                  x = data->currentMV->x; y = data->currentMV->y;
458          VECTOR newMV;                          }
459          VECTOR backupMV;                  }
460                    while (iDirection);
461    }
462    
463          MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;  /* MAINSEARCH FUNCTIONS END */
464    
465          static int32_t threshA,threshB;  /* HALFPELREFINE COULD BE A MAINSEARCH FUNCTION, BUT THERE IS NO NEED FOR IT */
         int32_t iFound,bPredEq;  
         int32_t iMinSAD,iSAD;  
466    
467          int32_t iSubBlock = ((y&1)<<1) + (x&1);  static void
468    HalfpelRefine(const SearchData * const data)
469    {
470    /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */
471    
472  /* Get maximum range */          VECTOR backupMV = *(data->currentMV);
473          get_range(&min_dx, &max_dx, &min_dy, &max_dy,          int iDirection; //not needed
                   x, y, 8, iWidth, iHeight, iFcode);  
474    
475  /* we work with abs. MVs, not relative to prediction, so range is relative to 0,0 */          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y - 1, 0);
476            CHECK_CANDIDATE(backupMV.x + 1, backupMV.y - 1, 0);
477            CHECK_CANDIDATE(backupMV.x - 1, backupMV.y + 1, 0);
478            CHECK_CANDIDATE(backupMV.x + 1, backupMV.y + 1, 0);
479    
480          if (!(MotionFlags & PMV_HALFPELDIAMOND8 ))          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y, 0);
481          { min_dx = EVEN(min_dx);          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y, 0);
         max_dx = EVEN(max_dx);  
         min_dy = EVEN(min_dy);  
         max_dy = EVEN(max_dy);  
         }               /* because we might use IF (dx>max_dx) THEN dx=max_dx; */  
482    
483            CHECK_CANDIDATE(backupMV.x, backupMV.y + 1, 0);
484            CHECK_CANDIDATE(backupMV.x, backupMV.y - 1, 0);
485    }
486    
487          bPredEq  = get_pmvdata(pMBs, (x>>1), (y>>1), iWcount, iSubBlock, pmv, psad);  static __inline int
488    SkipDecisionP(const IMAGE * current, const IMAGE * reference,
489                                                            const int x, const int y,
490                                                            const uint32_t iEdgedWidth, const uint32_t iQuant)
491    
         if ((x==0) && (y==0) )  
492          {          {
493                  threshA =  512/4;  /*      keep repeating checks for all b-frames before this P frame,
494                  threshB = 1024/4;          to make sure that SKIP is possible (todo)
495            how: if skip is not possible set sad00 to a very high value */
496    
497            uint32_t sadC = sad8(current->u + x*8 + y*(iEdgedWidth/2)*8,
498                                            reference->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2);
499            if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
500            sadC += sad8(current->v + x*8 + y*(iEdgedWidth/2)*8,
501                                            reference->v + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2);
502            if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
503    
504            return 1;
505          }          }
506          else  
507    static __inline void
508    SkipMacroblockP(MACROBLOCK *pMB, const int32_t sad)
509          {          {
510                  threshA = psad[0]/4;                    /* good estimate */          pMB->mode = MODE_NOT_CODED;
511                  threshB = threshA+256/4;          pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = pMB->mv16.x = 0;
512                  if (threshA< 512/4) threshA =  512/4;          pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = pMB->mv16.y = 0;
513                  if (threshA>1024/4) threshA = 1024/4;          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
                 if (threshB>1792/4) threshB = 1792/4;  
514          }          }
515    
516          iFound=0;  bool
517    MotionEstimation(MBParam * const pParam,
518  /* Step 2: Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion                                   FRAMEINFO * const current,
519     vector of the median.                                   FRAMEINFO * const reference,
520     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2                                   const IMAGE * const pRefH,
521  */                                   const IMAGE * const pRefV,
522                                     const IMAGE * const pRefHV,
523          if ((bPredEq) && (MVequal(pmv[0],pMB->mvs[iSubBlock]) ) )                                   const uint32_t iLimit)
524                  iFound=2;  {
525            MACROBLOCK *const pMBs = current->mbs;
526  /* Step 3: If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          const IMAGE *const pCurrent = &current->image;
527     Otherwise select large Diamond Search.          const IMAGE *const pRef = &reference->image;
 */  
528    
529          if ( (pmv[0].x != 0) || (pmv[0].y != 0) || (threshB<1536/4) || (bPredEq) )          const VECTOR zeroMV = { 0, 0 };
                 iDiamondSize=1; // 1 halfpel!  
         else  
                 iDiamondSize=2; // 2 halfpel = 1 full pixel!  
530    
531          if (!(MotionFlags & PMV_HALFPELDIAMOND8) )          uint32_t x, y;
532                  iDiamondSize*=2;          uint32_t iIntra = 0;
533            int32_t InterBias;
534    
535  /* Step 4: Calculate SAD around the Median prediction.          if (sadInit) (*sadInit) ();
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
536    
537            for (y = 0; y < pParam->mb_height; y++) {
538                    for (x = 0; x < pParam->mb_width; x++)  {
539    
540  // Prepare for main loop                          MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
541                            int32_t sad00 =  pMB->sad16
542                                    = sad16v(pCurrent->y + (x + y * pParam->edged_width) * 16,
543                                                            pRef->y + (x + y * pParam->edged_width) * 16,
544                                                            pParam->edged_width, pMB->sad8 );
545    
546          currMV->x=start_x;              /* start with mv16 */                          if (!(current->global_flags & XVID_LUMIMASKING)) {
547          currMV->y=start_y;                                  pMB->dquant = NO_CHANGE;
548                                    pMB->quant = current->quant; }
549    
550          iMinSAD = sad8( cur,  //initial skip decision
                         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;  
551    
552          if ( (iMinSAD < 256/4 ) || ( (MVequal(*currMV,pMB->mvs[iSubBlock])) && ((uint32_t)iMinSAD < pMB->sad8[iSubBlock]) ) )                          if ((pMB->dquant == NO_CHANGE) && (sad00 <= MAX_SAD00_FOR_SKIP * pMB->quant)
553          {                                  && (SkipDecisionP(pCurrent, pRef, x, y, pParam->edged_width, pMB->quant)) ) {
554                  if (MotionFlags & PMV_QUICKSTOP16)                                  if (pMB->sad16 < pMB->quant * INITIAL_SKIP_THRESH) {
555                          goto PMVfast8_Terminate_without_Refine;                                                  SkipMacroblockP(pMB, sad00);
556                  if (MotionFlags & PMV_EARLYSTOP16)                                                  continue;
                         goto PMVfast8_Terminate_with_Refine;  
557          }          }
558                            } else sad00 = 256*4096; // skip not allowed - for final skip decision
559    
560                            SearchP(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
561                                                    y, current->motion_flags, pMB->quant,
562                                                    current->fcode, pParam, pMBs, reference->mbs,
563                                                    current->global_flags & XVID_INTER4V, pMB);
564    
565    /* final skip decision, a.k.a. "the vector you found, really that good?" */
566                            if (sad00 < pMB->quant * MAX_SAD00_FOR_SKIP)
567                                    if ((100*pMB->sad16)/(sad00+1) > FINAL_SKIP_THRESH)
568                                    { SkipMacroblockP(pMB, sad00); continue; }
569    
570  /*  /* finally, intra decision */
    Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  
    Also calculate (0,0) but do not subtract offset.  
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset. ******** WHAT'S THIS 'OFFSET' ??? ***********  
 */  
   
 // the prediction might be even better than mv16  
         CHECK_MV8_CANDIDATE(pmv[0].x,pmv[0].y);  
   
 // (0,0) is always possible  
         CHECK_MV8_ZERO;  
571    
572  // previous frame MV is always possible                          InterBias = MV16_INTER_BIAS;
573          CHECK_MV8_CANDIDATE(pMB->mvs[iSubBlock].x,pMB->mvs[iSubBlock].y);                          if (pMB->quant > 8)  InterBias += 50 * (pMB->quant - 8); // to make high quants work
574                            if (y != 0)
575                                    if ((pMB - pParam->mb_width)->mode == MODE_INTER ) InterBias -= 50;
576                            if (x != 0)
577                                    if ((pMB - 1)->mode == MODE_INTER ) InterBias -= 50;
578    
579  // left neighbour, if allowed                          if (InterBias < pMB->sad16)  {
580          if (psad[1] != MV_MAX_ERROR)                                  const int32_t deviation =
581          {                                          dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,
582                  if (!(MotionFlags & PMV_HALFPEL8 ))                                                    pParam->edged_width);
                 {       pmv[1].x = EVEN(pmv[1].x);  
                 pmv[1].y = EVEN(pmv[1].y);  
                 }  
                 CHECK_MV8_CANDIDATE(pmv[1].x,pmv[1].y);  
         }  
583    
584  // top neighbour, if allowed                                  if (deviation < (pMB->sad16 - InterBias)) {
585          if (psad[2] != MV_MAX_ERROR)                                          if (++iIntra >= iLimit) return 1;
586          {                                          pMB->mode = MODE_INTRA;
587                  if (!(MotionFlags & PMV_HALFPEL8 ))                                          pMB->mv16 = pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =
588                  {       pmv[2].x = EVEN(pmv[2].x);                                                  pMB->mvs[3] = zeroMV;
589                  pmv[2].y = EVEN(pmv[2].y);                                          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =
590                                                    pMB->sad8[3] = 0;
591                  }                  }
                 CHECK_MV8_CANDIDATE(pmv[2].x,pmv[2].y);  
   
 // top right neighbour, if allowed  
                 if (psad[3] != MV_MAX_ERROR)  
                 {  
                         if (!(MotionFlags & PMV_HALFPEL8 ))  
                         {       pmv[3].x = EVEN(pmv[3].x);  
                         pmv[3].y = EVEN(pmv[3].y);  
592                          }                          }
                         CHECK_MV8_CANDIDATE(pmv[3].x,pmv[3].y);  
593                  }                  }
594          }          }
595            return 0;
 /* Step 6: If MinSAD <= thresa goto Step 10.  
    If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
 */  
   
         if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[iSubBlock]) && ((uint32_t)iMinSAD < pMB->sad8[iSubBlock]) ) )  
         {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
596          }          }
597    
 /************ (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.  
 */  
   
         backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */  
598    
599  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)
         iSAD = Diamond8_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,  
                                          x, y,  
                                          currMV->x, currMV->y, iMinSAD, &newMV,  
                                          pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);  
600    
601          if (iSAD < iMinSAD)  static __inline int
602    make_mask(const VECTOR * const pmv, const int i)
603          {          {
604                  *currMV = newMV;          int mask = 0xFF, j;
605                  iMinSAD = iSAD;          for (j = 0; j < i; j++) {
606                    if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already
607                    if (pmv[i].x == pmv[j].x) {
608                            if (pmv[i].y == pmv[j].y + iDiamondSize) { mask &= ~4; continue; }
609                            if (pmv[i].y == pmv[j].y - iDiamondSize) { mask &= ~8; continue; }
610                    } else
611                            if (pmv[i].y == pmv[j].y) {
612                                    if (pmv[i].x == pmv[j].x + iDiamondSize) { mask &= ~1; continue; }
613                                    if (pmv[i].x == pmv[j].x - iDiamondSize) { mask &= ~2; continue; }
614                            }
615            }
616            return mask;
617          }          }
618    
619          if (MotionFlags & PMV_EXTSEARCH8)  static __inline void
620    PreparePredictionsP(VECTOR * const pmv, int x, int y, const int iWcount,
621                            const int iHcount, const MACROBLOCK * const prevMB)
622          {          {
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
   
                 if (!(MVequal(pmv[0],backupMV)) )  
                 {       iSAD = Diamond16_MainSearch(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, iDiamondSize, iFcode, iQuant, iFound);  
623    
624                  if (iSAD < iMinSAD)  //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself
                 {  
                         *currMV = newMV;  
                         iMinSAD = iSAD;  
                 }  
                 }  
625    
626                  if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )          if ( (y != 0) && (x != (iWcount-1)) ) {         // [5] top-right neighbour
627                  {       iSAD = Diamond16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,                  pmv[5].x = EVEN(pmv[3].x);
628                                                            x, y,                  pmv[5].y = EVEN(pmv[3].y); }
629                                                            0, 0, iMinSAD, &newMV,          else pmv[5].x = pmv[5].y = 0;
                                                           pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);  
630    
631                  if (iSAD < iMinSAD)          if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }// pmv[3] is left neighbour
632                  {          else pmv[3].x = pmv[3].y = 0;
                         *currMV = newMV;  
                         iMinSAD = iSAD;  
                 }  
                 }  
         }  
633    
634  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.          if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }// [4] top neighbour
635     By performing an optional local half-pixel search, we can refine this result even further.      else pmv[4].x = pmv[4].y = 0;
 */  
636    
637  PMVfast8_Terminate_with_Refine:          // [1] median prediction
638          if (MotionFlags & PMV_HALFPELREFINE8)           // perform final half-pel step          pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
                 iMinSAD = Halfpel8_Refine( pRef, pRefH, pRefV, pRefHV, cur,  
                                                  x, y,  
                                                  currMV, iMinSAD,  
                                                  pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);  
639    
640            pmv[0].x = pmv[0].y = 0; // [0] is zero; not used in the loop (checked before) but needed here for make_mask
641    
642  PMVfast8_Terminate_without_Refine:          pmv[2].x = EVEN(prevMB->mvs[0].x); // [2] is last frame
643          currPMV->x = currMV->x - pmv[0].x;          pmv[2].y = EVEN(prevMB->mvs[0].y);
         currPMV->y = currMV->y - pmv[0].y;  
644    
645          return iMinSAD;          if ((x != iWcount-1) && (y != iHcount-1)) {
646                    pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); //[6] right-down neighbour in last frame
647                    pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y); }
648            else pmv[6].x = pmv[6].y = 0;
649  }  }
650    
651  int32_t EPZSSearch16(  static void
652                                          const uint8_t * const pRef,  SearchP(const uint8_t * const pRef,
653                                          const uint8_t * const pRefH,                                          const uint8_t * const pRefH,
654                                          const uint8_t * const pRefV,                                          const uint8_t * const pRefV,
655                                          const uint8_t * const pRefHV,                                          const uint8_t * const pRefHV,
656                                          const IMAGE * const pCur,                                          const IMAGE * const pCur,
657                                          const int x, const int y,                  const int x,
658                    const int y,
659                                          const uint32_t MotionFlags,                                          const uint32_t MotionFlags,
660                    const uint32_t iQuant,
661                    const uint32_t iFcode,
662                                          const MBParam * const pParam,                                          const MBParam * const pParam,
663                                          MACROBLOCK * const pMBs,                  const MACROBLOCK * const pMBs,
664                                          VECTOR * const currMV,                  const MACROBLOCK * const prevMBs,
665                                          VECTOR * const currPMV)                  int inter4v,
666  {                  MACROBLOCK * const pMB)
667      const uint32_t iWcount = pParam->mb_width;  {
     const uint32_t iHcount = pParam->mb_height;  
         const int32_t iFcode = pParam->fixed_code;  
         const int32_t iQuant = pParam->quant;  
668    
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
669          const int32_t iEdgedWidth = pParam->edged_width;          const int32_t iEdgedWidth = pParam->edged_width;
670    
671          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;          int i, iDirection = 255, mask, threshA;
672            int32_t temp[5];
673          int32_t min_dx;          VECTOR currentMV[5], pmv[7];
674          int32_t max_dx;          int32_t psad[4], iMinSAD[5];
675          int32_t min_dy;          MainSearchFunc * MainSearchPtr;
676          int32_t max_dy;          SearchData Data;
677    
678            get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, psad);  //has to be changed to get_pmv(2)()
679            get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 16,
680                                    pParam->width, pParam->height, iFcode);
681    
682            Data.predMV = pmv[0];
683            Data.Cur = pCur->y + (x + y * iEdgedWidth) * 16;
684            Data.iEdgedWidth = iEdgedWidth;
685            Data.currentMV = currentMV;
686            Data.iMinSAD = iMinSAD;
687            Data.Ref = pRef + (x + iEdgedWidth*y)*16;
688            Data.RefH = pRefH + (x + iEdgedWidth*y) * 16;
689            Data.RefV = pRefV + (x + iEdgedWidth*y) * 16;
690            Data.RefHV = pRefHV + (x + iEdgedWidth*y) * 16;
691            Data.temp = temp;
692    
693            Data.iQuant = iQuant;
694            Data.iFcode = iFcode;
695    
696            if (!(MotionFlags & PMV_HALFPEL16)) {
697                    Data.min_dx = EVEN(Data.min_dx);
698                    Data.max_dx = EVEN(Data.max_dx);
699                    Data.min_dy = EVEN(Data.min_dy);
700                    Data.max_dy = EVEN(Data.max_dy); }
701    
702            for(i = 0;  i < 5; i++) currentMV[i].x = currentMV[i].y = 0;
703    
704            i = d_mv_bits(pmv[0].x, pmv[0].y, iFcode);
705    
706            iMinSAD[0] = pMB->sad16 + lambda_vec16[iQuant] * i;
707            iMinSAD[1] = pMB->sad8[0] + lambda_vec8[iQuant] * i;
708            iMinSAD[2] = pMB->sad8[1];
709            iMinSAD[3] = pMB->sad8[2];
710            iMinSAD[4] = pMB->sad8[3];
711    
712            if (pMB->dquant != NO_CHANGE) inter4v = 0;
713    
714            if ((x == 0) && (y == 0)) threshA = 512;
715            else {
716                    threshA = psad[0] + 20;
717                    if (threshA < 512) threshA = 512;
718                    if (threshA > 1024) threshA = 1024; }
719    
720          VECTOR newMV;          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
721          VECTOR backupMV;                                          prevMBs + x + y * pParam->mb_width);
722    
723          VECTOR pmv[4];          if (inter4v) CheckCandidate = CheckCandidate16;
724          int32_t psad[8];          else CheckCandidate = CheckCandidate16no4v;
725    
726          static MACROBLOCK * oldMBs = NULL;  /* main loop. checking all predictions */
         MACROBLOCK * const pMB = pMBs + x + y * iWcount;  
         MACROBLOCK * oldMB = NULL;  
727    
728          static int32_t thresh2;          for (i = 1; i < 7; i++) {
729          int32_t bPredEq;                  if (!(mask = make_mask(pmv, i)) ) continue;
730          int32_t iMinSAD,iSAD=9999;                  CheckCandidate16(pmv[i].x, pmv[i].y, mask, &iDirection, &Data);
731                    if (iMinSAD[0] < threshA) break;
732            }
733    
734          MainSearch16FuncPtr EPZSMainSearchPtr;          if ((iMinSAD[0] <= threshA) ||
735                            (MVequal(currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
736                            (iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16))) {
737                    inter4v = 0;
738                    if (MotionFlags & PMV_QUICKSTOP16) goto PMVfast16_Terminate_without_Refine;
739                    if (MotionFlags & PMV_EARLYSTOP16) {
740                            CheckCandidate = CheckCandidate16no4v; // I sure hope it's faster
741                            goto PMVfast16_Terminate_with_Refine;
742                    }
743            }
744    
745          if (oldMBs == NULL)          if (MotionFlags & PMV_USESQUARES16)
746          {       oldMBs = (MACROBLOCK*) calloc(1,iWcount*iHcount*sizeof(MACROBLOCK));                  MainSearchPtr = SquareSearch;
747                  fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
748                    MainSearchPtr = AdvDiamondSearch;
749                    else MainSearchPtr = DiamondSearch;
750    
751            (*MainSearchPtr)(currentMV->x, currentMV->y, &Data, iDirection);
752    
753    /* extended search, diamond starting in 0,0 and in prediction.
754            note that this search is/might be done in halfpel positions,
755            which makes it more different than the diamond above */
756    
757            if (MotionFlags & PMV_EXTSEARCH16) {
758                    int32_t bSAD;
759                    VECTOR startMV = Data.predMV, backupMV = currentMV[0];
760                    if (!(MotionFlags & PMV_HALFPELREFINE16)) // who's gonna use extsearch and no halfpel?
761                            startMV.x = EVEN(startMV.x); startMV.y = EVEN(startMV.y);
762                    if (!(MVequal(startMV, backupMV))) {
763                            bSAD = iMinSAD[0]; iMinSAD[0] = MV_MAX_ERROR;
764    
765                            CheckCandidate16(startMV.x, startMV.y, 255, &iDirection, &Data);
766                            (*MainSearchPtr)(startMV.x, startMV.y, &Data, 255);
767                            if (bSAD < iMinSAD[0]) {
768                                    currentMV[0] = backupMV;
769                                    iMinSAD[0] = bSAD; }
770                    }
771    
772                    backupMV = currentMV[0];
773                    if (MotionFlags & PMV_HALFPELREFINE16) startMV.x = startMV.y = 1;
774                    else startMV.x = startMV.y = 0;
775                    if (!(MVequal(startMV, backupMV))) {
776                            bSAD = iMinSAD[0]; iMinSAD[0] = MV_MAX_ERROR;
777    
778                            CheckCandidate16(startMV.x, startMV.y, 255, &iDirection, &Data);
779                            (*MainSearchPtr)(startMV.x, startMV.y, &Data, 255);
780                            if (bSAD < iMinSAD[0]) {
781                                    currentMV[0] = backupMV;
782                                    iMinSAD[0] = bSAD; }
783                    }
784          }          }
         oldMB = oldMBs + x + y * iWcount;  
785    
786  /* Get maximum range */  PMVfast16_Terminate_with_Refine:
         get_range(&min_dx, &max_dx, &min_dy, &max_dy,  
                         x, y, 16, iWidth, iHeight, iFcode);  
787    
788  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(&Data);
789    
790          if (!(MotionFlags & PMV_HALFPEL16 ))  PMVfast16_Terminate_without_Refine:
         { min_dx = EVEN(min_dx);  
           max_dx = EVEN(max_dx);  
           min_dy = EVEN(min_dy);  
           max_dy = EVEN(max_dy);  
         }               /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
791    
792          bPredEq  = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);          if (inter4v)
793                    for(i = 0; i < 4; i++)
794                            Search8(&Data, 2*x+(i&1), 2*y+(i>>1), MotionFlags, pParam, pMB, pMBs, i);
795    
796            if (!(inter4v) ||
797                    (iMinSAD[0] < iMinSAD[1] + iMinSAD[2] + iMinSAD[3] + iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {
798    // INTER MODE
799                    pMB->mode = MODE_INTER;
800                    pMB->mv16 = pMB->mvs[0] = pMB->mvs[1]
801                            = pMB->mvs[2] = pMB->mvs[3] = currentMV[0];
802    
803  /* Step 4: Calculate SAD around the Median prediction.                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
804          MinSAD=SAD                          pMB->sad8[2] = pMB->sad8[3] =  iMinSAD[0];
         If Motion Vector equal to Previous frame motion vector  
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
 */  
805    
806  // Prepare for main loop                  pMB->pmvs[0].x = currentMV[0].x - Data.predMV.x;
807                    pMB->pmvs[0].y = currentMV[0].y - Data.predMV.y;
808            } else {
809    // INTER4V MODE; all other things are already set in Search8
810                    pMB->mode = MODE_INTER4V;
811                    pMB->sad16 = iMinSAD[1] + iMinSAD[2] + iMinSAD[3] + iMinSAD[4] + IMV16X16 * iQuant;
812            }
813    
         *currMV=pmv[0];         /* current best := median prediction */  
         if (!(MotionFlags & PMV_HALFPEL16))  
         {  
                 currMV->x = EVEN(currMV->x);  
                 currMV->y = EVEN(currMV->y);  
814          }          }
815    
816          if (currMV->x > max_dx)  static void
817                  currMV->x=max_dx;  Search8(const SearchData * const OldData,
818          if (currMV->x < min_dx)                  const int x, const int y,
819                  currMV->x=min_dx;                  const uint32_t MotionFlags,
820          if (currMV->y > max_dy)                  const MBParam * const pParam,
821                  currMV->y=max_dy;                  MACROBLOCK * const pMB,
822          if (currMV->y < min_dy)                  const MACROBLOCK * const pMBs,
823                  currMV->y=min_dy;                  const int block)
824    {
825            SearchData Data;
826    
827  /***************** This is predictor SET A: only median prediction ******************/          Data.predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2 , y/2, block);
828            Data.iMinSAD = OldData->iMinSAD + 1 + block;
829            Data.currentMV = OldData->currentMV+1+block;
830            Data.iFcode = OldData->iFcode;
831            Data.iQuant = OldData->iQuant;
832    
833          iMinSAD = sad16( cur,          if (block != 0)
834                  get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV, iEdgedWidth),                  *(Data.iMinSAD) += lambda_vec8[Data.iQuant] *
835                  iEdgedWidth, MV_MAX_ERROR);                                                                  d_mv_bits(      Data.currentMV->x - Data.predMV.x,
836          iMinSAD += calc_delta_16(currMV->x-pmv[0].x, currMV->y-pmv[0].y, (uint8_t)iFcode) * iQuant;                                                                                          Data.currentMV->y - Data.predMV.y,
837                                                                                            Data.iFcode);
838    
 // thresh1 is fixed to 256  
         if ( (iMinSAD < 256 ) || ( (MVequal(*currMV,pMB->mvs[0])) && ((uint32_t)iMinSAD < pMB->sad16) ) )  
                 {  
                         if (MotionFlags & PMV_QUICKSTOP16)  
                                 goto EPZS16_Terminate_without_Refine;  
                         if (MotionFlags & PMV_EARLYSTOP16)  
                                 goto EPZS16_Terminate_with_Refine;  
                 }  
839    
840  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/          if (MotionFlags & (PMV_EXTSEARCH8|PMV_HALFPELREFINE8)) {
841    
842  // previous frame MV                  Data.Ref = OldData->Ref + 8 * ((block&1) + pParam->edged_width*(block>>1));
843          CHECK_MV16_CANDIDATE(pMB->mvs[0].x,pMB->mvs[0].y);                  Data.RefH = OldData->RefH + 8 * ((block&1) + pParam->edged_width*(block>>1));
844                    Data.RefV = OldData->RefV + 8 * ((block&1) + pParam->edged_width*(block>>1));
845                    Data.RefHV = OldData->RefHV + 8 * ((block&1) + pParam->edged_width*(block>>1));
846    
847  // set threshhold based on Min of Prediction and SAD of collocated block                  Data.iEdgedWidth = pParam->edged_width;
 // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want  
848    
849          if ((x==0) && (y==0) )                  Data.Cur = OldData->Cur + 8 * ((block&1) + pParam->edged_width*(block>>1));
         {  
                 thresh2 =  512;  
         }  
         else  
         {  
 /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */  
850    
851                  thresh2 = MIN(psad[0],iSAD)*6/5 + 128;                  get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 8,
852          }                                  pParam->width, pParam->height, OldData->iFcode);
853    
854  // MV=(0,0) is often a good choice                  CheckCandidate = CheckCandidate8;
855    
856          CHECK_MV16_ZERO;                  if (MotionFlags & PMV_EXTSEARCH8) {
857    
858                            MainSearchFunc *MainSearchPtr;
859                            if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
860                                    else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
861                                            else MainSearchPtr = DiamondSearch;
862    
863  // left neighbour, if allowed                          (*MainSearchPtr)(Data.currentMV->x, Data.currentMV->y, &Data, 255);     }
         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);  
         }  
864    
865  // top neighbour, if allowed                  if (MotionFlags & PMV_HALFPELREFINE8) HalfpelRefine(&Data);
         if (y != 0)  
         {  
                 if (!(MotionFlags & PMV_HALFPEL16 ))  
                 {       pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
866                  }                  }
                 CHECK_MV16_CANDIDATE(pmv[2].x,pmv[2].y);  
867    
868  // top right neighbour, if allowed          pMB->pmvs[block].x = Data.currentMV->x - Data.predMV.x;
869                  if ((uint32_t)x != (iWcount-1))          pMB->pmvs[block].y = Data.currentMV->y - Data.predMV.y;
870                  {          pMB->mvs[block] = *(Data.currentMV);
871                          if (!(MotionFlags & PMV_HALFPEL16 ))          pMB->sad8[block] =  4 * (*(Data.iMinSAD));
                         {       pmv[3].x = EVEN(pmv[3].x);  
                                 pmv[3].y = EVEN(pmv[3].y);  
                         }  
                         CHECK_MV16_CANDIDATE(pmv[3].x,pmv[3].y);  
                 }  
872          }          }
873    
874  /* Terminate if MinSAD <= T_2  /* B-frames code starts here */
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
875    
876          if ( (iMinSAD <= thresh2)  static __inline VECTOR
877                  || ( MVequal(*currMV,pMB->mvs[0]) && ((uint32_t)iMinSAD <= pMB->sad16) ) )  ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
878                  {                  {
879                          if (MotionFlags & PMV_QUICKSTOP16)  /* the stupidiest function ever */
880                                  goto EPZS16_Terminate_without_Refine;          if (mode == MODE_FORWARD) return pMB->mvs[0];
881                          if (MotionFlags & PMV_EARLYSTOP16)          else return pMB->b_mvs[0];
                                 goto EPZS16_Terminate_with_Refine;  
882                  }                  }
883    
884  /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/  static void __inline
885    PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
886                                                            const uint32_t iWcount,
887                                                            const MACROBLOCK * const pMB,
888                                                            const uint32_t mode_curr)
889    {
890    
891          backupMV = pMB->mvs[0];                 // last MV          // [0] is prediction
892          backupMV.x += (pMB->mvs[0].x - oldMB->mvs[0].x );       // acceleration X          pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
         backupMV.y += (pMB->mvs[0].y - oldMB->mvs[0].y );       // acceleration Y  
893    
894          CHECK_MV16_CANDIDATE(backupMV.x,backupMV.y);          pmv[1].x = pmv[1].y = 0; // [1] is zero
895    
896  // left neighbour          pmv[2] = ChoosePred(pMB, mode_curr);
897          if (x != 0)          pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
                 CHECK_MV16_CANDIDATE((oldMB-1)->mvs[0].x,oldMB->mvs[0].y);  
898    
899  // top neighbour          pmv[3].x = pmv[3].y = 0;
900          if (y != 0)          if ((y != 0)&&(x != (int)(iWcount+1))) {                        // [3] top-right neighbour
901                  CHECK_MV16_CANDIDATE((oldMB-iWcount)->mvs[0].x,oldMB->mvs[0].y);                  pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
902                    pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y); }
903    
904  // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs          if (y != 0) {
905                    pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
906                    pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
907            } else pmv[4].x = pmv[4].y = 0;
908    
909          if ((uint32_t)x != iWcount-1)          if (x != 0) {
910                  CHECK_MV16_CANDIDATE((pMB+1)->mvs[0].x,oldMB->mvs[0].y);                  pmv[5] = ChoosePred(pMB-1, mode_curr);
911                    pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
912            } else pmv[5].x = pmv[5].y = 0;
913    
914  // bottom neighbour, dito          if ((x != 0)&&(y != 0)) {
915          if ((uint32_t)y != iHcount-1)                  pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
916                  CHECK_MV16_CANDIDATE((pMB+iWcount)->mvs[0].x,oldMB->mvs[0].y);                  pmv[6].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
917            } else pmv[6].x = pmv[6].y = 0;
918    
919  /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */  // more?
         if (iMinSAD <= thresh2)  
                 {  
                         if (MotionFlags & PMV_QUICKSTOP16)  
                                 goto EPZS16_Terminate_without_Refine;  
                         if (MotionFlags & PMV_EARLYSTOP16)  
                                 goto EPZS16_Terminate_with_Refine;  
920                  }                  }
921    
 /************ (if Diamond Search)  **************/  
922    
923          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */  /* search backward or forward, for b-frames */
924    static void
925    SearchBF(       const uint8_t * const pRef,
926                            const uint8_t * const pRefH,
927                            const uint8_t * const pRefV,
928                            const uint8_t * const pRefHV,
929                            const IMAGE * const pCur,
930                            const int x, const int y,
931                            const uint32_t MotionFlags,
932                            const uint32_t iQuant,
933                            const uint32_t iFcode,
934                            const MBParam * const pParam,
935                            MACROBLOCK * const pMB,
936                            const VECTOR * const predMV,
937                            int32_t * const best_sad,
938                            const int32_t mode_current)
939    {
940    
941  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          const int32_t iEdgedWidth = pParam->edged_width;
942    
943            int i, iDirection, mask;
944            VECTOR currentMV, pmv[7];
945            MainSearchFunc *MainSearchPtr;
946            int32_t iMinSAD = MV_MAX_ERROR;
947            SearchData Data;
948    
949            Data.iMinSAD = &iMinSAD;
950            Data.Cur = pCur->y + (x + y * iEdgedWidth) * 16;
951            Data.iEdgedWidth = iEdgedWidth;
952            Data.currentMV = &currentMV;
953            Data.iMinSAD = &iMinSAD;
954            Data.Ref = pRef + (x + y * iEdgedWidth) * 16;
955            Data.RefH = pRefH + (x + y * iEdgedWidth) * 16;
956            Data.RefV = pRefV + (x + y * iEdgedWidth) * 16;
957            Data.RefHV = pRefHV + (x + y * iEdgedWidth) * 16;
958    
959            Data.iQuant = iQuant;
960            Data.iFcode = iFcode;
961            Data.predMV = *predMV;
962    
963            get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 16,
964                                    pParam->width, pParam->height, iFcode);
965    
966            if (!(MotionFlags & PMV_HALFPEL16)) {
967                    Data.min_dx = EVEN(Data.min_dx);
968                    Data.max_dx = EVEN(Data.max_dx);
969                    Data.min_dy = EVEN(Data.min_dy);
970                    Data.max_dy = EVEN(Data.max_dy); } // no-halpel and b-frames. do we need it?
971    
972    
973            pmv[0] = Data.predMV;
974            PreparePredictionsBF(pmv, x, y, pParam->mb_width,
975                                            pMB, mode_current);
976    
977            currentMV.x = currentMV.y = 0;
978    
979            CheckCandidate = CheckCandidate16no4v;
980    
981    // main loop. checking all predictions
982            for (i = 0; i < 8; i++) {
983                    if (!(mask = make_mask(pmv, i)) ) continue;
984                    CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, &Data);
985            }
986    
987          if (MotionFlags & PMV_USESQUARES16)          if (MotionFlags & PMV_USESQUARES16)
988                  EPZSMainSearchPtr = Square16_MainSearch;                  MainSearchPtr = SquareSearch;
989          else          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
990                  EPZSMainSearchPtr = Diamond16_MainSearch;                  MainSearchPtr = AdvDiamondSearch;
991                    else MainSearchPtr = DiamondSearch;
992    
993          iSAD = (*EPZSMainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,          (*MainSearchPtr)(currentMV.x, currentMV.y, &Data, 255);
                         x, y,  
                         currMV->x, currMV->y, iMinSAD, &newMV, pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                         2, iFcode, iQuant, 0);  
994    
995          if (iSAD < iMinSAD)          if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(&Data);
         {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
996    
997    // three bits are needed to code backward mode. four for forward
998    // we treat the bits just like they were vector's
999            if (mode_current == MODE_FORWARD) iMinSAD +=  4 * lambda_vec16[iQuant];
1000            else iMinSAD +=  3 * lambda_vec16[iQuant];
1001    
         if (MotionFlags & PMV_EXTSEARCH16)  
         {  
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
1002    
1003                  if (!(MVequal(pmv[0],backupMV)) )          if (iMinSAD < *best_sad) {
1004                  {                  *best_sad = iMinSAD;
1005                          iSAD = (*EPZSMainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,                  pMB->mode = mode_current;
1006                                  x, y,                  pMB->pmvs[0].x = currentMV.x - predMV->x;
1007                                  pmv[0].x, pmv[0].y, iMinSAD, &newMV,                  pMB->pmvs[0].y = currentMV.y - predMV->y;
1008                                  pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);                  if (mode_current == MODE_FORWARD) pMB->mvs[0] = currentMV;
1009                    else pMB->b_mvs[0] = currentMV;
1010                  }                  }
1011    
                 if (iSAD < iMinSAD)  
                 {  
                         *currMV = newMV;  
                         iMinSAD = iSAD;  
1012                  }                  }
1013    
1014                  if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )  static int32_t
1015                  {  SearchDirect(const uint8_t * const f_Ref,
1016                          iSAD = (*EPZSMainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,                                  const uint8_t * const f_RefH,
1017                                  x, y,                                  const uint8_t * const f_RefV,
1018                          0, 0, iMinSAD, &newMV,                                  const uint8_t * const f_RefHV,
1019                          pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, /*iDiamondSize*/ 2, iFcode, iQuant, 0);                                  const uint8_t * const b_Ref,
1020                                    const uint8_t * const b_RefH,
1021                                    const uint8_t * const b_RefV,
1022                                    const uint8_t * const b_RefHV,
1023                                    const IMAGE * const pCur,
1024                                    const int x, const int y,
1025                                    const uint32_t MotionFlags,
1026                                    const uint32_t iQuant,
1027                                    const int32_t TRB, const int32_t TRD,
1028                                    const MBParam * const pParam,
1029                                    MACROBLOCK * const pMB,
1030                                    const MACROBLOCK * const b_mb,
1031                                    int32_t * const best_sad)
1032    
1033    {
1034            const uint32_t iEdgedWidth = pParam->edged_width;
1035            int32_t iMinSAD = 0, skip_sad;
1036            int k;
1037            VECTOR currentMV;
1038            MainSearchFunc *MainSearchPtr;
1039            SearchData Data;
1040    
1041            Data.iMinSAD = &iMinSAD;
1042            Data.Cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;
1043            Data.iEdgedWidth = iEdgedWidth;
1044            Data.currentMV = &currentMV;
1045            Data.iQuant = iQuant;
1046            Data.referencemv = b_mb->mvs;
1047    
1048            Data.Ref= f_Ref + (x + iEdgedWidth*y) * 16;
1049            Data.RefH = f_RefH + (x + iEdgedWidth*y) * 16;
1050            Data.RefV = f_RefV + (x + iEdgedWidth*y) * 16;
1051            Data.RefHV = f_RefHV + (x + iEdgedWidth*y) * 16;
1052            Data.bRef = b_Ref + (x + iEdgedWidth*y) * 16;
1053            Data.bRefH = b_RefH + (x + iEdgedWidth*y) * 16;
1054            Data.bRefV = b_RefV + (x + iEdgedWidth*y) * 16;
1055            Data.bRefHV = b_RefHV + (x + iEdgedWidth*y) * 16;
1056    /*
1057    //What we do here is a complicated version of CheckCandidateDirect(0,0);
1058    get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 16, pParam->width, pParam->height, 19);
1059    
1060                          if (iSAD < iMinSAD)  */
1061                          {          Data.max_dx = 2 * pParam->width - 2 * (x) * 16;
1062                                  *currMV = newMV;          Data.max_dy = 2 * pParam->height - 2 * (y) * 16;
1063                                  iMinSAD = iSAD;          Data.min_dx = -(2 * 16 + 2 * (x) * 16);
1064                          }          Data.min_dy = -(2 * 16 + 2 * (y) * 16);
1065    
1066            for (k = 0; k < 4; k++) {
1067                    pMB->mvs[k].x = Data.directmvF[k].x = ((TRB * Data.referencemv[k].x) / TRD);
1068                    pMB->b_mvs[k].x = Data.directmvB[k].x = ((TRB - TRD) * Data.referencemv[k].x) / TRD;
1069                    pMB->mvs[k].y = Data.directmvF[k].y = ((TRB * Data.referencemv[k].y) / TRD);
1070                    pMB->b_mvs[k].y = Data.directmvB[k].y = ((TRB - TRD) * Data.referencemv[k].y) / TRD;
1071    
1072            if (( pMB->mvs[k].x > Data.max_dx ) || ( pMB->mvs[k].x < Data.min_dx )
1073                            || ( pMB->mvs[k].y > Data.max_dy ) || ( pMB->mvs[k].y < Data.min_dy )
1074                            || ( pMB->b_mvs[k].x > Data.max_dx ) || ( pMB->b_mvs[k].x < Data.min_dx )
1075                            || ( pMB->b_mvs[k].y > Data.max_dy ) || ( pMB->b_mvs[k].y < Data.min_dy )) {
1076    /*
1077                    fprintf(debug, "\nERROR - out of range : vector %d,%d and %d,%d\n", pMB->mvs[k].x, pMB->mvs[k].y,pMB->b_mvs[k].x,pMB->b_mvs[k].y );
1078                    fprintf(debug, " range is x: %d..%d y: %d..%d \n", Data.min_dx,Data.max_dx,Data.min_dy,Data.max_dy);
1079                    fprintf(debug,"macroblock %d, %d \n", x, y);
1080                    fprintf(debug, "direct MV is %d,%d \n", directmv[k].x, directmv[k].y);
1081    */
1082                    *best_sad = 256*4096; // in that case, we won't use direct mode
1083                    pMB->mode = MODE_DIRECT; // just to make sure it doesn't say "MODE_DIRECT_NONE_MV"
1084                    pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;  /* because backwards and interpol might rely on this */
1085                    return 0; }
1086    
1087    
1088            if (b_mb->mode != MODE_INTER4V) {
1089                    iMinSAD = sad16bi(Data.Cur,
1090                                                    get_ref_mv(f_Ref, f_RefH, f_RefV, f_RefHV,
1091                                                                    x, y, 16, &pMB->mvs[0], iEdgedWidth),
1092                                                    get_ref_mv(b_Ref, b_RefH, b_RefV, b_RefHV,
1093                                                                    x, y, 16, &pMB->b_mvs[0], iEdgedWidth), iEdgedWidth);
1094    
1095                    Data.directmvF[1] = Data.directmvF[2] = Data.directmvF[3] = Data.directmvF[0];
1096                    Data.directmvB[1] = Data.directmvB[2] = Data.directmvB[3] = Data.directmvB[0];
1097                    break;
1098                  }                  }
1099            iMinSAD += sad8bi(Data.Cur + (k&1)*8 + (k>>1)* 8 * iEdgedWidth,
1100                                                    get_ref_mv(f_Ref, f_RefH, f_RefV, f_RefHV,
1101                                                                    (2*x+(k&1)), (2*y+(k>>1)), 8, &pMB->mvs[k], iEdgedWidth),
1102                                                    get_ref_mv(b_Ref, b_RefH, b_RefV, b_RefHV,
1103                                                                    (2*x+(k&1)), (2*y+(k>>1)), 8, &pMB->b_mvs[k], iEdgedWidth),
1104                                                    iEdgedWidth);
1105          }          }
1106    
1107  /***************        Choose best MV found     **************/  // skip decision
1108            if (iMinSAD < (int32_t)iQuant * SKIP_THRESH_B) {
1109  EPZS16_Terminate_with_Refine:                  pMB->mode = MODE_DIRECT_NONE_MV;
1110          if (MotionFlags & PMV_HALFPELREFINE16)          // perform final half-pel step                  return iMinSAD; }
1111                  iMinSAD = Halfpel16_Refine( pRef, pRefH, pRefV, pRefHV, cur,  
1112                                  x, y,          skip_sad = iMinSAD;
1113                                  currMV, iMinSAD,          iMinSAD += 2 * lambda_vec16[iQuant]; // 2 bits needed to code vector 0,0
1114                                  pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);          currentMV.x = currentMV.y = 0;
1115            if (b_mb->mode == MODE_INTER4V)
1116  EPZS16_Terminate_without_Refine:                  CheckCandidate = CheckCandidateDirect;
1117            else CheckCandidate = CheckCandidateDirectno4v;
1118          *oldMB = *pMB;  
1119    //  DIRECT MODE DELTA VECTOR SEARCH.
1120          currPMV->x = currMV->x - pmv[0].x;  //      This has to be made more effective, but at the moment I'm happy it's running at all
1121          currPMV->y = currMV->y - pmv[0].y;  
1122          return iMinSAD;          if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1123                    else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1124                            else MainSearchPtr = DiamondSearch;
1125    
1126            (*MainSearchPtr)(0, 0, &Data, 255);
1127    
1128            HalfpelRefine(&Data);
1129    
1130            iMinSAD +=  1 * lambda_vec16[iQuant]; // one bit is needed to code direct mode. we treat this bit just like it was vector's
1131            *best_sad = iMinSAD;
1132    
1133            if (b_mb->mode == MODE_INTER4V)
1134                    pMB->mode = MODE_DIRECT;
1135            else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation
1136    
1137            pMB->pmvs[3] = currentMV;
1138    
1139            for (k = 0; k < 4; k++) {
1140                    pMB->mvs[k].x = Data.directmvF[k].x + currentMV.x;
1141                    pMB->b_mvs[k].x = ((currentMV.x == 0)
1142                                                            ? Data.directmvB[k].x
1143                                                            : pMB->mvs[k].x - Data.referencemv[k].x);
1144                    pMB->mvs[k].y = (Data.directmvF[k].y + currentMV.y);
1145                    pMB->b_mvs[k].y = ((currentMV.y == 0)
1146                                                            ? Data.directmvB[k].y
1147                                                            : pMB->mvs[k].y - Data.referencemv[k].y);
1148                    if (b_mb->mode != MODE_INTER4V) {
1149                            pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1150                            pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1151                            break;
1152                    }
1153            }
1154            return 0;//skip_sad;
1155  }  }
1156    
1157    static __inline void
1158  int32_t EPZSSearch8(  SearchInterpolate(const uint8_t * const f_Ref,
1159                                          const uint8_t * const pRef,                                  const uint8_t * const f_RefH,
1160                                          const uint8_t * const pRefH,                                  const uint8_t * const f_RefV,
1161                                          const uint8_t * const pRefV,                                  const uint8_t * const f_RefHV,
1162                                          const uint8_t * const pRefHV,                                  const uint8_t * const b_Ref,
1163                                    const uint8_t * const b_RefH,
1164                                    const uint8_t * const b_RefV,
1165                                    const uint8_t * const b_RefHV,
1166                                          const IMAGE * const pCur,                                          const IMAGE * const pCur,
1167                                          const int x, const int y,                                          const int x, const int y,
1168                                          const int start_x, const int start_y,                                  const uint32_t fcode,
1169                                    const uint32_t bcode,
1170                                          const uint32_t MotionFlags,                                          const uint32_t MotionFlags,
1171                                    const uint32_t iQuant,
1172                                          const MBParam * const pParam,                                          const MBParam * const pParam,
1173                                          MACROBLOCK * const pMBs,                                  const VECTOR * const f_predMV,
1174                                          VECTOR * const currMV,                                  const VECTOR * const b_predMV,
1175                                          VECTOR * const currPMV)                                  MACROBLOCK * const pMB,
1176  {                                  int32_t * const best_sad)
1177      const uint32_t iWcount = pParam->mb_width;  
1178          const int32_t iFcode = pParam->fixed_code;  {
1179          const int32_t iQuant = pParam->quant;  /* Interpolated MC motion vector search, this is tedious and more complicated because there are
1180       two values for everything, always one for backward and one for forward ME. Still, we don't gain
1181       much from this search, maybe it should simply be skipped and simply current i_sad16 value used
1182       as "optimal". */
1183    
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
1184          const int32_t iEdgedWidth = pParam->edged_width;          const int32_t iEdgedWidth = pParam->edged_width;
1185    
1186          const uint8_t * cur = pCur->y + x*8 + y*8*iEdgedWidth;          int iDirection, i, j;
1187            int32_t iMinSAD = 256*4096;
1188            VECTOR currentMV[3];
1189            SearchData fData, bData;
1190    
         int32_t iDiamondSize=1;  
1191    
1192          int32_t min_dx;          fData.iMinSAD = bData.iMinSAD = &iMinSAD;
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
1193    
1194          VECTOR newMV;          fData.Cur = bData.Cur = pCur->y + (x + y * iEdgedWidth) * 16;
1195          VECTOR backupMV;          fData.iEdgedWidth = bData.iEdgedWidth = iEdgedWidth;
1196            fData.currentMV = currentMV; bData.currentMV = currentMV + 1;
1197            fData.iQuant = bData.iQuant = iQuant;
1198            fData.iFcode = bData.bFcode = fcode; fData.bFcode = bData.iFcode = bcode;
1199    
         VECTOR pmv[4];  
         int32_t psad[8];  
1200    
1201          const   int32_t iSubBlock = ((y&1)<<1) + (x&1);          bData.bRef = fData.Ref = f_Ref + (x + y * iEdgedWidth) * 16;
1202            bData.bRefH = fData.RefH = f_RefH + (x + y * iEdgedWidth) * 16;
1203            bData.bRefV = fData.RefV = f_RefV + (x + y * iEdgedWidth) * 16;
1204            bData.bRefHV = fData.RefHV = f_RefHV + (x + y * iEdgedWidth) * 16;
1205            bData.Ref = fData.bRef = b_Ref + (x + y * iEdgedWidth) * 16;
1206            bData.RefH = fData.bRefH = b_RefH + (x + y * iEdgedWidth) * 16;
1207            bData.RefV = fData.bRefV = b_RefV + (x + y * iEdgedWidth) * 16;
1208            bData.RefHV = fData.bRefHV = b_RefHV + (x + y * iEdgedWidth) * 16;
1209    
1210          MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          bData.bpredMV = fData.predMV = *f_predMV;
1211            fData.bpredMV = bData.predMV = *b_predMV;
1212    
         int32_t bPredEq;  
         int32_t iMinSAD,iSAD=9999;  
1213    
1214          MainSearch8FuncPtr EPZSMainSearchPtr;          currentMV[0] = pMB->mvs[0];
1215            currentMV[1] = pMB->b_mvs[0];
1216            get_range(&fData.min_dx, &fData.max_dx, &fData.min_dy, &fData.max_dy, x, y, 16, pParam->width, pParam->height, fcode);
1217            get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode);
1218    
1219  /* Get maximum range */          CheckCandidateInt(currentMV[0].x, currentMV[0].y, 255, &iDirection, &fData);
         get_range(&min_dx, &max_dx, &min_dy, &max_dy,  
                         x, y, 8, iWidth, iHeight, iFcode);  
1220    
1221  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  //diamond. I wish we could use normal mainsearch functions (square, advdiamond)
1222    
1223          if (!(MotionFlags & PMV_HALFPEL8 ))          do {
1224          { min_dx = EVEN(min_dx);                  iDirection = 255;
1225            max_dx = EVEN(max_dx);                  // forward MV moves
1226            min_dy = EVEN(min_dy);                  i = currentMV[0].x; j = currentMV[0].y;
           max_dy = EVEN(max_dy);  
         }               /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
1227    
1228          bPredEq  = get_pmvdata(pMBs, x>>1, y>>1, iWcount, iSubBlock, pmv, psad);                  CheckCandidateInt(i + 2, j, 0, &iDirection, &fData);
1229                    CheckCandidateInt(i, j + 2, 0, &iDirection, &fData);
1230                    CheckCandidateInt(i - 2, j, 0, &iDirection, &fData);
1231                    CheckCandidateInt(i, j - 2, 0, &iDirection, &fData);
1232    
1233                    // backward MV moves
1234                    i = currentMV[1].x; j = currentMV[1].y;
1235                    currentMV[2] = currentMV[0];
1236    
1237  /* Step 4: Calculate SAD around the Median prediction.                  CheckCandidateInt(i + 2, j, 0, &iDirection, &bData);
1238          MinSAD=SAD                  CheckCandidateInt(i, j + 2, 0, &iDirection, &bData);
1239          If Motion Vector equal to Previous frame motion vector                  CheckCandidateInt(i - 2, j, 0, &iDirection, &bData);
1240                  and MinSAD<PrevFrmSAD goto Step 10.                  CheckCandidateInt(i, j - 2, 0, &iDirection, &bData);
         If SAD<=256 goto Step 10.  
 */  
1241    
1242  // Prepare for main loop          } while (!(iDirection));
1243    
1244    /* halfpel refinement. luckly we can use normal halfpel function for it */
1245    
1246          if (!(MotionFlags & PMV_HALFPEL8))          if (MotionFlags & PMV_HALFPELREFINE16) {
1247          {                  CheckCandidate = CheckCandidateInt;
1248                  currMV->x = EVEN(currMV->x);                  HalfpelRefine(&fData);
1249                  currMV->y = EVEN(currMV->y);                  currentMV[2] = currentMV[0];
1250                    HalfpelRefine(&bData);
1251          }          }
1252    
1253          if (currMV->x > max_dx)  // two bits are needed to code interpolate mode. we treat the bits just like they were vector's
1254                  currMV->x=max_dx;          iMinSAD +=  2 * lambda_vec16[iQuant];
1255          if (currMV->x < min_dx)          if (iMinSAD < *best_sad) {
1256                  currMV->x=min_dx;                  *best_sad = iMinSAD;
1257          if (currMV->y > max_dy)                  pMB->mvs[0] = currentMV[0];
1258                  currMV->y=max_dy;                  pMB->b_mvs[0] = currentMV[1];
1259          if (currMV->y < min_dy)                  pMB->mode = MODE_INTERPOLATE;
                 currMV->y=min_dy;  
   
 /***************** This is predictor SET A: only median prediction ******************/  
   
   
         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;  
1260    
1261                    pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;
1262                    pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;
1263                    pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;
1264                    pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;
1265            }
1266    }
1267    
1268  // thresh1 is fixed to 256  void
1269          if (iMinSAD < 256/4 )  MotionEstimationBVOP(MBParam * const pParam,
1270                                             FRAMEINFO * const frame,
1271                                             const int32_t time_bp,
1272                                             const int32_t time_pp,
1273                                             // forward (past) reference
1274                                             const MACROBLOCK * const f_mbs,
1275                                             const IMAGE * const f_ref,
1276                                             const IMAGE * const f_refH,
1277                                             const IMAGE * const f_refV,
1278                                             const IMAGE * const f_refHV,
1279                                             // backward (future) reference
1280                                             const MACROBLOCK * const b_mbs,
1281                                             const IMAGE * const b_ref,
1282                                             const IMAGE * const b_refH,
1283                                             const IMAGE * const b_refV,
1284                                             const IMAGE * const b_refHV)
1285                  {                  {
1286                          if (MotionFlags & PMV_QUICKSTOP8)          uint32_t i, j;
1287                                  goto EPZS8_Terminate_without_Refine;          int32_t best_sad, skip_sad;
1288                          if (MotionFlags & PMV_EARLYSTOP8)          int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;
1289                                  goto EPZS8_Terminate_with_Refine;          static const VECTOR zeroMV={0,0};
                 }  
1290    
1291  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
1292    
1293  // previous frame MV          const int32_t TRB = time_pp - time_bp;
1294          CHECK_MV8_CANDIDATE(pMB->mvs[0].x,pMB->mvs[0].y);          const int32_t TRD = time_pp;
1295    
1296  // MV=(0,0) is often a good choice          // note: i==horizontal, j==vertical
1297    
1298          CHECK_MV8_ZERO;          for (j = 0; j < pParam->mb_height; j++) {
1299    
1300  /* Terminate if MinSAD <= T_2                  f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
1301    
1302          if (iMinSAD < 512/4)    /* T_2 == 512/4 hardcoded */                  for (i = 0; i < pParam->mb_width; i++) {
1303                  {                          MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
1304                          if (MotionFlags & PMV_QUICKSTOP8)                          const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
1305                                  goto EPZS8_Terminate_without_Refine;  
1306                          if (MotionFlags & PMV_EARLYSTOP8)  /* special case, if collocated block is SKIPed: encoding is forward (0,0), cpb=0 without further ado */
1307                                  goto EPZS8_Terminate_with_Refine;                          if (b_mb->mode == MODE_NOT_CODED) {
1308                                    pMB->mode = MODE_NOT_CODED;
1309                                    continue;
1310                  }                  }
1311    
1312  /************ (if Diamond Search)  **************/  /* direct search comes first, because it (1) checks for SKIP-mode
1313            and (2) sets very good predictions for forward and backward search */
1314    
1315          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */                          skip_sad = SearchDirect(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
1316                                                                            b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
1317                                                                            &frame->image,
1318                                                                            i, j,
1319                                                                            frame->motion_flags,
1320                                                                            frame->quant,
1321                                                                            TRB, TRD,
1322                                                                            pParam,
1323                                                                            pMB, b_mb,
1324                                                                            &best_sad);
1325    
1326          if (!(MotionFlags & PMV_HALFPELDIAMOND8))                          if (!(frame->global_flags & XVID_HALFPEL)) best_sad = skip_sad = 256*4096;
1327                  iDiamondSize *= 2;                          else
1328                                    if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
1329    
1330  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  //                      best_sad = 256*4096; //uncomment to disable Directsearch.
1331    //      To disable any other mode, just comment the function call
1332    
1333  //      if (MotionFlags & PMV_USESQUARES8)                          // forward search
1334  //              EPZSMainSearchPtr = Square8_MainSearch;                          SearchBF(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
1335  //      else                                                  &frame->image, i, j,
1336                  EPZSMainSearchPtr = Diamond8_MainSearch;                                                  frame->motion_flags,
1337                                                    frame->quant, frame->fcode, pParam,
1338                                                    pMB, &f_predMV, &best_sad,
1339                                                    MODE_FORWARD);
1340    
1341          iSAD = (*EPZSMainSearchPtr)(pRef, pRefH, pRefV, pRefHV, cur,                          // backward search
1342                  x, y,                          SearchBF(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
1343                  currMV->x, currMV->y, iMinSAD, &newMV,                                                  &frame->image, i, j,
1344                  pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth,                                                  frame->motion_flags,
1345                  iDiamondSize, iFcode, iQuant, 00);                                                  frame->quant, frame->bcode, pParam,
1346                                                    pMB, &b_predMV, &best_sad,
1347                                                    MODE_BACKWARD);
1348    
1349                            // interpolate search comes last, because it uses data from forward and backward as prediction
1350    
1351          if (iSAD < iMinSAD)                          SearchInterpolate(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
1352          {                                                  b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
1353                  *currMV = newMV;                                                  &frame->image,
1354                  iMinSAD = iSAD;                                                  i, j,
1355                                                    frame->fcode, frame->bcode,
1356                                                    frame->motion_flags,
1357                                                    frame->quant, pParam,
1358                                                    &f_predMV, &b_predMV,
1359                                                    pMB, &best_sad);
1360    
1361                            switch (pMB->mode) {
1362                                    case MODE_FORWARD:
1363                                            f_count++;
1364                                            f_predMV = pMB->mvs[0];
1365                                            break;
1366                                    case MODE_BACKWARD:
1367                                            b_count++;
1368                                            b_predMV = pMB->b_mvs[0];
1369                                            break;
1370                                    case MODE_INTERPOLATE:
1371                                            i_count++;
1372                                            f_predMV = pMB->mvs[0];
1373                                            b_predMV = pMB->b_mvs[0];
1374                                            break;
1375                                    case MODE_DIRECT:
1376                                    case MODE_DIRECT_NO4V:
1377                                            d_count++;
1378                                            break;
1379                                    default:
1380                                            break;
1381                            }
1382                    }
1383          }          }
1384    
1385          if (MotionFlags & PMV_EXTSEARCH8)  //      fprintf(debug,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d, N: %04d\n",
1386          {  //                              f_count,b_count,i_count,d_count,n_count);
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
   
                 if (!(MVequal(pmv[0],backupMV)) )  
                 {  
                         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, iDiamondSize, iFcode, iQuant, 0);  
1387    
                         if (iSAD < iMinSAD)  
                         {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
1388                  }                  }
1389    
1390                  if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )  /* Hinted ME starts here */
                 {  
                         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);  
1391    
1392                          if (iSAD < iMinSAD)  static __inline void
1393    Search8hinted(  const SearchData * const OldData,
1394                                    const int x, const int y,
1395                                    const uint32_t MotionFlags,
1396                                    const MBParam * const pParam,
1397                                    MACROBLOCK * const pMB,
1398                                    const MACROBLOCK * const pMBs,
1399                                    const int block)
1400                          {                          {
1401                                  *currMV = newMV;          SearchData Data;
1402                                  iMinSAD = iSAD;          MainSearchFunc *MainSearchPtr;
                         }  
                 }  
         }  
1403    
1404  /***************        Choose best MV found     **************/          Data.predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2 , y/2, block);
1405            Data.iMinSAD = OldData->iMinSAD + 1 + block;
1406            Data.currentMV = OldData->currentMV+1+block;
1407            Data.iFcode = OldData->iFcode;
1408            Data.iQuant = OldData->iQuant;
1409    
1410  EPZS8_Terminate_with_Refine:          Data.Ref = OldData->Ref + 8 * ((block&1) + pParam->edged_width*(block>>1));
1411          if (MotionFlags & PMV_HALFPELREFINE8)           // perform final half-pel step          Data.RefH = OldData->RefH + 8 * ((block&1) + pParam->edged_width*(block>>1));
1412                  iMinSAD = Halfpel8_Refine( pRef, pRefH, pRefV, pRefHV, cur,          Data.RefV = OldData->RefV + 8 * ((block&1) + pParam->edged_width*(block>>1));
1413                                  x, y,          Data.RefHV = OldData->RefHV + 8 * ((block&1) + pParam->edged_width*(block>>1));
1414                                  currMV, iMinSAD,          Data.iEdgedWidth = pParam->edged_width;
1415                                  pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);          Data.Cur = OldData->Cur + 8 * ((block&1) + pParam->edged_width*(block>>1));
1416    
1417  EPZS8_Terminate_without_Refine:          CheckCandidate = CheckCandidate8;
1418    
1419          currPMV->x = currMV->x - pmv[0].x;          if (block != 0)
1420          currPMV->y = currMV->y - pmv[0].y;                  *(Data.iMinSAD) += lambda_vec8[Data.iQuant] *
1421          return iMinSAD;                                                                  d_mv_bits(      Data.currentMV->x - Data.predMV.x,
1422  }                                                                                          Data.currentMV->y - Data.predMV.y,
1423                                                                                            Data.iFcode);
1424    
1425    
1426            get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 8,
1427                                    pParam->width, pParam->height, OldData->iFcode);
1428    
1429            if (pMB->mode == MODE_INTER4V) {
1430                    int dummy;
1431                    CheckCandidate8(pMB->mvs[block].x, pMB->mvs[block].y, 0, &dummy, &Data); }
1432    
1433            if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
1434                    else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1435                            else MainSearchPtr = DiamondSearch;
1436    
1437  /* ***********************************************************          (*MainSearchPtr)(Data.currentMV->x, Data.currentMV->y, &Data, 255);
         bvop motion estimation  
 // TODO: need to incorporate prediction here (eg. sad += calc_delta_16)  
 ***************************************************************/  
1438    
1439  /*          if (MotionFlags & PMV_HALFPELREFINE8) HalfpelRefine(&Data);
 void MotionEstimationBVOP(  
                         MBParam * const pParam,  
                         FRAMEINFO * const frame,  
1440    
1441                          // forward (past) reference          pMB->pmvs[block].x = Data.currentMV->x - Data.predMV.x;
1442                          const MACROBLOCK * const f_mbs,          pMB->pmvs[block].y = Data.currentMV->y - Data.predMV.y;
1443                      const IMAGE * const f_ref,          pMB->mvs[block] = *(Data.currentMV);
1444                          const IMAGE * const f_refH,          pMB->sad8[block] =  4 * (*(Data.iMinSAD));
1445                      const IMAGE * const f_refV,  }
                         const IMAGE * const f_refHV,  
                         // backward (future) reference  
                         const MACROBLOCK * const b_mbs,  
                     const IMAGE * const b_ref,  
                         const IMAGE * const b_refH,  
                     const IMAGE * const b_refV,  
                         const IMAGE * const b_refHV)  
 {  
     const uint32_t mb_width = pParam->mb_width;  
     const uint32_t mb_height = pParam->mb_height;  
         const int32_t edged_width = pParam->edged_width;  
   
         int32_t i,j;  
   
         int32_t f_sad16;  
         int32_t b_sad16;  
         int32_t i_sad16;  
         int32_t d_sad16;  
         int32_t best_sad;  
1446    
         VECTOR pmv_dontcare;  
1447    
1448          // note: i==horizontal, j==vertical  static void
1449      for (j = 0; j < mb_height; j++)  SearchPhinted ( const uint8_t * const pRef,
1450          {                                  const uint8_t * const pRefH,
1451                  for (i = 0; i < mb_width; i++)                                  const uint8_t * const pRefV,
1452                                    const uint8_t * const pRefHV,
1453                                    const IMAGE * const pCur,
1454                                    const int x,
1455                                    const int y,
1456                                    const uint32_t MotionFlags,
1457                                    const uint32_t iQuant,
1458                                    const uint32_t iFcode,
1459                                    const MBParam * const pParam,
1460                                    const MACROBLOCK * const pMBs,
1461                                    int inter4v,
1462                                    MACROBLOCK * const pMB)
1463                  {                  {
                         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 = MB_IGNORE;  
                                 mb->mvs[0].x = 0;  
                                 mb->mvs[0].y = 0;  
                                 mb->b_mvs[0].x = 0;  
                                 mb->b_mvs[0].y = 0;  
                                 continue;  
                         }  
1464    
1465            const int32_t iEdgedWidth = pParam->edged_width;
1466    
1467                          // forward search          int i;
1468                          f_sad16 = SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,          VECTOR currentMV[5];
1469                                                  &frame->image,          int32_t iMinSAD[5];
1470                                                  i, j,          int32_t temp[5];
1471                                                  frame->motion_flags,  frame->quant, frame->fcode,          MainSearchFunc * MainSearchPtr;
1472                                                  pParam,          SearchData Data;
1473                                                  f_mbs,  
1474                                                  &mb->mvs[0], &pmv_dontcare);    // ignore pmv          Data.predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1475            get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 16,
1476                                    pParam->width, pParam->height, iFcode);
1477    
1478            Data.Cur = pCur->y + (x + y * iEdgedWidth) * 16;
1479            Data.iEdgedWidth = iEdgedWidth;
1480            Data.currentMV = currentMV;
1481            Data.iMinSAD = iMinSAD;
1482            Data.Ref = pRef + (x + iEdgedWidth*y)*16;
1483            Data.RefH = pRefH + (x + iEdgedWidth*y) * 16;
1484            Data.RefV = pRefV + (x + iEdgedWidth*y) * 16;
1485            Data.RefHV = pRefHV + (x + iEdgedWidth*y) * 16;
1486            Data.temp = temp;
1487            Data.iQuant = iQuant;
1488            Data.iFcode = iFcode;
1489    
1490            if (!(MotionFlags & PMV_HALFPEL16)) {
1491                    Data.min_dx = EVEN(Data.min_dx);
1492                    Data.max_dx = EVEN(Data.max_dx);
1493                    Data.min_dy = EVEN(Data.min_dy);
1494                    Data.max_dy = EVEN(Data.max_dy);
1495            }
1496    
1497            for(i = 0; i < 5; i++) iMinSAD[i] = MV_MAX_ERROR;
1498    
1499            if (pMB->dquant != NO_CHANGE) inter4v = 0;
1500    
1501            if (inter4v)
1502                    CheckCandidate = CheckCandidate16;
1503            else CheckCandidate = CheckCandidate16no4v;
1504    
1505    
1506            pMB->mvs[0].x = EVEN(pMB->mvs[0].x);
1507            pMB->mvs[0].y = EVEN(pMB->mvs[0].y);
1508            if (pMB->mvs[0].x > Data.max_dx) pMB->mvs[0].x = Data.max_dx; // this is in case iFcode changed
1509            if (pMB->mvs[0].x < Data.min_dx) pMB->mvs[0].x = Data.min_dx;
1510            if (pMB->mvs[0].y > Data.max_dy) pMB->mvs[0].y = Data.max_dy;
1511            if (pMB->mvs[0].y < Data.min_dy) pMB->mvs[0].y = Data.min_dy;
1512    
1513            CheckCandidate16(pMB->mvs[0].x, pMB->mvs[0].y, 0, &i, &Data);
1514    
1515            if (pMB->mode == MODE_INTER4V)
1516                    for (i = 1; i < 4; i++) { // all four vectors will be used as four predictions for 16x16 search
1517                            pMB->mvs[i].x = EVEN(pMB->mvs[i].x);
1518                            pMB->mvs[i].y = EVEN(pMB->mvs[i].y);
1519                            if (!(make_mask(pMB->mvs, i)))
1520                                    CheckCandidate16(pMB->mvs[i].x, pMB->mvs[i].y, 0, &i, &Data);
1521                    }
1522    
1523                          // backward search          if (MotionFlags & PMV_USESQUARES16)
1524                          b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,                  MainSearchPtr = SquareSearch;
1525                                                  &frame->image,          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
1526                                                  i, j,                  MainSearchPtr = AdvDiamondSearch;
1527                                                  frame->motion_flags,  frame->quant, frame->bcode,                  else MainSearchPtr = DiamondSearch;
1528                                                  pParam,  
1529                                                  b_mbs,          (*MainSearchPtr)(currentMV->x, currentMV->y, &Data, 255);
1530                                                  &mb->b_mvs[0], &pmv_dontcare);  // ignore pmv  
1531            if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(&Data);
1532    
1533            if (inter4v)
1534                    for(i = 0; i < 4; i++)
1535                            Search8hinted(&Data, 2*x+(i&1), 2*y+(i>>1), MotionFlags, pParam, pMB, pMBs, i);
1536    
1537            if (!(inter4v) ||
1538                    (iMinSAD[0] < iMinSAD[1] + iMinSAD[2] + iMinSAD[3] + iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {
1539    // INTER MODE
1540    
1541                          // interpolate search (simple, but effective)                  pMB->mode = MODE_INTER;
1542                          i_sad16 = sad16bi_c(                  pMB->mv16 = pMB->mvs[0] = pMB->mvs[1]
1543                                          frame->image.y + i*16 + j*16*edged_width,                          = pMB->mvs[2] = pMB->mvs[3] = currentMV[0];
                                         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;  
1544    
1545                    pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
1546                            pMB->sad8[2] = pMB->sad8[3] =  iMinSAD[0];
1547    
1548                          if (f_sad16 < b_sad16)                  pMB->pmvs[0].x = currentMV[0].x - Data.predMV.x;
1549                          {                  pMB->pmvs[0].y = currentMV[0].y - Data.predMV.y;
1550                                  best_sad = f_sad16;          } else {
1551                                  mb->mode = MB_FORWARD;  // INTER4V MODE; all other things are already set in Search8hinted
1552                          }                  pMB->mode = MODE_INTER4V;
1553                          else                  pMB->sad16 = iMinSAD[1] + iMinSAD[2] + iMinSAD[3] + iMinSAD[4] + IMV16X16 * iQuant;
                         {  
                                 best_sad = b_sad16;  
                                 mb->mode = MB_BACKWARD;  
1554                          }                          }
1555    
                         if (i_sad16 < best_sad)  
                         {  
                                 best_sad = i_sad16;  
                                 mb->mode = MB_INTERPOLATE;  
1556                          }                          }
1557    
1558                          if (d_sad16 < best_sad)  void
1559    MotionEstimationHinted( MBParam * const pParam,
1560                                                    FRAMEINFO * const current,
1561                                                    FRAMEINFO * const reference,
1562                                                    const IMAGE * const pRefH,
1563                                                    const IMAGE * const pRefV,
1564                                                    const IMAGE * const pRefHV)
1565                          {                          {
1566                                  best_sad = d_sad16;          MACROBLOCK *const pMBs = current->mbs;
1567                                  mb->mode = MB_DIRECT;          const IMAGE *const pCurrent = &current->image;
1568            const IMAGE *const pRef = &reference->image;
1569    
1570            uint32_t x, y;
1571    
1572            if (sadInit) (*sadInit) ();
1573    
1574            for (y = 0; y < pParam->mb_height; y++) {
1575                    for (x = 0; x < pParam->mb_width; x++)  {
1576                            int32_t sad00;
1577    
1578                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1579    
1580    //intra mode is copied from the first pass. At least for the time being
1581                            if  ((pMB->mode == MODE_INTRA) || (pMB->mode == MODE_NOT_CODED) ) continue;
1582    
1583                            if (!(current->global_flags & XVID_LUMIMASKING)) {
1584                                    pMB->dquant = NO_CHANGE;
1585                                    pMB->quant = current->quant; }
1586    
1587                            if (pMB->dquant == NO_CHANGE) //no skip otherwise, anyway
1588                                    sad00 = pMB->sad16
1589                                            = sad16(pCurrent->y + (x + y * pParam->edged_width) * 16,
1590                                                                    pRef->y + (x + y * pParam->edged_width) * 16,
1591                                                                    pParam->edged_width, 256*4096 );
1592                            else sad00 = 256*4096;
1593    
1594    
1595    //initial skip decision
1596    
1597                            if ( (pMB->dquant == NO_CHANGE) && (sad00 <= MAX_SAD00_FOR_SKIP * pMB->quant)
1598                                    && ( //(pMB->mode == MODE_NOT_CODED) ||
1599                                            (SkipDecisionP(pCurrent, pRef, x, y, pParam->edged_width, pMB->quant) )) ) {
1600                                    if (sad00 < pMB->quant * INITIAL_SKIP_THRESH) {
1601                                            SkipMacroblockP(pMB, sad00);
1602                                            continue; } //skipped
1603                          }                          }
1604                            else sad00 = 256*4096;
1605    
1606                            if (pMB->mode == MODE_NOT_CODED)
1607                                    SearchP(        pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1608                                                            y, current->motion_flags, pMB->quant,
1609                                                            current->fcode, pParam, pMBs, reference->mbs,
1610                                                            current->global_flags & XVID_INTER4V, pMB);
1611    
1612                            else
1613                                    SearchPhinted(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1614                                                            y, current->motion_flags, pMB->quant,
1615                                                            current->fcode, pParam, pMBs,
1616                                                            current->global_flags & XVID_INTER4V, pMB);
1617    
1618    /* final skip decision, a.k.a. "the vector you found, really that good?" */
1619                            if (sad00 < pMB->quant * MAX_SAD00_FOR_SKIP)
1620                                    if ((100*pMB->sad16)/(sad00+1) > FINAL_SKIP_THRESH)
1621                                    SkipMacroblockP(pMB, sad00);
1622    
1623                  }                  }
1624          }          }
1625  }  }
1626    
 */  

Legend:
Removed from v.132  
changed lines
  Added in v.530

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