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

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

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

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

Legend:
Removed from v.300  
changed lines
  Added in v.644

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