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

Legend:
Removed from v.289  
changed lines
  Added in v.675

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