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

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

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

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

Legend:
Removed from v.347  
changed lines
  Added in v.871

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