[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 346, Sun Jul 28 02:55:41 2002 UTC branches/dev-api-3/xvidcore/src/motion/motion_est.c revision 676, Mon Nov 25 13:38:56 2002 UTC
# Line 28  Line 28 
28   *   *
29   *************************************************************************/   *************************************************************************/
30    
 /**************************************************************************  
  *  
  *  Modifications:  
  *  
  *      01.05.2002      updated MotionEstimationBVOP  
  *      25.04.2002 partial prevMB conversion  
  *  22.04.2002 remove some compile warning by chenm001 <chenm001@163.com>  
  *  14.04.2002 added MotionEstimationBVOP()  
  *  02.04.2002 add EPZS(^2) as ME algorithm, use PMV_USESQUARES to choose between  
  *             EPZS and EPZS^2  
  *  08.02.2002 split up PMVfast into three routines: PMVFast, PMVFast_MainLoop  
  *             PMVFast_Refine to support multiple searches with different start points  
  *  07.01.2002 uv-block-based interpolation  
  *  06.01.2002 INTER/INTRA-decision is now done before any SEARCH8 (speedup)  
  *             changed INTER_BIAS to 150 (as suggested by suxen_drol)  
  *             removed halfpel refinement step in PMVfastSearch8 + quality=5  
  *             added new quality mode = 6 which performs halfpel refinement  
  *             filesize difference between quality 5 and 6 is smaller than 1%  
  *             (Isibaar)  
  *  31.12.2001 PMVfastSearch16 and PMVfastSearch8 (gruel)  
  *  30.12.2001 get_range/MotionSearchX simplified; blue/green bug fix  
  *  22.12.2001 commented best_point==99 check  
  *  19.12.2001 modified get_range (purple bug fix)  
  *  15.12.2001 moved pmv displacement from mbprediction  
  *  02.12.2001 motion estimation/compensation split (Isibaar)  
  *  16.11.2001 rewrote/tweaked search algorithms; pross@cs.rmit.edu.au  
  *  10.11.2001 support for sad16/sad8 functions  
  *  28.08.2001 reactivated MODE_INTER4V for EXT_MODE  
  *  24.08.2001 removed MODE_INTER4V_Q, disabled MODE_INTER4V for EXT_MODE  
  *  22.08.2001 added MODE_INTER4V_Q  
  *  20.08.2001 added pragma to get rid of internal compiler error with VC6  
  *             idea by Cyril. Thanks.  
  *  
  *  Michael Militzer <isibaar@videocoding.de>  
  *  
  **************************************************************************/  
   
31  #include <assert.h>  #include <assert.h>
32  #include <stdio.h>  #include <stdio.h>
33  #include <stdlib.h>  #include <stdlib.h>
# Line 74  Line 37 
37  #include "../prediction/mbprediction.h"  #include "../prediction/mbprediction.h"
38  #include "../global.h"  #include "../global.h"
39  #include "../utils/timer.h"  #include "../utils/timer.h"
40    #include "../image/interpolate8x8.h"
41    #include "motion_est.h"
42  #include "motion.h"  #include "motion.h"
43  #include "sad.h"  #include "sad.h"
44    #include "../utils/emms.h"
45    
46    #define INITIAL_SKIP_THRESH     (10)
47    #define FINAL_SKIP_THRESH       (50)
48    #define MAX_SAD00_FOR_SKIP      (20)
49    #define MAX_CHROMA_SAD_FOR_SKIP (22)
50    #define SKIP_THRESH_B (25)
51    
52    #define CHECK_CANDIDATE(X,Y,D) { \
53    (*CheckCandidate)((const int)(X),(const int)(Y), (D), &iDirection, data ); }
54    
55  static int32_t lambda_vec16[32] =       /* rounded values for lambda param for weight of motion bits as in modified H.26L */  #define 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    static __inline int
58  // mv.length table  d_mv_bits(int x, int y, const uint32_t iFcode)
 static const uint32_t mvtab[33] = {  
         1, 2, 3, 4, 6, 7, 7, 7,  
         9, 9, 9, 10, 10, 10, 10, 10,  
         10, 10, 10, 10, 10, 10, 10, 10,  
         10, 11, 11, 11, 11, 11, 11, 12, 12  
 };  
   
   
 static __inline uint32_t  
 mv_bits(int32_t component,  
                 const uint32_t iFcode)  
59  {  {
60          if (component == 0)          int xb, yb;
                 return 1;  
61    
62          if (component < 0)          if (x == 0) xb = 1;
63                  component = -component;          else {
64                    if (x < 0) x = -x;
65          if (iFcode == 1) {                  x += (1 << (iFcode - 1)) - 1;
66                  if (component > 32)                  x >>= (iFcode - 1);
67                          component = 32;                  if (x > 32) x = 32;
68                    xb = mvtab[x] + iFcode;
                 return mvtab[component] + 1;  
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          static const VECTOR zeroMV = { 0, 0 };          ref1 = GetReference(halfpel_x, halfpel_y, dir, data); // this reference is used in all cases
148          VECTOR predMV;          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                          predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          ref1 = GetReference(halfpel_x, halfpel_y, dir, data); // this reference is used in all cases
193            switch( ((x&1)<<1) + (y&1) ) {
194            case 0: // pure halfpel position
195                    return (uint8_t *) GetReference(halfpel_x, halfpel_y, dir, data);
196            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                          pMB->sad16 =          case 2: // x qpel, y halfpel - left or right during qpel refinement
205                                  SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,                  ref2 = GetReference(x - halfpel_x, halfpel_y, dir, data);
206                                                   x, y, predMV.x, predMV.y, predMV.x, predMV.y,                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
207                                                   current->motion_flags, current->quant,                  interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
208                                                   current->fcode, pParam, pMBs, prevMBs, &pMB->mv16,                  interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
209                                                   &pMB->pmvs[0]);                  interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
210                    break;
211    
212                          if (0 < (pMB->sad16 - MV16_INTER_BIAS)) {          default: // x and y in qpel resolution - the "corners" (top left/right and
213                                  int32_t deviation;                           // bottom left/right) during qpel refinement
214                    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                                  deviation =  /* CHECK_CANDIATE FUNCTIONS START */
                                         dev16(pCurrent->y + x * 16 + y * 16 * pParam->edged_width,  
                                                   pParam->edged_width);  
227    
228                                  if (deviation < (pMB->sad16 - MV16_INTER_BIAS)) {  static void
229                                          pMB->mode = MODE_INTRA;  CheckCandidate16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
230                                          pMB->mv16 = pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =  {
231                                                  pMB->mvs[3] = zeroMV;          int t, xc, yc;
232                                          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =          const uint8_t * Reference;
233                                                  pMB->sad8[3] = 0;          VECTOR * current;
234    
235                                          iIntra++;          if (( x > data->max_dx) || ( x < data->min_dx)
236                                          if (iIntra >= iLimit)                  || ( y > data->max_dy) || (y < data->min_dy)) return;
                                                 return 1;  
237    
238                                          continue;          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, predMV.x, predMV.y,  
                                                                         current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[0],  
                                                                         &pMB->pmvs[0]);  
                                         }  
                                         if (sad8 < pMB->sad16) {  
   
                                                 predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 1);  
                                                 sad8 += pMB->sad8[1] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x + 1, 2 * y,  
                                                                         pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,  
                                                                         current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[1],  
                                                                         &pMB->pmvs[1]);  
                                         }  
                                         if (sad8 < pMB->sad16) {  
                                                 predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 2);  
                                                 sad8 += pMB->sad8[2] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x, 2 * y + 1,  
                                                                         pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,  
                                                                         current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[2],  
                                                                         &pMB->pmvs[2]);  
                                         }  
                                         if (sad8 < pMB->sad16) {  
                                                 predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 3);  
                                                 sad8 += pMB->sad8[3] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x + 1, 2 * y + 1,  
                                                                         pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,  
                                                                         current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs,  
                                                                         &pMB->mvs[3],  
                                                                         &pMB->pmvs[3]);  
                                         }  
   
                                         /* 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; }
                                 pMB->sad16;  
                         }  
                         }  
267    
268          return 0;          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    
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(-center_x, -center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=0; currMV->y=0; }  }     \  
 }  
   
 #define NOCHECK_MV16_CANDIDATE(X,Y) { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \  
 }  
   
 #define CHECK_MV16_CANDIDATE(X,Y) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_CANDIDATE_DIR(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \  
 }  
   
 #define CHECK_MV16_CANDIDATE_FOUND(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
 }  
   
   
 #define CHECK_MV8_ZERO {\  
   iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, 0, 0 , iEdgedWidth), iEdgedWidth); \  
   iSAD += calc_delta_8(-center_x, -center_y, (uint8_t)iFcode, iQuant);\  
   if (iSAD < iMinSAD) \  
   { iMinSAD=iSAD; currMV->x=0; currMV->y=0; } \  
 }  
   
 #define NOCHECK_MV8_CANDIDATE(X,Y) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \  
 }  
   
 #define CHECK_MV8_CANDIDATE(X,Y) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV8_CANDIDATE_DIR(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \  
 }  
   
 #define CHECK_MV8_CANDIDATE_FOUND(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
 }  
   
 /* too slow and not fully functional at the moment */  
 /*  
 int32_t ZeroSearch16(  
                                         const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const IMAGE * const pCur,  
                                         const int x, const int y,  
                                         const uint32_t MotionFlags,  
                                         const uint32_t iQuant,  
                                         const uint32_t iFcode,  
                                         MBParam * const pParam,  
                                         const MACROBLOCK * const pMBs,  
                                         const MACROBLOCK * const prevMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
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;
286    
287            if (( x > data->max_dx) || ( x < data->min_dx)
288                    || ( y > data->max_dy) || (y < data->min_dy)) return;
289    
290            if (data->qpel_precision) { // x and y are in 1/4 precision
291                    Reference = Interpolate16x16qpel(x, y, 0, data);
292                    t = d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
293                    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          pred = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
307            sad += (data->lambda16 * t * sad)/1000;
308    
309          iSAD = sad16( cur,          if (sad < *(data->iMinSAD)) {
310                  get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth),                  *(data->iMinSAD) = sad;
311                  iEdgedWidth, MV_MAX_ERROR);                  current->x = x; current->y = y;
312          if (iSAD <= iQuant * 96)                  *dir = Direction; }
313                  iSAD -= MV16_00_BIAS;  }
314    
315          currMV->x = 0;  static void
316          currMV->y = 0;  CheckCandidate16no4vI(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
317          currPMV->x = -pred.x;  {
318          currPMV->y = -pred.y;  // maximum speed - for P/B/I decision
319            int32_t sad;
320    
321          return iSAD;          if (( x > data->max_dx) || ( x < data->min_dx)
322                    || ( y > data->max_dy) || (y < data->min_dy)) return;
323    
324  }          sad = sad16(data->Cur, data->Ref + x/2 + (y/2)*(data->iEdgedWidth),
325  */                                          data->iEdgedWidth, 256*4096);
326    
327  int32_t          if (sad < *(data->iMinSAD)) {
328  Diamond16_MainSearch(const uint8_t * const pRef,                  *(data->iMinSAD) = sad;
329                                           const uint8_t * const pRefH,                  data->currentMV[0].x = x; data->currentMV[0].y = y;
330                                           const uint8_t * const pRefV,                  *dir = Direction; }
331                                           const uint8_t * const pRefHV,  }
                                          const uint8_t * const cur,  
                                          const int x,  
                                          const int y,  
                                    const int start_x,  
                                    const int start_y,  
                                    int iMinSAD,  
                                    VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                          const int32_t min_dx,  
                                          const int32_t max_dx,  
                                          const int32_t min_dy,  
                                          const int32_t max_dy,  
                                          const int32_t iEdgedWidth,  
                                          const int32_t iDiamondSize,  
                                          const int32_t iFcode,  
                                          const int32_t iQuant,  
                                          int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iDirectionBackup;  
         int32_t iSAD;  
         VECTOR backupMV;  
332    
         backupMV.x = start_x;  
         backupMV.y = start_y;  
333    
334  /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  static void
335    CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)
336    {
337            int32_t sad;
338            int xb, yb, t;
339            const uint8_t *ReferenceF, *ReferenceB;
340            VECTOR *current;
341    
342          CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);          if (( xf > data->max_dx) || ( xf < data->min_dx)
343          CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);                  || ( yf > data->max_dy) || (yf < data->min_dy)) return;
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
344    
345          if (iDirection) {          if (data->qpel_precision) {
346                  while (!iFound) {                  ReferenceF = Interpolate16x16qpel(xf, yf, 0, data);
347                          iFound = 1;                  xb = data->currentQMV[1].x; yb = data->currentQMV[1].y;
348                          backupMV = *currMV;                  current = data->currentQMV;
349                          iDirectionBackup = iDirection;                  ReferenceB = Interpolate16x16qpel(xb, yb, 1, data);
350                    t = d_mv_bits(xf - data->predMV.x, yf - data->predMV.y, data->iFcode)
351                          if (iDirectionBackup != 2)                                   + d_mv_bits(xb - data->bpredMV.x, yb - data->bpredMV.y, data->iFcode);
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                    backupMV.y, 1);  
                         if (iDirectionBackup != 1)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                    backupMV.y, 2);  
                         if (iDirectionBackup != 4)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,  
                                                                                    backupMV.y - iDiamondSize, 3);  
                         if (iDirectionBackup != 3)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,  
                                                                                    backupMV.y + iDiamondSize, 4);  
                 }  
352          } else {          } else {
353                  currMV->x = start_x;                  ReferenceF = Interpolate16x16qpel(2*xf, 2*yf, 0, data);
354                  currMV->y = start_y;                  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          return iMinSAD;  
365            sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
366            sad += (data->lambda16 * t * sad)/1000;
367    
368            if (sad < *(data->iMinSAD)) {
369                    *(data->iMinSAD) = sad;
370                    current->x = xf; current->y = yf;
371                    *dir = Direction; }
372  }  }
373    
374  int32_t  static void
375  Square16_MainSearch(const uint8_t * const pRef,  CheckCandidateDirect(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x,  
                                         const int y,  
                                    const int start_x,  
                                    const int start_y,  
                                    int iMinSAD,  
                                    VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
376  {  {
377  /* Do a square search around given starting point, return SAD of best */          int32_t sad = 0;
378            int k;
379            const uint8_t *ReferenceF;
380            const uint8_t *ReferenceB;
381            VECTOR mvs, b_mvs;
382    
383          int32_t iDirection = 0;          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
         int32_t iSAD;  
         VECTOR backupMV;  
384    
385          backupMV.x = start_x;          for (k = 0; k < 4; k++) {
386          backupMV.y = start_y;                  mvs.x = data->directmvF[k].x + x;
387                    b_mvs.x = ((x == 0) ?
388                            data->directmvB[k].x
389                            : mvs.x - data->referencemv[k].x);
390    
391  /* It's one search with full square pattern, and new parts for all following diamonds */                  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  /*   new direction are extra, so 1-4 is normal diamond                  if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
397        537                          || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
398        1*2                          || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
399        648                          || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
 */  
   
         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);  
400    
401                    if (!data->qpel) {
402                            mvs.x *= 2; mvs.y *= 2;
403                            b_mvs.x *= 2; b_mvs.y *= 2; //we move to qpel precision anyway
404                    }
405                    ReferenceF = Interpolate8x8qpel(mvs.x, mvs.y, k, 0, data);
406                    ReferenceB = Interpolate8x8qpel(b_mvs.x, b_mvs.y, k, 1, data);
407    
408          if (iDirection) {                  sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
409                  while (!iFound) {                                                  ReferenceF, ReferenceB,
410                          iFound = 1;                                                  data->iEdgedWidth);
411                          backupMV = *currMV;                  if (sad > *(data->iMinSAD)) return;
412            }
413    
414                          switch (iDirection) {          sad += (data->lambda16 * d_mv_bits(x, y, 1) * sad)/1000;
                         case 1:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                    backupMV.y, 1);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
                         case 2:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
415    
416                          case 3:          if (sad < *(data->iMinSAD)) {
417                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                  *(data->iMinSAD) = sad;
418                                                                                   4);                  data->currentMV->x = x; data->currentMV->y = y;
419                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                  *dir = Direction; }
420                                                                                   backupMV.y - iDiamondSize, 7);  }
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
421    
422                          case 4:  static void
423                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  CheckCandidateDirectno4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
424                                                                                   3);  {
425                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          int32_t sad;
426                                                                                   backupMV.y - iDiamondSize, 5);          const uint8_t *ReferenceF;
427                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          const uint8_t *ReferenceB;
428                                                                                   backupMV.y + iDiamondSize, 6);          VECTOR mvs, b_mvs;
                                 break;  
   
                         case 5:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
   
                         case 6:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
   
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
429    
430                                  break;          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
431    
432                          case 7:          mvs.x = data->directmvF[0].x + x;
433                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          b_mvs.x = ((x == 0) ?
434                                                                                     backupMV.y, 1);                  data->directmvB[0].x
435                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                  : mvs.x - data->referencemv[0].x);
                                                                                  4);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
436    
437                          case 8:          mvs.y = data->directmvF[0].y + y;
438                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,          b_mvs.y = ((y == 0) ?
439                                                                                   2);                  data->directmvB[0].y
440                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,                  : mvs.y - data->referencemv[0].y);
441                                                                                   4);  
442                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
443                                                                                   backupMV.y + iDiamondSize, 6);                  || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
444                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,                  || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
445                                                                                   backupMV.y - iDiamondSize, 7);                  || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
446                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
447                                                                                   backupMV.y + iDiamondSize, 8);          if (!data->qpel) {
448                                  break;                          mvs.x *= 2; mvs.y *= 2;
449                          default:                          b_mvs.x *= 2; b_mvs.y *= 2; //we move to qpel precision anyway
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
   
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         }  
                 }  
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
         }  
         return iMinSAD;  
450  }  }
451            ReferenceF = Interpolate16x16qpel(mvs.x, mvs.y, 0, data);
452            ReferenceB = Interpolate16x16qpel(b_mvs.x, b_mvs.y, 1, data);
453    
454            sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
455            sad += (data->lambda16 * d_mv_bits(x, y, 1) * sad)/1000;
456    
457  int32_t          if (sad < *(data->iMinSAD)) {
458  Full16_MainSearch(const uint8_t * const pRef,                  *(data->iMinSAD) = sad;
459                                    const uint8_t * const pRefH,                  data->currentMV->x = x; data->currentMV->y = y;
460                                    const uint8_t * const pRefV,                  *dir = Direction; }
461                                    const uint8_t * const pRefHV,  }
462                                    const uint8_t * const cur,  
463                                    const int x,  static void
464                                    const int y,  CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                                    const int start_x,  
                                    const int start_y,  
                                    int iMinSAD,  
                                    VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                   const int32_t min_dx,  
                                   const int32_t max_dx,  
                                   const int32_t min_dy,  
                                   const int32_t max_dy,  
                                   const int32_t iEdgedWidth,  
                                   const int32_t iDiamondSize,  
                                   const int32_t iFcode,  
                                   const int32_t iQuant,  
                                   int iFound)  
465  {  {
466          int32_t iSAD;          int32_t sad; int t;
467          int32_t dx, dy;          const uint8_t * Reference;
468          VECTOR backupMV;  
469            if (( x > data->max_dx) || ( x < data->min_dx)
470                    || ( y > data->max_dy) || (y < data->min_dy)) return;
471    
472          backupMV.x = start_x;          if (data->qpel) Reference = Interpolate16x16qpel(x, y, 0, data);
473          backupMV.y = start_y;          else Reference = Interpolate16x16qpel(2*x, 2*y, 0, data);
474    
475          for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)          sad = sad8(data->Cur, Reference, data->iEdgedWidth);
476                  for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)          if (data->qpel) t = d_mv_bits(2 * x - data->predMV.x, 2 * y - data->predMV.y, data->iFcode);
477                          NOCHECK_MV16_CANDIDATE(dx, dy);          else t = d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
478    
479          return iMinSAD;          sad += (data->lambda8 * t * (sad+NEIGH_8X8_BIAS))/100;
480    
481            if (sad < *(data->iMinSAD)) {
482                    *(data->iMinSAD) = sad;
483                    data->currentMV->x = x; data->currentMV->y = y;
484                    *dir = Direction; }
485  }  }
486    
487  int32_t  /* CHECK_CANDIATE FUNCTIONS END */
488  AdvDiamond16_MainSearch(const uint8_t * const pRef,  
489                                                  const uint8_t * const pRefH,  /* MAINSEARCH FUNCTIONS START */
                                                 const uint8_t * const pRefV,  
                                                 const uint8_t * const pRefHV,  
                                                 const uint8_t * const cur,  
                                                 const int x,  
                                                 const int y,  
                                            int start_x,  
                                            int start_y,  
                                            int iMinSAD,  
                                            VECTOR * const currMV,  
                                            const int center_x,  
                                            const int center_y,  
                                                 const int32_t min_dx,  
                                                 const int32_t max_dx,  
                                                 const int32_t min_dy,  
                                                 const int32_t max_dy,  
                                                 const int32_t iEdgedWidth,  
                                                 const int32_t iDiamondSize,  
                                                 const int32_t iFcode,  
                                                 const int32_t iQuant,  
                                                 int iDirection)  
 {  
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_MV16_CANDIDATE(start_x - iDiamondSize, start_y);  
                 CHECK_MV16_CANDIDATE(start_x + iDiamondSize, start_y);  
                 CHECK_MV16_CANDIDATE(start_x, start_y - iDiamondSize);  
                 CHECK_MV16_CANDIDATE(start_x, start_y + 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_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 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_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
   
                         if (bDirection & 4)  
                                 CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);  
   
                         if (bDirection & 8)  
                                 CHECK_MV16_CANDIDATE_DIR(start_x, start_y + 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                                  start_x = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
512                                  start_y = 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_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);                                  } else {                        // what remains here is up or down
516                                          CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y, 2);
517                                  } else                  // what remains here is up or down                                          CHECK_CANDIDATE(x - iDiamondSize, y, 1); }
                                 {  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
                                 }  
518    
519                                  if (iDirection) {                                  if (iDirection) {
520                                          bDirection += iDirection;                                          bDirection += iDirection;
521                                          start_x = currMV->x;                                          x = data->currentMV->x; y = data->currentMV->y; }
522                                          start_y = 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_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
526                                                                                           start_y - iDiamondSize, 2 + 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
527                                          break;                                          break;
528                                  case 1:                                  case 1:
529                                            CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
530                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
531                                          break;                                          break;
532                                  case 2 + 4:                                  case 2 + 4:
533                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
534                                                                                           start_y - iDiamondSize, 1 + 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
535                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
536                                          break;                                          break;
537                                  case 4:                                  case 4:
538                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
539                                                                                           start_y - iDiamondSize, 2 + 4);                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y - iDiamondSize, 1 + 4);  
540                                          break;                                          break;
541                                  case 8:                                  case 8:
542                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
543                                                                                           start_y + iDiamondSize, 2 + 8);                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
544                                          break;                                          break;
545                                  case 1 + 4:                                  case 1 + 4:
546                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
547                                                                                           start_y + iDiamondSize, 1 + 8);                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
548                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
549                                          break;                                          break;
550                                  case 2 + 8:                                  case 2 + 8:
551                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
552                                                                                           start_y - iDiamondSize, 1 + 4);                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
553                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
554                                          break;                                          break;
555                                  case 1 + 8:                                  case 1 + 8:
556                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
557                                                                                           start_y - iDiamondSize, 2 + 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
558                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + 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_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
562                                                                                           start_y - iDiamondSize, 1 + 4);                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
563                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
564                                                                                           start_y + iDiamondSize, 1 + 8);                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
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                                          start_x = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
                                         start_y = currMV->y;  
                                 }  
570                          }                          }
571                  }                  }
572                  while (1);                              //forever                  while (1);                              //forever
573          }          }
         return iMinSAD;  
 }  
   
 #define CHECK_MV16_F_INTERPOL(X,Y) { \  
   if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \  
     && ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, b_currMV->x, b_currMV->y, iEdgedWidth),   \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16((X) - f_center_x, (Y) - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16(b_currMV->x - b_center_x, b_currMV->y - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; f_currMV->x=(X); f_currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_F_INTERPOL_FOUND(X,Y) { \  
   if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \  
     && ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, b_currMV->x, b_currMV->y, iEdgedWidth),   \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16((X) - f_center_x, (Y) - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16(b_currMV->x - b_center_x, b_currMV->y - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; f_currMV->x=(X); f_currMV->y=(Y); iFound=0;} } \  
 }  
   
 #define CHECK_MV16_B_INTERPOL(X,Y) { \  
   if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \  
     && ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth),   \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16((X) - b_center_x, (Y) - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; b_currMV->x=(X); b_currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_B_INTERPOL_FOUND(X,Y) { \  
   if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \  
     && ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth),   \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16((X) - b_center_x, (Y) - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; b_currMV->x=(X); b_currMV->y=(Y); iFound=0;} } \  
 }  
   
 int32_t  
 Diamond16_InterpolMainSearch(  
                                         const uint8_t * const f_pRef,  
                                          const uint8_t * const f_pRefH,  
                                          const uint8_t * const f_pRefV,  
                                          const uint8_t * const f_pRefHV,  
   
                                          const uint8_t * const cur,  
   
                                         const uint8_t * const b_pRef,  
                                          const uint8_t * const b_pRefH,  
                                          const uint8_t * const b_pRefV,  
                                          const uint8_t * const b_pRefHV,  
   
                                          const int x,  
                                          const int y,  
   
                                    const int f_start_x,  
                                    const int f_start_y,  
                                    const int b_start_x,  
                                    const int b_start_y,  
   
                                    int iMinSAD,  
                                    VECTOR * const f_currMV,  
                                    VECTOR * const b_currMV,  
   
                                    const int f_center_x,  
                                    const int f_center_y,  
                                    const int b_center_x,  
                                    const int b_center_y,  
   
                                     const int32_t f_min_dx,  
                                         const int32_t f_max_dx,  
                                         const int32_t f_min_dy,  
                                         const int32_t f_max_dy,  
   
                                     const int32_t b_min_dx,  
                                         const int32_t b_max_dx,  
                                         const int32_t b_min_dy,  
                                         const int32_t b_max_dy,  
   
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
   
                                         const int32_t f_iFcode,  
                                         const int32_t b_iFcode,  
   
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iSAD;  
   
         VECTOR f_backupMV;  
         VECTOR b_backupMV;  
   
         f_currMV->x = f_start_x;  
         f_currMV->y = f_start_y;  
         b_currMV->x = b_start_x;  
         b_currMV->y = b_start_y;  
   
         do  
         {  
                 iFound = 1;  
   
                 f_backupMV = *f_currMV;  
   
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x - iDiamondSize, f_backupMV.y);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x + iDiamondSize, f_backupMV.y);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y - iDiamondSize);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y + iDiamondSize);  
   
                 b_backupMV = *b_currMV;  
   
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x - iDiamondSize, b_backupMV.y);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x + iDiamondSize, b_backupMV.y);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y - iDiamondSize);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y + iDiamondSize);  
   
         } while (!iFound);  
   
         return iMinSAD;  
 }  
   
 /* Sorry, these MACROS really got too large... I'll turn them into function soon! */  
   
 #define CHECK_MV16_DIRECT_FOUND(X,Y) \  
         if ( (X)>=(-32) && (X)<=(31) && ((Y)>=-32) && ((Y)<=31) ) \  
         { int k;\  
         VECTOR mvs,b_mvs;       \  
         iSAD = 0;\  
         for (k = 0; k < 4; k++) {       \  
                                         mvs.x = (int32_t) ((TRB * directmv[k].x) / TRD + (X));          \  
                     b_mvs.x = (int32_t) (((X) == 0)                                                     \  
                                                                                 ? ((TRB - TRD) * directmv[k].x) / TRD   \  
                                             : mvs.x - directmv[k].x);                           \  
                                                                                                                                                                 \  
                     mvs.y = (int32_t) ((TRB * directmv[k].y) / TRD + (Y));              \  
                         b_mvs.y = (int32_t) (((Y) == 0)                                                         \  
                                                                                 ? ((TRB - TRD) * directmv[k].y) / TRD   \  
                                             : mvs.y - directmv[k].y);                           \  
                                                                                                                                                                 \  
   if ( (mvs.x <= max_dx) && (mvs.x >= min_dx) \  
     && (mvs.y <= max_dy) && (mvs.y >= min_dy)  \  
         && (b_mvs.x <= max_dx) && (b_mvs.x >= min_dx)  \  
     && (b_mvs.y <= max_dy) && (b_mvs.y >= min_dy) ) { \  
             iSAD += sad8bi( cur + 8*(k&1) + 8*(k>>1)*iEdgedWidth,                                                                                                       \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \  
                                         mvs.x, mvs.y, iEdgedWidth),                                                             \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \  
                                         b_mvs.x, b_mvs.y, iEdgedWidth),                                                         \  
                         iEdgedWidth); \  
                 }       \  
         else    \  
                 iSAD = 65535;   \  
         } \  
         iSAD += calc_delta_16((X),(Y), 1, iQuant);\  
         if (iSAD < iMinSAD) \  
             {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iFound=0; } \  
 }  
   
   
   
 int32_t  
 Diamond16_DirectMainSearch(  
                                         const uint8_t * const f_pRef,  
                                         const uint8_t * const f_pRefH,  
                                         const uint8_t * const f_pRefV,  
                                         const uint8_t * const f_pRefHV,  
   
                                         const uint8_t * const cur,  
   
                                         const uint8_t * const b_pRef,  
                                         const uint8_t * const b_pRefH,  
                                         const uint8_t * const b_pRefV,  
                                         const uint8_t * const b_pRefHV,  
   
                                         const int x,  
                                         const int y,  
   
                                         const int TRB,  
                                         const int TRD,  
   
                                     const int start_x,  
                                     const int start_y,  
   
                                     int iMinSAD,  
                                     VECTOR * const currMV,  
                                         const VECTOR * const directmv,  
574    
575                                      const int32_t min_dx,  static void
576                                          const int32_t max_dx,  SquareSearch(int x, int y, const SearchData * const data, int bDirection)
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
   
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
   
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iSAD;  
   
         VECTOR backupMV;  
   
         currMV->x = start_x;  
         currMV->y = start_y;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         do  
577          {          {
578                  iFound = 1;          int iDirection;
   
                 backupMV = *currMV;  
579    
580                  CHECK_MV16_DIRECT_FOUND(backupMV.x - iDiamondSize, backupMV.y);          do {
581                  CHECK_MV16_DIRECT_FOUND(backupMV.x + iDiamondSize, backupMV.y);                  iDirection = 0;
582                  CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y - iDiamondSize);                  if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);
583                  CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y + iDiamondSize);                  if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);
584                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);
585          } while (!iFound);                  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                    if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128);
590    
591          return iMinSAD;                  bDirection = iDirection;
592                    x = data->currentMV->x; y = data->currentMV->y;
593            } while (iDirection);
594  }  }
595    
596    static void
597  int32_t  DiamondSearch(int x, int y, const SearchData * const data, int bDirection)
 AdvDiamond8_MainSearch(const uint8_t * const pRef,  
                                            const uint8_t * const pRefH,  
                                            const uint8_t * const pRefV,  
                                            const uint8_t * const pRefHV,  
                                            const uint8_t * const cur,  
                                            const int x,  
                                            const int y,  
                                            int start_x,  
                                            int start_y,  
                                            int iMinSAD,  
                                            VECTOR * const currMV,  
                                            const int center_x,  
                                            const int center_y,  
                                            const int32_t min_dx,  
                                            const int32_t max_dx,  
                                            const int32_t min_dy,  
                                            const int32_t max_dy,  
                                            const int32_t iEdgedWidth,  
                                            const int32_t iDiamondSize,  
                                            const int32_t iFcode,  
                                            const int32_t iQuant,  
                                            int iDirection)  
598  {  {
599    
         int32_t iSAD;  
   
600  /* 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) */
601    
602          if (iDirection) {                  int iDirection;
                 CHECK_MV8_CANDIDATE(start_x - iDiamondSize, start_y);  
                 CHECK_MV8_CANDIDATE(start_x + iDiamondSize, start_y);  
                 CHECK_MV8_CANDIDATE(start_x, start_y - iDiamondSize);  
                 CHECK_MV8_CANDIDATE(start_x, start_y + iDiamondSize);  
         } else {  
                 int bDirection = 1 + 2 + 4 + 8;  
603    
604                  do {                  do {
605                          iDirection = 0;                          iDirection = 0;
606                          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);
607                                  CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);                          if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
608                            if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
609                          if (bDirection & 2)                          if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
                                 CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
   
                         if (bDirection & 4)  
                                 CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);  
   
                         if (bDirection & 8)  
                                 CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
610    
611                          /* now we're doing diagonal checks near our candidate */                          /* now we're doing diagonal checks near our candidate */
612    
613                          if (iDirection)         //checking if anything found                          if (iDirection) {               //checking if anything found
                         {  
614                                  bDirection = iDirection;                                  bDirection = iDirection;
615                                  iDirection = 0;                                  iDirection = 0;
616                                  start_x = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
617                                  start_y = currMV->y;                                  if (bDirection & 3) {   //our candidate is left or right
618                                  if (bDirection & 3)     //our candidate is left or right                                          CHECK_CANDIDATE(x, y + iDiamondSize, 8);
619                                  {                                          CHECK_CANDIDATE(x, y - iDiamondSize, 4);
620                                          CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);                                  } else {                        // what remains here is up or down
621                                          CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y, 2);
622                                  } else                  // what remains here is up or down                                          CHECK_CANDIDATE(x - iDiamondSize, y, 1); }
                                 {  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
                                 }  
623    
                                 if (iDirection) {  
624                                          bDirection += iDirection;                                          bDirection += iDirection;
625                                          start_x = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
                                         start_y = currMV->y;  
                                 }  
                         } else                          //about to quit, eh? not so fast....  
                         {  
                                 switch (bDirection) {  
                                 case 2:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 2 + 4:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 4:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         break;  
                                 case 8:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 1 + 4:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         break;  
                                 case 2 + 8:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1 + 8:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         break;  
                                 default:                //1+2+4+8 == we didn't find anything at all  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 }  
                                 if (!(iDirection))  
                                         break;          //ok, the end. really  
                                 else {  
                                         bDirection = iDirection;  
                                         start_x = currMV->x;  
                                         start_y = currMV->y;  
                                 }  
                         }  
626                  }                  }
                 while (1);                              //forever  
627          }          }
628          return iMinSAD;                  while (iDirection);
629  }  }
630    
631    /* MAINSEARCH FUNCTIONS END */
632    
633  int32_t  /* HALFPELREFINE COULD BE A MAINSEARCH FUNCTION, BUT THERE IS NO NEED FOR IT */
634  Full8_MainSearch(const uint8_t * const pRef,  
635                                   const uint8_t * const pRefH,  static void
636                                   const uint8_t * const pRefV,  SubpelRefine(const SearchData * const data)
                                  const uint8_t * const pRefHV,  
                                  const uint8_t * const cur,  
                                  const int x,  
                                  const int y,  
                            const int start_x,  
                            const int start_y,  
                            int iMinSAD,  
                            VECTOR * const currMV,  
                            const int center_x,  
                            const int center_y,  
                                  const int32_t min_dx,  
                                  const int32_t max_dx,  
                                  const int32_t min_dy,  
                                  const int32_t max_dy,  
                                  const int32_t iEdgedWidth,  
                                  const int32_t iDiamondSize,  
                                  const int32_t iFcode,  
                                  const int32_t iQuant,  
                                  int iFound)  
637  {  {
638          int32_t iSAD;  /* Do a half-pel or q-pel refinement */
         int32_t dx, dy;  
639          VECTOR backupMV;          VECTOR backupMV;
640            int iDirection; //not needed
641    
642            if (data->qpel_precision)
643                    backupMV = *(data->currentQMV);
644            else backupMV = *(data->currentMV);
645    
646          backupMV.x = start_x;          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y - 1, 0);
647          backupMV.y = start_y;          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y - 1, 0);
648            CHECK_CANDIDATE(backupMV.x - 1, backupMV.y + 1, 0);
649            CHECK_CANDIDATE(backupMV.x + 1, backupMV.y + 1, 0);
650    
651          for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y, 0);
652                  for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y, 0);
                         NOCHECK_MV8_CANDIDATE(dx, dy);  
653    
654          return iMinSAD;          CHECK_CANDIDATE(backupMV.x, backupMV.y + 1, 0);
655            CHECK_CANDIDATE(backupMV.x, backupMV.y - 1, 0);
656  }  }
657    
658  Halfpel8_RefineFuncPtr Halfpel8_Refine;  static __inline int
659    SkipDecisionP(const IMAGE * current, const IMAGE * reference,
660                                                            const int x, const int y,
661                                                            const uint32_t iEdgedWidth, const uint32_t iQuant)
662    
663  int32_t  {
664  Halfpel16_Refine(const uint8_t * const pRef,  /*      keep repeating checks for all b-frames before this P frame,
665                                   const uint8_t * const pRefH,          to make sure that SKIP is possible (todo)
666                                   const uint8_t * const pRefV,          how: if skip is not possible set sad00 to a very high value */
667                                   const uint8_t * const pRefHV,  
668                                   const uint8_t * const cur,          uint32_t sadC = sad8(current->u + x*8 + y*(iEdgedWidth/2)*8,
669                                   const int x,                                          reference->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2);
670                                   const int y,          if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
671                                   VECTOR * const currMV,          sadC += sad8(current->v + (x + y*(iEdgedWidth/2))*8,
672                                   int32_t iMinSAD,                                          reference->v + (x + y*(iEdgedWidth/2))*8, iEdgedWidth/2);
673                             const int center_x,          if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
                            const int center_y,  
                                  const int32_t min_dx,  
                                  const int32_t max_dx,  
                                  const int32_t min_dy,  
                                  const int32_t max_dy,  
                                  const int32_t iFcode,  
                                  const int32_t iQuant,  
                                  const int32_t iEdgedWidth)  
 {  
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
   
         int32_t iSAD;  
         VECTOR backupMV = *currMV;  
   
         CHECK_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);  
674    
675          return iMinSAD;          return 1;
676  }  }
677    
678  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)  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            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;
687    
688            pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
689    }
690    
691  int32_t  bool
692  PMVfastSearch16(const uint8_t * const pRef,  MotionEstimation(MBParam * const pParam,
693                                  const uint8_t * const pRefH,                                   FRAMEINFO * const current,
694                                  const uint8_t * const pRefV,                                   FRAMEINFO * const reference,
695                                  const uint8_t * const pRefHV,                                   const IMAGE * const pRefH,
696                                  const IMAGE * const pCur,                                   const IMAGE * const pRefV,
697                                  const int x,                                   const IMAGE * const pRefHV,
698                                  const int y,                                   const uint32_t iLimit)
                                 const int start_x,      /* start is searched first, so it should contain the most */  
                                 const int start_y,  /* likely motion vector for this block */  
                                 const int center_x,     /* center is from where length of MVs is measured */  
                                 const int center_y,  
                                 const uint32_t MotionFlags,  
                                 const uint32_t iQuant,  
                                 const uint32_t iFcode,  
                                 const MBParam * const pParam,  
                                 const MACROBLOCK * const pMBs,  
                                 const MACROBLOCK * const prevMBs,  
                                 VECTOR * const currMV,  
                                 VECTOR * const currPMV)  
699  {  {
700          const uint32_t iWcount = pParam->mb_width;          MACROBLOCK *const pMBs = current->mbs;
701          const int32_t iWidth = pParam->width;          const IMAGE *const pCurrent = &current->image;
702          const int32_t iHeight = pParam->height;          const IMAGE *const pRef = &reference->image;
         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;  
   
         int32_t threshA, threshB;  
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD;  
703    
704  /* Get maximum range */          const VECTOR zeroMV = { 0, 0 };
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
705    
706  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          uint32_t x, y;
707            uint32_t iIntra = 0;
708            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 (!(MotionFlags & PMV_HALFPEL16)) {  //initial skip decision
766                  min_dx = EVEN(min_dx);  /* no early skip for GMC (global vector = skip vector is unknown!)  */
767                  max_dx = EVEN(max_dx);                          if (current->coding_type == P_VOP)      { /* no fast SKIP for S(GMC)-VOPs */
768                  min_dy = EVEN(min_dy);                                  if (pMB->dquant == NO_CHANGE && sad00 < pMB->quant * INITIAL_SKIP_THRESH)
769                  max_dy = EVEN(max_dy);                                          if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, pParam->edged_width, pMB->quant)) {
770                                                    SkipMacroblockP(pMB, sad00);
771                                                    continue;
772                                            }
773          }          }
774    
775          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */                          SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
776          //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);                                                  y, current->motion_flags, pMB->quant,
777          bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);                                                  &Data, pParam, pMBs, reference->mbs,
778                                                    current->global_flags & XVID_INTER4V, pMB);
779          if ((x == 0) && (y == 0)) {  
780                  threshA = 512;  /* final skip decision, a.k.a. "the vector you found, really that good?" */
781                  threshB = 1024;                          if (current->coding_type == P_VOP)      {
782          } else {                                  if ( (pMB->dquant == NO_CHANGE) && (sad00 < pMB->quant * MAX_SAD00_FOR_SKIP)
783                  threshA = psad[0];                                  && ((100*pMB->sad16)/(sad00+1) > FINAL_SKIP_THRESH) )
784                  threshB = threshA + 256;                                          if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, pParam->edged_width, pMB->quant)) {
785                  if (threshA < 512)                                                  SkipMacroblockP(pMB, sad00);
786                          threshA = 512;                                                  continue;
787                  if (threshA > 1024)                                          }
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
788          }          }
789    
790          iFound = 0;  /* finally, intra decision */
791    
792  /* Step 4: Calculate SAD around the Median prediction.                          InterBias = MV16_INTER_BIAS;
793     MinSAD=SAD                          if (pMB->quant > 8)  InterBias += 100 * (pMB->quant - 8); // to make high quants work
794     If Motion Vector equal to Previous frame motion vector                          if (y != 0)
795     and MinSAD<PrevFrmSAD goto Step 10.                                  if ((pMB - pParam->mb_width)->mode == MODE_INTRA ) InterBias -= 80;
796     If SAD<=256 goto Step 10.                          if (x != 0)
797  */                                  if ((pMB - 1)->mode == MODE_INTRA ) InterBias -= 80;
798    
799          currMV->x = start_x;                          if (Data.chroma) InterBias += 50; // to compensate bigger SAD
         currMV->y = start_y;  
800    
801          if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */                          if (InterBias < pMB->sad16)  {
802                  currMV->x = EVEN(currMV->x);                                  const int32_t deviation =
803                  currMV->y = EVEN(currMV->y);                                          dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,
804          }                                                    pParam->edged_width);
805    
806          if (currMV->x > max_dx) {                                  if (deviation < (pMB->sad16 - InterBias)) {
807                  currMV->x = max_dx;                                          if (++iIntra >= iLimit) { free(qimage); return 1; }
808                                            pMB->mode = MODE_INTRA;
809                                            pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =
810                                                            pMB->mvs[3] = zeroMV;
811                                            pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] =
812                                                            pMB->qmvs[3] = zeroMV;
813                                            pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =
814                                                    pMB->sad8[3] = 0;
815                                    }
816          }          }
         if (currMV->x < min_dx) {  
                 currMV->x = min_dx;  
817          }          }
         if (currMV->y > max_dy) {  
                 currMV->y = max_dy;  
818          }          }
819          if (currMV->y < min_dy) {          free(qimage);
820                  currMV->y = min_dy;  
821            if (current->coding_type == S_VOP)      /* first GMC step only for S(GMC)-VOPs */
822                    current->GMC_MV = GlobalMotionEst( pMBs, pParam, current->fcode );
823            else
824                    current->GMC_MV = zeroMV;
825    
826            return 0;
827          }          }
828    
         iMinSAD =  
                 sad16(cur,  
                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
829    
830          if ((iMinSAD < 256) ||  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)
831                  ((MVequal(*currMV, prevMB->mvs[0])) &&  
832                   ((int32_t) iMinSAD < prevMB->sad16))) {  static __inline int
833                  if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  make_mask(const VECTOR * const pmv, const int i)
834                  {                  {
835                          if (!MVzero(*currMV)) {          int mask = 255, j;
836                                  iMinSAD += MV16_00_BIAS;          for (j = 0; j < i; j++) {
837                                  CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures                  if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already
838                                  iMinSAD -= MV16_00_BIAS;                  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;
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
848          }          }
849    
850    static __inline void
851    PreparePredictionsP(VECTOR * const pmv, int x, int y, const int iWcount,
852                            const int iHcount, const MACROBLOCK * const prevMB)
853    {
854    
855  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself
    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;  
856    
857  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          if ( (y != 0) && (x != (iWcount-1)) ) {         // [5] top-right neighbour
858     Otherwise select large Diamond Search.                  pmv[5].x = EVEN(pmv[3].x);
859  */                  pmv[5].y = EVEN(pmv[3].y);
860            } else pmv[5].x = pmv[5].y = 0;
861    
862          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))          if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }// pmv[3] is left neighbour
863                  iDiamondSize = 1;               // halfpel!          else pmv[3].x = pmv[3].y = 0;
         else  
                 iDiamondSize = 2;               // halfpel!  
864    
865          if (!(MotionFlags & PMV_HALFPELDIAMOND16))          if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }// [4] top neighbour
866                  iDiamondSize *= 2;      else pmv[4].x = pmv[4].y = 0;
867    
868  /*          // [1] median prediction
869     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.          pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
    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.  
 */  
870    
871  // (0,0) is always possible          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          if (!MVzero(pmv[0]))          pmv[2].x = EVEN(prevMB->mvs[0].x); // [2] is last frame
874                  CHECK_MV16_ZERO;          pmv[2].y = EVEN(prevMB->mvs[0].y);
875    
876  // previous frame MV is always possible          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          if (!MVzero(prevMB->mvs[0]))  static void
883                  if (!MVequal(prevMB->mvs[0], pmv[0]))  SearchP(const IMAGE * const pRef,
884                          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);                  const uint8_t * const pRefH,
885                    const uint8_t * const pRefV,
886                    const uint8_t * const pRefHV,
887                    const IMAGE * const pCur,
888                    const int x,
889                    const int y,
890                    const uint32_t MotionFlags,
891                    const uint32_t iQuant,
892                    SearchData * const Data,
893                    const MBParam * const pParam,
894                    const MACROBLOCK * const pMBs,
895                    const MACROBLOCK * const prevMBs,
896                    int inter4v,
897                    MACROBLOCK * const pMB)
898    {
899    
900  // left neighbour, if allowed          int i, iDirection = 255, mask, threshA;
901            VECTOR pmv[7];
902    
903          if (!MVzero(pmv[1]))          get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);  //has to be changed to get_pmv(2)()
904                  if (!MVequal(pmv[1], prevMB->mvs[0]))          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
905                          if (!MVequal(pmv[1], pmv[0])) {                                  pParam->width, pParam->height, Data->iFcode, pParam->m_quarterpel);
906                                  if (!(MotionFlags & PMV_HALFPEL16)) {  
907                                          pmv[1].x = EVEN(pmv[1].x);          Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16;
908                                          pmv[1].y = EVEN(pmv[1].y);          Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8;
909                                  }          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    
                                 CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
                         }  
 // top neighbour, if allowed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], prevMB->mvs[0]))  
                         if (!MVequal(pmv[2], pmv[0]))  
                                 if (!MVequal(pmv[2], pmv[1])) {  
922                                          if (!(MotionFlags & PMV_HALFPEL16)) {                                          if (!(MotionFlags & PMV_HALFPEL16)) {
923                                                  pmv[2].x = EVEN(pmv[2].x);                  Data->min_dx = EVEN(Data->min_dx);
924                                                  pmv[2].y = EVEN(pmv[2].y);                  Data->max_dx = EVEN(Data->max_dx);
925                                          }                  Data->min_dy = EVEN(Data->min_dy);
926                                          CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);                  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  // top right neighbour, if allowed          if ((x == 0) && (y == 0)) threshA = 512;
944                                          if (!MVzero(pmv[3]))          else {
945                                                  if (!MVequal(pmv[3], prevMB->mvs[0]))                  threshA = Data->temp[0]; // that's when we keep this SAD atm
946                                                          if (!MVequal(pmv[3], pmv[0]))                  if (threshA < 512) threshA = 512;
947                                                                  if (!MVequal(pmv[3], pmv[1]))                  if (threshA > 1024) threshA = 1024; }
                                                                         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);  
                                                                         }  
                                 }  
948    
949          if ((MVzero(*currMV)) &&          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
950                  (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )                                          prevMBs + x + y * pParam->mb_width);
                 iMinSAD -= MV16_00_BIAS;  
951    
952            if (inter4v || Data->chroma) CheckCandidate = CheckCandidate16;
953            else CheckCandidate = CheckCandidate16no4v; //for extra speed
954    
955  /* Step 6: If MinSAD <= thresa goto Step 10.  /* main loop. checking all predictions */
    If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
 */  
956    
957          if ((iMinSAD <= threshA) ||          for (i = 1; i < 7; i++) {
958                  (MVequal(*currMV, prevMB->mvs[0]) &&                  if (!(mask = make_mask(pmv, i)) ) continue;
959                   ((int32_t) iMinSAD < prevMB->sad16))) {                  (*CheckCandidate)(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
960                  if (MotionFlags & PMV_QUICKSTOP16)                  if (Data->iMinSAD[0] <= threshA) break;
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
961          }          }
962    
963            if ((Data->iMinSAD[0] <= threshA) ||
964                            (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
965                            (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16))) {
966                    inter4v = 0;
967            } else {
968    
969  /************ (Diamond Search)  **************/                  MainSearchFunc * MainSearchPtr;
970  /*                  if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
971     Step 7: Perform Diamond search, with either the small or large diamond.                  else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
972     If Found=2 only examine one Diamond pattern, and afterwards goto step 10                          else MainSearchPtr = DiamondSearch;
973     Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
974     If center then goto step 10.                  (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
975     Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
976     Refine by using small diamond and goto step 10.  /* extended search, diamond starting in 0,0 and in prediction.
977  */          note that this search is/might be done in halfpel positions,
978            which makes it more different than the diamond above */
         if (MotionFlags & PMV_USESQUARES16)  
                 MainSearchPtr = Square16_MainSearch;  
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
   
         backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  
   
   
 /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                   currMV->x, currMV->y, iMinSAD, &newMV, center_x, center_y,  
                                                   min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
979    
980          if (MotionFlags & PMV_EXTSEARCH16) {          if (MotionFlags & PMV_EXTSEARCH16) {
981  /* extended: search (up to) two more times: orignal prediction and (0,0) */                          int32_t bSAD;
982                            VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
983                  if (!(MVequal(pmv[0], backupMV))) {                          if (!(MotionFlags & PMV_HALFPELREFINE16)) // who's gonna use extsearch and no halfpel?
984                          iSAD =                                  startMV.x = EVEN(startMV.x); startMV.y = EVEN(startMV.y);
985                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                          if (!(MVequal(startMV, backupMV))) {
986                                                                    center_x, center_y, iMinSAD, &newMV, center_x, center_y,                                  bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
987    
988                          if (iSAD < iMinSAD) {                                  (*CheckCandidate)(startMV.x, startMV.y, 255, &iDirection, Data);
989                                  *currMV = newMV;                                  (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
990                                  iMinSAD = iSAD;                                  if (bSAD < Data->iMinSAD[0]) {
991                          }                                          Data->currentMV[0] = backupMV;
992                                            Data->iMinSAD[0] = bSAD; }
993                  }                  }
994    
995                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                          backupMV = Data->currentMV[0];
996                          iSAD =                          if (MotionFlags & PMV_HALFPELREFINE16) startMV.x = startMV.y = 1;
997                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                          else startMV.x = startMV.y = 0;
998                                                                    iMinSAD, &newMV, center_x, center_y,                          if (!(MVequal(startMV, backupMV))) {
999                                                                    min_dx, max_dx, min_dy, max_dy,                                  bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
                                                                   iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
1000    
1001                          if (iSAD < iMinSAD) {                                  (*CheckCandidate)(startMV.x, startMV.y, 255, &iDirection, Data);
1002                                  *currMV = newMV;                                  (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
1003                                  iMinSAD = iSAD;                                  if (bSAD < Data->iMinSAD[0]) {
1004                                            Data->currentMV[0] = backupMV;
1005                                            Data->iMinSAD[0] = bSAD; }
1006                          }                          }
1007                  }                  }
1008          }          }
1009    
1010  /*          if (MotionFlags & PMV_HALFPELREFINE16) SubpelRefine(Data);
    Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  
 */  
   
   PMVfast16_Terminate_with_Refine:  
         if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step  
                 iMinSAD =  
                         Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
1011    
1012    PMVfast16_Terminate_without_Refine:          for(i = 0; i < 5; i++) {
1013          currPMV->x = currMV->x - center_x;                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // initialize qpel vectors
1014          currPMV->y = currMV->y - center_y;                  Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
         return iMinSAD;  
1015  }  }
1016    
1017            if((pParam->m_quarterpel) && (MotionFlags & PMV_QUARTERPELREFINE16)) {
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                    SubpelRefine(Data);
1024            }
1025    
1026            if (Data->iMinSAD[0] < (int32_t)iQuant * 30 ) inter4v = 0;
1027            if (inter4v) {
1028                    SearchData Data8;
1029                    Data8.iFcode = Data->iFcode;
1030                    Data8.lambda8 = Data->lambda8;
1031                    Data8.iEdgedWidth = Data->iEdgedWidth;
1032                    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                    if (Data->chroma) {
1040                            int sumx, sumy, dx, dy;
1041    
1042  int32_t                          if(pParam->m_quarterpel) {
1043  Diamond8_MainSearch(const uint8_t * const pRef,                                  sumx= pMB->qmvs[0].x/2 + pMB->qmvs[1].x/2 + pMB->qmvs[2].x/2 + pMB->qmvs[3].x/2;
1044                                          const uint8_t * const pRefH,                                  sumy = pMB->qmvs[0].y/2 + pMB->qmvs[1].y/2 + pMB->qmvs[2].y/2 + pMB->qmvs[3].y/2;
1045                                          const uint8_t * const pRefV,                          } else {
1046                                          const uint8_t * const pRefHV,                                  sumx = pMB->mvs[0].x + pMB->mvs[1].x + pMB->mvs[2].x + pMB->mvs[3].x;
1047                                          const uint8_t * const cur,                                  sumy = pMB->mvs[0].y + pMB->mvs[1].y + pMB->mvs[2].y + pMB->mvs[3].y;
1048                                          const int x,                          }
1049                                          const int y,                          dx = (sumx >> 3) + roundtab_76[sumx & 0xf];
1050                                          int32_t start_x,                          dy = (sumy >> 3) + roundtab_76[sumy & 0xf];
                                         int32_t start_y,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iDirectionBackup;  
         int32_t iSAD;  
         VECTOR backupMV;  
1051    
1052          backupMV.x = start_x;                          Data->iMinSAD[1] += ChromaSAD(dx, dy, Data);
1053          backupMV.y = start_y;                  }
1054            }
1055    
1056  /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */          if (!(inter4v) ||
1057                    (Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
1058                            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_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
1065          CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);                          pMB->sad8[2] = pMB->sad8[3] =  Data->iMinSAD[0];
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
1066    
1067          if (iDirection) {                  if(pParam->m_quarterpel) {
1068                  while (!iFound) {                          pMB->qmvs[0] = pMB->qmvs[1]
1069                          iFound = 1;                                  = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1070                          backupMV = *currMV;     // since iDirection!=0, this is well defined!                          pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1071                          iDirectionBackup = iDirection;                          pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;
1072                    } else {
1073                          if (iDirectionBackup != 2)                          pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1074                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
                                                                                   backupMV.y, 1);  
                         if (iDirectionBackup != 1)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                   backupMV.y, 2);  
                         if (iDirectionBackup != 4)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y - iDiamondSize, 3);  
                         if (iDirectionBackup != 3)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y + iDiamondSize, 4);  
1075                  }                  }
1076          } else {          } else {
1077                  currMV->x = start_x;  // INTER4V MODE; all other things are already set in Search8
1078                  currMV->y = start_y;                  pMB->mode = MODE_INTER4V;
1079                    pMB->sad16 = Data->iMinSAD[1] + Data->iMinSAD[2] +
1080                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * iQuant;
1081          }          }
         return iMinSAD;  
1082  }  }
1083    
1084    static void
1085    Search8(const SearchData * const OldData,
1086                    const int x, const int y,
1087                    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                    if (MotionFlags & PMV_EXTSEARCH8) {
1127                            int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
1128    
1129                            MainSearchFunc *MainSearchPtr;
1130                            if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
1131                                    else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1132                                            else MainSearchPtr = DiamondSearch;
1133    
1134  int32_t                          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);
 Square8_MainSearch(const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x,  
                                         const int y,  
                                         int32_t start_x,  
                                         int32_t start_y,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a square search around given starting point, return SAD of best */  
1135    
1136          int32_t iDirection = 0;                          if(*(Data->iMinSAD) < temp_sad) {
1137          int32_t iSAD;                                          Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1138          VECTOR backupMV;                                          Data->currentQMV->y = 2 * Data->currentMV->y;
1139                            }
1140                    }
1141    
1142          backupMV.x = start_x;                  if (MotionFlags & PMV_HALFPELREFINE8) {
1143          backupMV.y = start_y;                          int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
1144    
1145  /* It's one search with full square pattern, and new parts for all following diamonds */                          SubpelRefine(Data); // perform halfpel refine of current best vector
1146    
1147  /*   new direction are extra, so 1-4 is normal diamond                          if(*(Data->iMinSAD) < temp_sad) { // we have found a better match
1148        537                                  Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1149        1*2                                  Data->currentQMV->y = 2 * Data->currentMV->y;
1150        648                          }
1151  */                  }
   
         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);  
   
         CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 5);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 6);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 7);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 8);  
1152    
1153                    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          if (iDirection) {          if(pParam->m_quarterpel) {
1165                  while (!iFound) {                  pMB->pmvs[block].x = Data->currentQMV->x - Data->predMV.x;
1166                          iFound = 1;                  pMB->pmvs[block].y = Data->currentQMV->y - Data->predMV.y;
1167                          backupMV = *currMV;                  pMB->qmvs[block] = *(Data->currentQMV);
1168            }
1169            else {
1170                    pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1171                    pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
1172            }
1173    
1174                          switch (iDirection) {          pMB->mvs[block] = *(Data->currentMV);
1175                          case 1:          pMB->sad8[block] =  4 * (*Data->iMinSAD);
1176                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  }
                                                                                    backupMV.y, 1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
                         case 2:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
1177    
1178                          case 3:  /* B-frames code starts here */
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
1179    
1180                          case 4:  static __inline VECTOR
1181                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1182                                                                                   3);  {
1183                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  /* the stupidiest function ever */
1184                                                                                   backupMV.y - iDiamondSize, 5);          if (mode == MODE_FORWARD) return pMB->mvs[0];
1185                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          else return pMB->b_mvs[0];
1186                                                                                   backupMV.y + iDiamondSize, 6);  }
                                 break;  
   
                         case 5:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
   
                         case 6:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
   
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
1187    
1188                                  break;  static void __inline
1189    PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
1190                                                            const uint32_t iWcount,
1191                                                            const MACROBLOCK * const pMB,
1192                                                            const uint32_t mode_curr)
1193    {
1194    
1195                          case 7:          // [0] is prediction
1196                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
                                                                                    backupMV.y, 1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
1197    
1198                          case 8:          pmv[1].x = pmv[1].y = 0; // [1] is zero
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         default:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
   
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         }  
                 }  
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
         }  
         return iMinSAD;  
 }  
1199    
1200            pmv[2] = ChoosePred(pMB, mode_curr);
1201            pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
1202    
1203            if ((y != 0)&&(x != (int)(iWcount+1))) {                        // [3] top-right neighbour
1204                    pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
1205                    pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
1206            } else pmv[3].x = pmv[3].y = 0;
1207    
1208            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  int32_t          if ((x != 0)&&(y != 0)) {
1219  Halfpel8_Refine_c(const uint8_t * const pRef,                  pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
1220                                  const uint8_t * const pRefH,                  pmv[6].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1221                                  const uint8_t * const pRefV,          } else pmv[6].x = pmv[6].y = 0;
                                 const uint8_t * const pRefHV,  
                                 const uint8_t * const cur,  
                                 const int x,  
                                 const int y,  
                                 VECTOR * const currMV,  
                                 int32_t iMinSAD,  
                            const int center_x,  
                            const int center_y,  
                                 const int32_t min_dx,  
                                 const int32_t max_dx,  
                                 const int32_t min_dy,  
                                 const int32_t max_dy,  
                                 const int32_t iFcode,  
                                 const int32_t iQuant,  
                                 const int32_t iEdgedWidth)  
 {  
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
   
         int32_t iSAD;  
         VECTOR backupMV = *currMV;  
   
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y + 1);  
         CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y + 1);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y + 1);  
1222    
1223          return iMinSAD;  // more?
1224  }  }
1225    
1226    
1227  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)  /* search backward or forward, for b-frames */
1228    static void
1229  int32_t  SearchBF(       const uint8_t * const pRef,
 PMVfastSearch8(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,  
                                 const int center_x,  
                                 const int center_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  {  {
         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;  
1244    
1245          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;          const int32_t iEdgedWidth = pParam->edged_width;
1246    
1247          int32_t iDiamondSize;          int i, iDirection, mask;
1248            VECTOR pmv[7];
1249            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;
         VECTOR pmv[4];  
         int32_t psad[4];  
         VECTOR newMV;  
         VECTOR backupMV;  
         VECTOR startMV;  
1282    
1283  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);
         const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;  
1284    
1285           int32_t threshA, threshB;          SubpelRefine(Data);
         int32_t iFound, bPredEq;  
         int32_t iMinSAD, iSAD;  
1286    
1287          int32_t iSubBlock = (y & 1) + (y & 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          MainSearch8FuncPtr MainSearchPtr;          }
1321    
1322          /* Init variables */  }
         startMV.x = start_x;  
         startMV.y = start_y;  
1323    
1324          /* Get maximum range */  static int32_t
1325          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,  SearchDirect(const IMAGE * const f_Ref,
1326                            iFcode);                                  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          if (!(MotionFlags & PMV_HALFPELDIAMOND8)) {          for (k = 0; k < 4; k++) {
1374                  min_dx = EVEN(min_dx);                  pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);
1375                  max_dx = EVEN(max_dx);                  pMB->b_mvs[k].x = Data->directmvB[k].x = ((TRB - TRD) * Data->referencemv[k].x) / TRD;
1376                  min_dy = EVEN(min_dy);                  pMB->mvs[k].y = Data->directmvF[k].y = ((TRB * Data->referencemv[k].y) / TRD);
1377                  max_dy = EVEN(max_dy);                  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    
         /* because we might use 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);  
   
         if ((x == 0) && (y == 0)) {  
                 threshA = 512 / 4;  
                 threshB = 1024 / 4;  
1396    
1397          } else {          if (b_mb->mode == MODE_INTER4V) CheckCandidate = CheckCandidateDirect;
1398                  threshA = psad[0] / 4;  /* good estimate? */          else CheckCandidate = CheckCandidateDirectno4v;
                 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.  
 */  
1399    
1400            (*CheckCandidate)(0, 0, 255, &k, Data);
1401    
1402  // Prepare for main loop  // 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    if (MotionFlags & PMV_USESQUARES8)                  if (Data->qpel) {
1409        MainSearchPtr = Square8_MainSearch;                          sum = pMB->mvs[0].y/2 + pMB->mvs[1].y/2 + pMB->mvs[2].y/2 + pMB->mvs[3].y/2;
1410    else                          dy = (sum >> 3) + roundtab_76[sum & 0xf];
1411                            sum = pMB->mvs[0].x/2 + pMB->mvs[1].x/2 + pMB->mvs[2].x/2 + pMB->mvs[3].x/2;
1412                            dx = (sum >> 3) + roundtab_76[sum & 0xf];
1413    
1414          if (MotionFlags & PMV_ADVANCEDDIAMOND8)                          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                  MainSearchPtr = AdvDiamond8_MainSearch;                          b_dy = (sum >> 3) + roundtab_76[sum & 0xf];
1416          else                          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                  MainSearchPtr = Diamond8_MainSearch;                          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          *currMV = startMV;                          sum = pMB->b_mvs[0].x + pMB->b_mvs[1].x + pMB->b_mvs[2].x + pMB->b_mvs[3].x;
1426                            b_dx = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1427                            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          iMinSAD =                  if (sum < MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) {
1440                  sad8(cur,                          pMB->mode = MODE_DIRECT_NONE_MV;
1441                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,                          return *Data->iMinSAD;
1442                                                  iEdgedWidth), iEdgedWidth);                  }
1443          iMinSAD +=          }
                 calc_delta_8(currMV->x - center_x, currMV->y - center_y,  
                                          (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256 / 4) || ((MVequal(*currMV, prevMB->mvs[iSubBlock]))  
                                                                 && ((int32_t) iMinSAD <  
                                                                         prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  
    vector of the median.  
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
   
         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.  
 */  
1444    
1445          if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))          skip_sad = *Data->iMinSAD;
                 iDiamondSize = 1;               // 1 halfpel!  
         else  
                 iDiamondSize = 2;               // 2 halfpel = 1 full pixel!  
1446    
1447          if (!(MotionFlags & PMV_HALFPELDIAMOND8))  //  DIRECT MODE DELTA VECTOR SEARCH.
1448                  iDiamondSize *= 2;  //      This has to be made more effective, but at the moment I'm happy it's running at all
1449    
1450            if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1451                    else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1452                            else MainSearchPtr = DiamondSearch;
1453    
1454  /*          (*MainSearchPtr)(0, 0, Data, 255);
    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(center_x, center_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, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
1455    
1456          if (MotionFlags & PMV_EXTSEARCH8) {          SubpelRefine(Data);
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
1457    
1458                  if (!(MVequal(pmv[0], backupMV))) {  //      *Data->iMinSAD +=  1 * Data->lambda16; // one bit is needed to code direct mode
1459                          iSAD =          *best_sad = *Data->iMinSAD;
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
1460    
1461                          if (iSAD < iMinSAD) {          if (b_mb->mode == MODE_INTER4V)
1462                                  *currMV = newMV;                  pMB->mode = MODE_DIRECT;
1463                                  iMinSAD = iSAD;          else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation
                         }  
                 }  
1464    
1465                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          pMB->pmvs[3] = *Data->currentMV;
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
1466    
1467                          if (iSAD < iMinSAD) {          for (k = 0; k < 4; k++) {
1468                                  *currMV = newMV;                  pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
1469                                  iMinSAD = iSAD;                  pMB->b_mvs[k].x = (     (Data->currentMV->x == 0)
1470                                                            ? Data->directmvB[k].x
1471                                                            :pMB->mvs[k].x - Data->referencemv[k].x);
1472                    pMB->mvs[k].y = (Data->directmvF[k].y + Data->currentMV->y);
1473                    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                    }
1482    
1483                    if (b_mb->mode != MODE_INTER4V) {
1484                            pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1485                            pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1486                            pMB->qmvs[3] = pMB->qmvs[2] = pMB->qmvs[1] = pMB->qmvs[0];
1487                            pMB->b_qmvs[3] = pMB->b_qmvs[2] = pMB->b_qmvs[1] = pMB->b_qmvs[0];
1488                            break;
1489                          }                          }
1490                  }                  }
1491            return skip_sad;
1492          }          }
1493    
 /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.  
    By performing an optional local half-pixel search, we can refine this result even further.  
 */  
   
   PMVfast8_Terminate_with_Refine:  
         if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step  
                 iMinSAD =  
                         Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                         iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                         iFcode, iQuant, iEdgedWidth);  
   
1494    
1495    PMVfast8_Terminate_without_Refine:  static __inline void
1496          currPMV->x = currMV->x - center_x;  SearchInterpolate(const uint8_t * const f_Ref,
1497          currPMV->y = currMV->y - center_y;                                  const uint8_t * const f_RefH,
1498                                    const uint8_t * const f_RefV,
1499          return iMinSAD;                                  const uint8_t * const f_RefHV,
1500  }                                  const uint8_t * const b_Ref,
1501                                    const uint8_t * const b_RefH,
1502  int32_t                                  const uint8_t * const b_RefV,
1503  EPZSSearch16(const uint8_t * const pRef,                                  const uint8_t * const b_RefHV,
                          const uint8_t * const pRefH,  
                          const uint8_t * const pRefV,  
                          const uint8_t * const pRefHV,  
1504                           const IMAGE * const pCur,                           const IMAGE * const pCur,
1505                           const int x,                                  const int x, const int y,
1506                           const int y,                                  const uint32_t fcode,
1507                          const int start_x,                                  const uint32_t bcode,
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
1508                           const uint32_t MotionFlags,                           const uint32_t MotionFlags,
                          const uint32_t iQuant,  
                          const uint32_t iFcode,  
1509                           const MBParam * const pParam,                           const MBParam * const pParam,
1510                           const MACROBLOCK * const pMBs,                                  const VECTOR * const f_predMV,
1511                           const MACROBLOCK * const prevMBs,                                  const VECTOR * const b_predMV,
1512                           VECTOR * const currMV,                                  MACROBLOCK * const pMB,
1513                           VECTOR * const currPMV)                                  int32_t * const best_sad,
1514                                    SearchData * const fData)
1515    
1516  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const uint32_t iHcount = pParam->mb_height;  
1517    
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
1518          const int32_t iEdgedWidth = pParam->edged_width;          const int32_t iEdgedWidth = pParam->edged_width;
1519            int iDirection, i, j;
1520            SearchData bData;
1521    
1522          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          *(bData.iMinSAD = fData->iMinSAD) = 4096*256;
1523            bData.Cur = fData->Cur;
1524          int32_t min_dx;          fData->iEdgedWidth = bData.iEdgedWidth = iEdgedWidth;
1525          int32_t max_dx;          bData.currentMV = fData->currentMV + 1; bData.currentQMV = fData->currentQMV + 1;
1526          int32_t min_dy;          bData.lambda16 = fData->lambda16;
1527          int32_t max_dy;          fData->iFcode = bData.bFcode = fcode; fData->bFcode = bData.iFcode = bcode;
1528    
1529          VECTOR newMV;          bData.bRef = fData->Ref = f_Ref + (x + y * iEdgedWidth) * 16;
1530          VECTOR backupMV;          bData.bRefH = fData->RefH = f_RefH + (x + y * iEdgedWidth) * 16;
1531            bData.bRefV = fData->RefV = f_RefV + (x + y * iEdgedWidth) * 16;
1532          VECTOR pmv[4];          bData.bRefHV = fData->RefHV = f_RefHV + (x + y * iEdgedWidth) * 16;
1533          int32_t psad[8];          bData.Ref = fData->bRef = b_Ref + (x + y * iEdgedWidth) * 16;
1534            bData.RefH = fData->bRefH = b_RefH + (x + y * iEdgedWidth) * 16;
1535          static MACROBLOCK *oldMBs = NULL;          bData.RefV = fData->bRefV = b_RefV + (x + y * iEdgedWidth) * 16;
1536            bData.RefHV = fData->bRefHV = b_RefHV + (x + y * iEdgedWidth) * 16;
1537  //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;          bData.RefQ = fData->RefQ;
1538          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;          fData->qpel_precision = bData.qpel_precision = 0; bData.qpel = fData->qpel;
1539          MACROBLOCK *oldMB = NULL;          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           int32_t thresh2;          CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, 255, &iDirection, fData);
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD = 9999;  
1559    
1560          MainSearch16FuncPtr MainSearchPtr;  //diamond. I wish we could use normal mainsearch functions (square, advdiamond)
1561    
1562          if (oldMBs == NULL) {          do {
1563                  oldMBs = (MACROBLOCK *) calloc(iWcount * iHcount, sizeof(MACROBLOCK));                  iDirection = 255;
1564  //      fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));                  // 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            if (fData->qpel) {
1583                    CheckCandidate = CheckCandidateInt;
1584                    fData->qpel_precision = bData.qpel_precision = 1;
1585                    get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode, 0);
1586                    get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode, 0);
1587                    fData->currentQMV[2].x = fData->currentQMV[0].x = 2 * fData->currentMV[0].x;
1588                    fData->currentQMV[2].y = fData->currentQMV[0].y = 2 * fData->currentMV[0].y;
1589                    fData->currentQMV[1].x = 2 * fData->currentMV[1].x;
1590                    fData->currentQMV[1].y = 2 * fData->currentMV[1].y;
1591                    SubpelRefine(fData);
1592                    fData->currentQMV[2] = fData->currentQMV[0];
1593                    SubpelRefine(&bData);
1594            }
1595    
1596            *fData->iMinSAD +=  2 * fData->lambda16; // two bits are needed to code interpolate mode.
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          }          }
         oldMB = oldMBs + x + y * iWcount;  
1618    
1619  /* Get maximum range */  void
1620          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  MotionEstimationBVOP(MBParam * const pParam,
1621                            iFcode);                                           FRAMEINFO * const frame,
1622                                             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          if (!(MotionFlags & PMV_HALFPEL16)) {          const int32_t TRB = time_pp - time_bp;
1646                  min_dx = EVEN(min_dx);          const int32_t TRD = time_pp;
1647                  max_dx = EVEN(max_dx);          uint8_t * qimage;
1648                  min_dy = EVEN(min_dy);  
1649                  max_dy = EVEN(max_dy);  // some pre-inintialized data for the rest of the search
1650          }  
1651          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */          SearchData Data;
1652          //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);          int32_t iMinSAD;
1653          bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);          VECTOR currentMV[3];
1654            VECTOR currentQMV[3];
1655  /* Step 4: Calculate SAD around the Median prediction.          Data.iEdgedWidth = pParam->edged_width;
1656          MinSAD=SAD          Data.currentMV = currentMV; Data.currentQMV = currentQMV;
1657          If Motion Vector equal to Previous frame motion vector          Data.iMinSAD = &iMinSAD;
1658                  and MinSAD<PrevFrmSAD goto Step 10.          Data.lambda16 = lambda_vec16[frame->quant] + 2;
1659          If SAD<=256 goto Step 10.          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  // Prepare for main loop          // note: i==horizontal, j==vertical
1669            for (j = 0; j < pParam->mb_height; j++) {
1670    
1671          currMV->x = start_x;                  f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
         currMV->y = start_y;  
1672    
1673          if (!(MotionFlags & PMV_HALFPEL16)) {                  for (i = 0; i < pParam->mb_width; i++) {
1674                  currMV->x = EVEN(currMV->x);                          MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
1675                  currMV->y = EVEN(currMV->y);                          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 (currMV->x > max_dx)                          Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
1685                  currMV->x = max_dx;                          pMB->quant = frame->quant;
         if (currMV->x < min_dx)  
                 currMV->x = min_dx;  
         if (currMV->y > max_dy)  
                 currMV->y = max_dy;  
         if (currMV->y < min_dy)  
                 currMV->y = min_dy;  
   
 /***************** This is predictor SET A: only median prediction ******************/  
   
         iMinSAD =  
                 sad16(cur,  
                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
   
 // thresh1 is fixed to 256  
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
         }  
   
 /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/  
1686    
1687  // previous frame MV  /* direct search comes first, because it (1) checks for SKIP-mode
1688          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);          and (2) sets very good predictions for forward and backward search */
1689                            skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
1690                                                                            b_ref, b_refH->y, b_refV->y, b_refHV->y,
1691                                                                            &frame->image,
1692                                                                            i, j,
1693                                                                            frame->motion_flags,
1694                                                                            TRB, TRD,
1695                                                                            pParam,
1696                                                                            pMB, b_mb,
1697                                                                            &best_sad,
1698                                                                            &Data);
1699    
1700  // set threshhold based on Min of Prediction and SAD of collocated block                          if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
 // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want  
1701    
1702          if ((x == 0) && (y == 0)) {                          // forward search
1703                  thresh2 = 512;                          SearchBF(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
1704          } else {                                                  &frame->image, i, j,
1705  /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */                                                  frame->motion_flags,
1706                                                    frame->fcode, pParam,
1707                  thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;                                                  pMB, &f_predMV, &best_sad,
1708          }                                                  MODE_FORWARD, &Data);
   
 // MV=(0,0) is often a good choice  
   
         CHECK_MV16_ZERO;  
   
   
 // left neighbour, if allowed  
         if (x != 0) {  
                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                         pmv[1].x = EVEN(pmv[1].x);  
                         pmv[1].y = EVEN(pmv[1].y);  
                 }  
                 CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
         }  
 // 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);  
                 }  
                 CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed  
                 if ((uint32_t) x != (iWcount - 1)) {  
                         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);  
                 }  
         }  
   
 /* Terminate if MinSAD <= T_2  
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
 */  
   
         if ((iMinSAD <= thresh2)  
                 || (MVequal(*currMV, prevMB->mvs[0]) &&  
                         ((int32_t) iMinSAD <= prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
         }  
   
 /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/  
   
         backupMV = prevMB->mvs[0];      // collocated MV  
         backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x);     // acceleration X  
         backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y);     // acceleration Y  
   
         CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y);  
   
 // left neighbour  
         if (x != 0)  
                 CHECK_MV16_CANDIDATE((prevMB - 1)->mvs[0].x, (prevMB - 1)->mvs[0].y);  
   
 // top neighbour  
         if (y != 0)  
                 CHECK_MV16_CANDIDATE((prevMB - iWcount)->mvs[0].x,  
                                                          (prevMB - iWcount)->mvs[0].y);  
   
 // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs  
   
         if ((uint32_t) x != iWcount - 1)  
                 CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);  
   
 // bottom neighbour, dito  
         if ((uint32_t) y != iHcount - 1)  
                 CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,  
                                                          (prevMB + iWcount)->mvs[0].y);  
   
 /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */  
         if (iMinSAD <= thresh2) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
         }  
   
 /************ (if Diamond Search)  **************/  
   
         backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  
   
         if (MotionFlags & PMV_USESQUARES16)  
                 MainSearchPtr = Square16_MainSearch;  
         else  
          if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
   
 /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  
   
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  
                                                   currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);  
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
1709    
1710                            // backward search
1711                            SearchBF(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
1712                                                    &frame->image, i, j,
1713                                                    frame->motion_flags,
1714                                                    frame->bcode, pParam,
1715                                                    pMB, &b_predMV, &best_sad,
1716                                                    MODE_BACKWARD, &Data);
1717    
1718          if (MotionFlags & PMV_EXTSEARCH16) {                          // interpolate search comes last, because it uses data from forward and backward as prediction
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
1719    
1720                  if (!(MVequal(pmv[0], backupMV))) {                          SearchInterpolate(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
1721                          iSAD =                                                  b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
1722                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                                  &frame->image,
1723                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,                                                  i, j,
1724                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,                                                  frame->fcode, frame->bcode,
1725                                                                    2, iFcode, iQuant, 0);                                                  frame->motion_flags,
1726                  }                                                  pParam,
1727                                                    &f_predMV, &b_predMV,
1728                                                    pMB, &best_sad,
1729                                                    &Data);
1730    
1731                  if (iSAD < iMinSAD) {                          switch (pMB->mode) {
1732                          *currMV = newMV;                                  case MODE_FORWARD:
1733                          iMinSAD = iSAD;                                          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                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                                  case MODE_DIRECT:
1753                          iSAD =                                  case MODE_DIRECT_NO4V:
1754                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                                          d_count++;
1755                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,                                  default:
1756                                                                    max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);                                          break;
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
1757                          }                          }
1758                  }                  }
1759          }          }
1760            free(qimage);
 /***************        Choose best MV found     **************/  
   
   EPZS16_Terminate_with_Refine:  
         if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step  
                 iMinSAD =  
                         Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
   
   EPZS16_Terminate_without_Refine:  
   
         *oldMB = *prevMB;  
   
         currPMV->x = currMV->x - center_x;  
         currPMV->y = currMV->y - center_y;  
         return iMinSAD;  
1761  }  }
1762    
1763    /* Hinted ME starts here */
1764    
1765  int32_t  static void
1766  EPZSSearch8(const uint8_t * const pRef,  SearchPhinted ( const IMAGE * const pRef,
1767                          const uint8_t * const pRefH,                          const uint8_t * const pRefH,
1768                          const uint8_t * const pRefV,                          const uint8_t * const pRefV,
1769                          const uint8_t * const pRefHV,                          const uint8_t * const pRefHV,
1770                          const IMAGE * const pCur,                          const IMAGE * const pCur,
1771                          const int x,                          const int x,
1772                          const int y,                          const int y,
                         const int start_x,  
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
1773                          const uint32_t MotionFlags,                          const uint32_t MotionFlags,
1774                          const uint32_t iQuant,                          const uint32_t iQuant,
                         const uint32_t iFcode,  
1775                          const MBParam * const pParam,                          const MBParam * const pParam,
1776                          const MACROBLOCK * const pMBs,                          const MACROBLOCK * const pMBs,
1777                          const MACROBLOCK * const prevMBs,                                  int inter4v,
1778                          VECTOR * const currMV,                                  MACROBLOCK * const pMB,
1779                          VECTOR * const currPMV)                                  SearchData * const Data)
1780  {  {
1781  /* Please not that EPZS might not be a good choice for 8x8-block motion search ! */  
1782            int i, t;
1783          const uint32_t iWcount = pParam->mb_width;          MainSearchFunc * MainSearchPtr;
1784          const int32_t iWidth = pParam->width;  
1785          const int32_t iHeight = pParam->height;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1786          const int32_t iEdgedWidth = pParam->edged_width;                                  pParam->width, pParam->height, Data->iFcode, pParam->m_quarterpel);
1787    
1788          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;          Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16;
1789            Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8;
1790          int32_t iDiamondSize = 1;          Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8;
1791    
1792            Data->Ref = pRef->y + (x + Data->iEdgedWidth*y) * 16;
1793            Data->RefH = pRefH + (x + Data->iEdgedWidth*y) * 16;
1794            Data->RefV = pRefV + (x + Data->iEdgedWidth*y) * 16;
1795            Data->RefHV = pRefHV + (x + Data->iEdgedWidth*y) * 16;
1796            Data->RefCV = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8;
1797            Data->RefCU = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8;
1798            Data->qpel_precision = 0;
1799    
1800          int32_t min_dx;          if (!(MotionFlags & PMV_HALFPEL16)) {
1801          int32_t max_dx;                  Data->min_dx = EVEN(Data->min_dx);
1802          int32_t min_dy;                  Data->max_dx = EVEN(Data->max_dx);
1803          int32_t max_dy;                  Data->min_dy = EVEN(Data->min_dy);
1804                    Data->max_dy = EVEN(Data->max_dy);
1805          VECTOR newMV;          }
1806          VECTOR backupMV;          if (pParam->m_quarterpel) Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1807            else Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1808          VECTOR pmv[4];  
1809          int32_t psad[8];          for(i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;
1810    
1811          const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);          if (pMB->dquant != NO_CHANGE) inter4v = 0;
1812    
1813  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          if (inter4v || Data->chroma) CheckCandidate = CheckCandidate16;
1814          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;          else CheckCandidate = CheckCandidate16no4v;
1815    
1816          int32_t bPredEq;          pMB->mvs[0].x = EVEN(pMB->mvs[0].x);
1817          int32_t iMinSAD, iSAD = 9999;          pMB->mvs[0].y = EVEN(pMB->mvs[0].y);
1818            if (pMB->mvs[0].x > Data->max_dx) pMB->mvs[0].x = Data->max_dx; // this is in case iFcode changed
1819          MainSearch8FuncPtr MainSearchPtr;          if (pMB->mvs[0].x < Data->min_dx) pMB->mvs[0].x = Data->min_dx;
1820            if (pMB->mvs[0].y > Data->max_dy) pMB->mvs[0].y = Data->max_dy;
1821  /* Get maximum range */          if (pMB->mvs[0].y < Data->min_dy) pMB->mvs[0].y = Data->min_dy;
1822          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,  
1823                            iFcode);          (*CheckCandidate)(pMB->mvs[0].x, pMB->mvs[0].y, 0, &t, Data);
1824    
1825  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          if (pMB->mode == MODE_INTER4V)
1826                    for (i = 1; i < 4; i++) { // all four vectors will be used as four predictions for 16x16 search
1827          if (!(MotionFlags & PMV_HALFPEL8)) {                          pMB->mvs[i].x = EVEN(pMB->mvs[i].x);
1828                  min_dx = EVEN(min_dx);                          pMB->mvs[i].y = EVEN(pMB->mvs[i].y);
1829                  max_dx = EVEN(max_dx);                          if (!(make_mask(pMB->mvs, i)))
1830                  min_dy = EVEN(min_dy);                                  (*CheckCandidate)(pMB->mvs[i].x, pMB->mvs[i].y, 0, &t, Data);
                 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[0].x, pmv[0].y, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, x >> 1, y >> 1, iSubBlock, pmv, psad);  
   
   
 /* 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_HALFPEL8)) {  
                 currMV->x = EVEN(currMV->x);  
                 currMV->y = EVEN(currMV->y);  
         }  
   
         if (currMV->x > max_dx)  
                 currMV->x = max_dx;  
         if (currMV->x < min_dx)  
                 currMV->x = min_dx;  
         if (currMV->y > max_dy)  
                 currMV->y = max_dy;  
         if (currMV->y < min_dy)  
                 currMV->y = min_dy;  
   
 /***************** This is predictor SET A: only median prediction ******************/  
   
   
         iMinSAD =  
                 sad8(cur,  
                          get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  
                                                 iEdgedWidth), iEdgedWidth);  
         iMinSAD +=  
                 calc_delta_8(currMV->x - center_x, currMV->y - center_y,  
                                          (uint8_t) iFcode, iQuant);  
   
   
 // thresh1 is fixed to 256  
         if (iMinSAD < 256 / 4) {  
                 if (MotionFlags & PMV_QUICKSTOP8)  
                         goto EPZS8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
1831          }          }
1832    
1833  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/          if (MotionFlags & PMV_USESQUARES16)
1834                    MainSearchPtr = SquareSearch;
1835            else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
1836                    MainSearchPtr = AdvDiamondSearch;
1837                    else MainSearchPtr = DiamondSearch;
1838    
1839  // MV=(0,0) is often a good choice          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);
         CHECK_MV8_ZERO;  
1840    
1841  // previous frame MV          if (MotionFlags & PMV_HALFPELREFINE16) SubpelRefine(Data);
         CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x, prevMB->mvs[iSubBlock].y);  
1842    
1843  // left neighbour, if allowed          for(i = 0; i < 5; i++) {
1844          if (psad[1] != MV_MAX_ERROR) {                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // initialize qpel vectors
1845                  if (!(MotionFlags & PMV_HALFPEL8)) {                  Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
1846                          pmv[1].x = EVEN(pmv[1].x);          }
1847                          pmv[1].y = EVEN(pmv[1].y);  
1848                  }          if((pParam->m_quarterpel) && (MotionFlags & PMV_QUARTERPELREFINE16)) {
1849                  CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1850          }                                  pParam->width, pParam->height, Data->iFcode, 0);
1851  // top neighbour, if allowed                  Data->qpel_precision = 1;
1852          if (psad[2] != MV_MAX_ERROR) {                  SubpelRefine(Data);
1853                  if (!(MotionFlags & PMV_HALFPEL8)) {          }
1854                          pmv[2].x = EVEN(pmv[2].x);  
1855                          pmv[2].y = EVEN(pmv[2].y);          if (inter4v) {
1856                    SearchData Data8;
1857                    Data8.iFcode = Data->iFcode;
1858                    Data8.lambda8 = Data->lambda8;
1859                    Data8.iEdgedWidth = Data->iEdgedWidth;
1860                    Data8.RefQ = Data->RefQ;
1861                    Data8.qpel = Data->qpel;
1862                    Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
1863                    Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
1864                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
1865                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
1866    
1867                    if (Data->chroma) {
1868                            int sumx, sumy, dx, dy;
1869    
1870                            if(pParam->m_quarterpel) {
1871                                    sumx= pMB->qmvs[0].x/2 + pMB->qmvs[1].x/2 + pMB->qmvs[2].x/2 + pMB->qmvs[3].x/2;
1872                                    sumy = pMB->qmvs[0].y/2 + pMB->qmvs[1].y/2 + pMB->qmvs[2].y/2 + pMB->qmvs[3].y/2;
1873                            } else {
1874                                    sumx = pMB->mvs[0].x + pMB->mvs[1].x + pMB->mvs[2].x + pMB->mvs[3].x;
1875                                    sumy = pMB->mvs[0].y + pMB->mvs[1].y + pMB->mvs[2].y + pMB->mvs[3].y;
1876                  }                  }
1877                  CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);                          dx = (sumx >> 3) + roundtab_76[sumx & 0xf];
1878                            dy = (sumy >> 3) + roundtab_76[sumy & 0xf];
1879    
1880  // top right neighbour, if allowed                          Data->iMinSAD[1] += ChromaSAD(dx, dy, Data);
                 if (psad[3] != MV_MAX_ERROR) {  
                         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);  
1881                  }                  }
1882          }          }
1883    
1884  /*  // this bias is zero anyway, at the moment!          if (!(inter4v) ||
1885                    (Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] + Data->iMinSAD[3] +
1886          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)                                                          Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {
1887                  iMinSAD -= MV8_00_BIAS;  // INTER MODE
1888                    pMB->mode = MODE_INTER;
1889                    pMB->mvs[0] = pMB->mvs[1]
1890                            = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
1891    
1892  */                  pMB->qmvs[0] = pMB->qmvs[1]
1893                            = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1894    
1895  /* Terminate if MinSAD <= T_2                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
1896     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]                          pMB->sad8[2] = pMB->sad8[3] =  Data->iMinSAD[0];
 */  
1897    
1898          if (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */                  if(pParam->m_quarterpel) {
1899                  if (MotionFlags & PMV_QUICKSTOP8)                          pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1900                          goto EPZS8_Terminate_without_Refine;                          pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;
1901                  if (MotionFlags & PMV_EARLYSTOP8)                  } else {
1902                          goto EPZS8_Terminate_with_Refine;                          pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1903                            pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
1904          }          }
1905            } else {
1906  /************ (Diamond Search)  **************/  // INTER4V MODE; all other things are already set in Search8
1907                    pMB->mode = MODE_INTER4V;
1908          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                  pMB->sad16 = Data->iMinSAD[1] + Data->iMinSAD[2] + Data->iMinSAD[3]
1909                                                    + Data->iMinSAD[4] + IMV16X16 * iQuant;
         if (!(MotionFlags & PMV_HALFPELDIAMOND8))  
                 iDiamondSize *= 2;  
   
 /* default: use best prediction as starting point for one call of EPZS_MainSearch */  
   
 // there is no EPZS^2 for inter4v at the moment  
   
   if (MotionFlags & PMV_USESQUARES8)  
       MainSearchPtr = Square8_MainSearch;  
   else  
   
         if (MotionFlags & PMV_ADVANCEDDIAMOND8)  
                 MainSearchPtr = AdvDiamond8_MainSearch;  
         else  
                 MainSearchPtr = Diamond8_MainSearch;  
   
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  
                                                   currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, 0);  
   
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
1910          }          }
1911    
1912          if (MotionFlags & PMV_EXTSEARCH8) {  }
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
1913    
1914                  if (!(MVequal(pmv[0], backupMV))) {  void
1915                          iSAD =  MotionEstimationHinted( MBParam * const pParam,
1916                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                                  FRAMEINFO * const current,
1917                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,                                                  FRAMEINFO * const reference,
1918                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,                                                  const IMAGE * const pRefH,
1919                                                                    iDiamondSize, iFcode, iQuant, 0);                                                  const IMAGE * const pRefV,
1920                                                    const IMAGE * const pRefHV)
1921    {
1922            MACROBLOCK *const pMBs = current->mbs;
1923            const IMAGE *const pCurrent = &current->image;
1924            const IMAGE *const pRef = &reference->image;
1925    
1926                          if (iSAD < iMinSAD) {          uint32_t x, y;
1927                                  *currMV = newMV;          uint8_t * qimage;
1928                                  iMinSAD = iSAD;          int32_t temp[5], quant = current->quant;
1929            int32_t iMinSAD[5];
1930            VECTOR currentMV[5], currentQMV[5];
1931            SearchData Data;
1932            Data.iEdgedWidth = pParam->edged_width;
1933            Data.currentMV = currentMV;
1934            Data.currentQMV = currentQMV;
1935            Data.iMinSAD = iMinSAD;
1936            Data.temp = temp;
1937            Data.iFcode = current->fcode;
1938            Data.rounding = pParam->m_rounding_type;
1939            Data.qpel = pParam->m_quarterpel;
1940            Data.chroma = current->global_flags & XVID_ME_COLOUR;
1941    
1942            if((qimage = (uint8_t *) malloc(32 * pParam->edged_width)) == NULL)
1943                    return; // allocate some mem for qpel interpolated blocks
1944                                      // somehow this is dirty since I think we shouldn't use malloc outside
1945                                      // encoder_create() - so please fix me!
1946    
1947            Data.RefQ = qimage;
1948    
1949            if (sadInit) (*sadInit) ();
1950    
1951            for (y = 0; y < pParam->mb_height; y++) {
1952                    for (x = 0; x < pParam->mb_width; x++)  {
1953    
1954                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1955    
1956    //intra mode is copied from the first pass. At least for the time being
1957                            if  ((pMB->mode == MODE_INTRA) || (pMB->mode == MODE_NOT_CODED) ) continue;
1958    
1959                            if (!(current->global_flags & XVID_LUMIMASKING)) {
1960                                    pMB->dquant = NO_CHANGE;
1961                                    pMB->quant = current->quant; }
1962                            else {
1963                                    if (pMB->dquant != NO_CHANGE) {
1964                                            quant += DQtab[pMB->dquant];
1965                                            if (quant > 31) quant = 31;
1966                                            else if (quant < 1) quant = 1;
1967                          }                          }
1968                                    pMB->quant = quant;
1969                  }                  }
1970    
1971                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                          SearchPhinted(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1972                          iSAD =                                                          y, current->motion_flags, pMB->quant,
1973                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                                                          pParam, pMBs, current->global_flags & XVID_INTER4V, pMB,
1974                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,                                                          &Data);
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, 0);  
1975    
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
1976                  }                  }
1977          }          }
1978            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, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                         iFcode, iQuant, iEdgedWidth);  
   
   EPZS8_Terminate_without_Refine:  
   
         currPMV->x = currMV->x - center_x;  
         currPMV->y = currMV->y - center_y;  
         return iMinSAD;  
1979  }  }
1980    
1981    static __inline int
1982    MEanalyzeMB (   const uint8_t * const pRef,
1983  int32_t                                  const uint8_t * const pCur,
 PMVfastIntSearch16(const uint8_t * const pRef,  
                                 const uint8_t * const pRefH,  
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const IMAGE * const pCur,  
1984                                  const int x,                                  const int x,
1985                                  const int y,                                  const int y,
                                 const int start_x,              /* start should be most likely vector */  
                                 const int start_y,  
                                 const int center_x,             /* center is from where length of MVs is measured */  
                                 const int center_y,  
                                 const uint32_t MotionFlags,  
                                 const uint32_t iQuant,  
                                 const uint32_t iFcode,  
1986                                  const MBParam * const pParam,                                  const MBParam * const pParam,
1987                                  const MACROBLOCK * const pMBs,                                  const MACROBLOCK * const pMBs,
1988                                  const MACROBLOCK * const prevMBs,                                  MACROBLOCK * const pMB,
1989                                  VECTOR * const currMV,                                  SearchData * const Data)
                                 VECTOR * const currPMV)  
1990  {  {
         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;  
         const VECTOR zeroMV = { 0, 0 };  
   
         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;  
   
         VECTOR pmv[4];  
         int32_t psad[4];  
1991    
1992          MainSearch16FuncPtr MainSearchPtr;          int i = 255, mask;
1993            VECTOR pmv[3];
1994            *(Data->iMinSAD) = MV_MAX_ERROR;
1995    
1996          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;          //median is only used as prediction. it doesn't have to be real
1997          MACROBLOCK *const pMB = pMBs + x + y * iWcount;          if (x == 1 && y == 1) Data->predMV.x = Data->predMV.y = 0;
1998            else
1999          int32_t threshA, threshB;                  if (x == 1) //left macroblock does not have any vector now
2000          int32_t bPredEq;                          Data->predMV = (pMB - pParam->mb_width)->mvs[0]; // top instead of median
2001          int32_t iMinSAD, iSAD;                  else if (y == 1) // top macroblock don't have it's vector
2002                            Data->predMV = (pMB - 1)->mvs[0]; // left instead of median
2003                            else Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); //else median
2004  /* Get maximum range */  
2005          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2006                            iFcode);                                  pParam->width, pParam->height, Data->iFcode, pParam->m_quarterpel);
2007    
2008  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          Data->Cur = pCur + (x + y * pParam->edged_width) * 16;
2009            Data->Ref = pRef + (x + y * pParam->edged_width) * 16;
2010          if ((x == 0) && (y == 0)) {  
2011                  threshA = 512;          pmv[1].x = EVEN(pMB->mvs[0].x);
2012                  threshB = 1024;          pmv[1].y = EVEN(pMB->mvs[0].y);
2013            pmv[2].x = EVEN(Data->predMV.x);
2014                  bPredEq = 0;          pmv[2].y = EVEN(Data->predMV.y);
2015                  psad[0] = psad[1] = psad[2] = psad[3] = 0;          pmv[0].x = pmv[0].y = 0;
2016                  *currMV = pmv[0] = pmv[1] = pmv[2] = pmv[3] = zeroMV;  
2017            (*CheckCandidate)(0, 0, 255, &i, Data);
2018          } else {  
2019                  threshA = psad[0];  //early skip for 0,0
2020                  threshB = threshA + 256;          if (*Data->iMinSAD < MAX_SAD00_FOR_SKIP * 4) {
2021                  if (threshA < 512)                  pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
2022                          threshA = 512;                  pMB->mode = MODE_NOT_CODED;
2023                  if (threshA > 1024)                  return 0;
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
   
                 bPredEq = get_ipmvdata(pMBs, iWcount, 0, x, y, 0, pmv, psad);  
                 *currMV = pmv[0];                       /* current best := prediction */  
2024          }          }
2025    
2026          iFound = 0;          if (!(mask = make_mask(pmv, 1)))
2027                    (*CheckCandidate)(pmv[1].x, pmv[1].y, mask, &i, Data);
2028            if (!(mask = make_mask(pmv, 2)))
2029                    (*CheckCandidate)(pmv[2].x, pmv[2].y, mask, &i, Data);
2030    
2031  /* Step 4: Calculate SAD around the Median prediction.          if (*Data->iMinSAD > MAX_SAD00_FOR_SKIP * 4) // diamond only if needed
2032     MinSAD=SAD                  DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, i);
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
2033    
2034          if (currMV->x > max_dx) {          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
2035                  currMV->x = EVEN(max_dx);          pMB->mode = MODE_INTER;
2036          }          return *(Data->iMinSAD);
         if (currMV->x < min_dx) {  
                 currMV->x = EVEN(min_dx);  
         }  
         if (currMV->y > max_dy) {  
                 currMV->y = EVEN(max_dy);  
         }  
         if (currMV->y < min_dy) {  
                 currMV->y = EVEN(min_dy);  
         }  
   
         iMinSAD =  
                 sad16(cur,  
                           get_iref_mv(pRef, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
   
         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;  
                         }  
                 }  
   
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfastInt16_Terminate_with_Refine;  
2037          }          }
2038    
2039    #define INTRA_THRESH    1350
2040    #define INTER_THRESH    1200
2041    
 /* 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->i_mvs[0])))  
                 iFound = 2;  
2042    
2043  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.  int
2044     Otherwise select large Diamond Search.  MEanalysis(     const IMAGE * const pRef,
2045  */                          FRAMEINFO * const Current,
2046                            MBParam * const pParam,
2047          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))                          int maxIntra, //maximum number if non-I frames
2048                  iDiamondSize = 2;               // halfpel units!                          int intraCount, //number of non-I frames after last I frame; 0 if we force P/B frame
2049          else                          int bCount) // number if B frames in a row
2050                  iDiamondSize = 4;               // halfpel units!  {
2051            uint32_t x, y, intra = 0;
2052  /*          int sSAD = 0;
2053     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.          MACROBLOCK * const pMBs = Current->mbs;
2054     Also calculate (0,0) but do not subtract offset.          const IMAGE * const pCurrent = &Current->image;
2055     Let MinSAD be the smallest SAD up to this point.          int IntraThresh = INTRA_THRESH, InterThresh = INTER_THRESH;
2056     If MV is (0,0) subtract offset.  
2057  */          VECTOR currentMV;
2058            int32_t iMinSAD;
2059  // (0,0) is often a good choice          SearchData Data;
2060            Data.iEdgedWidth = pParam->edged_width;
2061          if (!MVzero(pmv[0]))          Data.currentMV = &currentMV;
2062                  CHECK_MV16_ZERO;          Data.iMinSAD = &iMinSAD;
2063            Data.iFcode = Current->fcode;
2064  // previous frame MV is always possible          CheckCandidate = CheckCandidate16no4vI;
   
         if (!MVzero(prevMB->i_mvs[0]))  
                 if (!MVequal(prevMB->i_mvs[0], pmv[0]))  
                         CHECK_MV16_CANDIDATE(prevMB->i_mvs[0].x, prevMB->i_mvs[0].y);  
   
 // left neighbour, if allowed  
   
         if (!MVzero(pmv[1]))  
                 if (!MVequal(pmv[1], prevMB->i_mvs[0]))  
                         if (!MVequal(pmv[1], pmv[0]))  
                                 CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
   
 // top neighbour, if allowed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], prevMB->i_mvs[0]))  
                         if (!MVequal(pmv[2], pmv[0]))  
                                 if (!MVequal(pmv[2], pmv[1]))  
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed  
                                         if (!MVzero(pmv[3]))  
                                                 if (!MVequal(pmv[3], prevMB->i_mvs[0]))  
                                                         if (!MVequal(pmv[3], pmv[0]))  
                                                                 if (!MVequal(pmv[3], pmv[1]))  
                                                                         if (!MVequal(pmv[3], pmv[2]))  
                                                                                 CHECK_MV16_CANDIDATE(pmv[3].x,  
                                                                                                                          pmv[3].y);  
   
         if ((MVzero(*currMV)) &&  
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV16_00_BIAS;  
   
   
 /* 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.  
 */  
2065    
2066          if (MotionFlags & PMV_USESQUARES16)          if (intraCount < 10) // we're right after an I frame
2067                  MainSearchPtr = Square16_MainSearch;                  IntraThresh += 4 * (intraCount - 10) * (intraCount - 10);
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
2068          else          else
2069                  MainSearchPtr = Diamond16_MainSearch;                  if ( 5*(maxIntra - intraCount) < maxIntra) // we're close to maximum. 2 sec when max is 10 sec
2070                            IntraThresh -= (IntraThresh * (maxIntra - 5*(maxIntra - intraCount)))/maxIntra;
2071    
         backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  
2072    
2073            InterThresh += 400 * (1 - bCount);
2074            if (InterThresh < 200) InterThresh = 200;
2075    
2076  /* 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, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
2077    
2078          if (iSAD < iMinSAD) {          for (y = 1; y < pParam->mb_height-1; y++) {
2079                  *currMV = newMV;                  for (x = 1; x < pParam->mb_width-1; x++) {
2080                  iMinSAD = iSAD;                          int sad, dev;
2081          }                          MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
   
         if (MotionFlags & PMV_EXTSEARCH16) {  
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
2082    
2083                  if (!(MVequal(pmv[0], backupMV))) {                          sad = MEanalyzeMB(pRef->y, pCurrent->y, x, y,
2084                          iSAD =                                                                  pParam, pMBs, pMB, &Data);
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
2085    
2086                          if (iSAD < iMinSAD) {                          if (sad > IntraThresh) {
2087                                  *currMV = newMV;                                  dev = dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,
2088                                  iMinSAD = iSAD;                                                            pParam->edged_width);
2089                          }                                  if (dev + IntraThresh < sad) {
2090                                            pMB->mode = MODE_INTRA;
2091                                            if (++intra > (pParam->mb_height-2)*(pParam->mb_width-2)/2) return 2;  // I frame
2092                  }                  }
   
                 if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {  
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
2093                          }                          }
2094                            sSAD += sad;
2095                  }                  }
2096          }          }
2097            sSAD /= (pParam->mb_height-2)*(pParam->mb_width-2);
2098            if (sSAD > InterThresh ) return 1; //P frame
2099            emms();
2100            return 0; // B frame
2101    
 /*  
    Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  
 */  
   
 PMVfastInt16_Terminate_with_Refine:  
   
         pMB->i_mvs[0] = pMB->i_mvs[1] = pMB->i_mvs[2] = pMB->i_mvs[3] = pMB->i_mv16 = *currMV;  
         pMB->i_sad8[0] = pMB->i_sad8[1] = pMB->i_sad8[2] = pMB->i_sad8[3] = pMB->i_sad16 = iMinSAD;  
   
         if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step  
                 iMinSAD =  
                         Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
   
         pmv[0] = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          // get _REAL_ prediction (halfpel possible)  
   
 PMVfastInt16_Terminate_without_Refine:  
         currPMV->x = currMV->x - center_x;  
         currPMV->y = currMV->y - center_y;  
         return iMinSAD;  
2102  }  }
2103    
2104    int
2105    FindFcode(      const MBParam * const pParam,
2106  /* ***********************************************************                          const FRAMEINFO * const current)
         bvop motion estimation  
 ***************************************************************/  
   
 void  
 MotionEstimationBVOP(MBParam * const pParam,  
                                          FRAMEINFO * const frame,  
                                          const int32_t time_bp,  
                                          const int32_t time_pp,  
                                          // 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)  
2107  {  {
2108          const int mb_width = pParam->mb_width;          uint32_t x, y;
2109          const int mb_height = pParam->mb_height;          int max = 0, min = 0, i;
         const int edged_width = pParam->edged_width;  
   
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
   
         int i, j, k;  
2110    
2111          static const VECTOR zeroMV={0,0};          for (y = 0; y < pParam->mb_height; y++) {
2112                    for (x = 0; x < pParam->mb_width; x++) {
         int f_sad16;    /* forward (as usual) search */  
         int b_sad16;    /* backward (only in b-frames) search */  
         int i_sad16;    /* interpolated (both direction, b-frames only) */  
         int d_sad16;    /* direct mode (assume almost linear motion) */  
   
         int best_sad;  
   
         VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/  
         VECTOR f_interpolMV, b_interpolMV;  
         VECTOR pmv_dontcare;  
   
         int min_dx, max_dx, min_dy, max_dy;  
         int f_min_dx, f_max_dx, f_min_dy, f_max_dy;  
         int b_min_dx, b_max_dx, b_min_dy, b_max_dy;  
   
         int f_count=0;  
         int b_count=0;  
         int i_count=0;  
         int d_count=0;  
   
         const int64_t TRB = (int32_t)time_pp - (int32_t)time_bp;  
     const int64_t TRD = (int32_t)time_pp;  
   
         // fprintf(stderr,"TRB = %lld  TRD = %lld  time_bp =%d time_pp =%d\n\n",TRB,TRD,time_bp,time_pp);  
         // note: i==horizontal, j==vertical  
         for (j = 0; j < mb_height; j++) {  
2113    
2114                  f_predMV = zeroMV;      /* prediction is reset at left boundary */                          MACROBLOCK *pMB = &current->mbs[x + y * pParam->mb_width];
2115                  b_predMV = zeroMV;                          for(i = 0; i < (pMB->mode == MODE_INTER4V ? 4:1); i++) {
2116                                    if (pMB->mvs[i].x > max) max = pMB->mvs[i].x;
2117                                    if (pMB->mvs[i].y > max) max = pMB->mvs[i].y;
2118    
2119                  for (i = 0; i < mb_width; i++) {                                  if (pMB->mvs[i].x < min) min = pMB->mvs[i].x;
2120                          MACROBLOCK *mb = &frame->mbs[i + j * mb_width];                                  if (pMB->mvs[i].y < min) min = pMB->mvs[i].y;
                         const MACROBLOCK *f_mb = &f_mbs[i + j * mb_width];  
                         const MACROBLOCK *b_mb = &b_mbs[i + j * mb_width];  
   
                         mb->deltamv=zeroMV;  
   
 /* special case, if collocated block is SKIPed: encoding is forward (0,0), cpb=0 without further ado */  
   
 #ifndef _DISABLE_SKIP  
                         if (b_mb->mode == MODE_INTER && b_mb->cbp == 0 &&  
                                 b_mb->mvs[0].x == 0 && b_mb->mvs[0].y == 0) {  
                                 mb->mode = MODE_NOT_CODED;  
                                 mb->mvs[0].x = 0;  
                                 mb->mvs[0].y = 0;  
                                 mb->b_mvs[0].x = 0;  
                                 mb->b_mvs[0].y = 0;  
                                 continue;  
2121                          }                          }
 #endif  
   
                         if (b_mb->mode == MODE_INTER4V)  
                         {  
                                 d_sad16 = 0;  
                         /* same method of scaling as in decoder.c, so we copy from there */  
                     for (k = 0; k < 4; k++) {  
   
                                         mb->directmv[k] = b_mb->mvs[k];  
   
                                         mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);  
                     mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)  
                                                                                 ? ((TRB - TRD) * mb->directmv[k].x) / TRD  
                                             : mb->mvs[k].x - mb->directmv[k].x);  
   
                     mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);  
                         mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)  
                                                                                 ? ((TRB - TRD) * mb->directmv[k].y) / TRD  
                                             : mb->mvs[k].y - mb->directmv[k].y);  
   
                                         d_sad16 +=  
                                                 sad8bi(frame->image.y + 2*(i+(k&1))*8 + 2*(j+(k>>1))*8*edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 2*(i+(k&1)), 2*(j+(k>>1)), 8, &mb->mvs[k], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 2*(i+(k&1)), 2*(j+(k>>1)), 8, &mb->b_mvs[k], edged_width),  
                                                   edged_width);  
2122                                  }                                  }
2123                          }                          }
                         else  
                         {  
                                 mb->directmv[3] = mb->directmv[2] = mb->directmv[1] =  
                                         mb->directmv[0] = b_mb->mvs[0];  
2124    
2125                                  mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);          min = -min;
2126                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)          max += 1;
2127                                                                          ? ((TRB - TRD) * mb->directmv[0].x) / TRD          if (min > max) max = min;
2128                                      : mb->mvs[0].x - mb->directmv[0].x);          if (pParam->m_quarterpel) max *= 2;
   
                     mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);  
                 mb->b_mvs[0].y = (int32_t) ((mb->directmv[0].y == 0)  
                                                                         ? ((TRB - TRD) * mb->directmv[0].y) / TRD  
                                     : mb->mvs[0].y - mb->directmv[0].y);  
   
                                 d_sad16 = sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 i, j, 16, &mb->mvs[0], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 i, j, 16, &mb->b_mvs[0], edged_width),  
                                                   edged_width);  
2129    
2130            for (i = 1; (max > 32 << (i - 1)); i++);
2131            return i;
2132              }              }
                     d_sad16 += calc_delta_16(mb->deltamv.x, mb->deltamv.y, 1, frame->quant);  
   
                         // forward search  
                         f_sad16 = SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 &frame->image, i, j,  
                                                 mb->mvs[0].x, mb->mvs[0].y,                     /* start point f_directMV */  
                                                 f_predMV.x, f_predMV.y,                         /* center is f-prediction */  
                                                 frame->motion_flags,  
                                                 frame->quant, frame->fcode, pParam,  
                                                 f_mbs, f_mbs,  
                                                 &mb->mvs[0], &pmv_dontcare);  
2133    
2134    static void
2135    CheckGMC(int x, int y, const int dir, int * iDirection,
2136                    const MACROBLOCK * const pMBs, uint32_t * bestcount, VECTOR * GMC,
2137                    const MBParam * const pParam)
2138    {
2139            uint32_t mx, my, a, count = 0;
2140    
2141                          // backward search          for (my = 1; my < pParam->mb_height-1; my++)
2142                          b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,                  for (mx = 1; mx < pParam->mb_width-1; mx++) {
2143                                                  &frame->image, i, j,                          VECTOR mv;
2144                                                  mb->b_mvs[0].x, mb->b_mvs[0].y,         /* start point b_directMV */                          const MACROBLOCK *pMB = &pMBs[mx + my * pParam->mb_width];
2145                                                  b_predMV.x, b_predMV.y,                         /* center is b-prediction */                          if (pMB->mode == MODE_INTRA || pMB->mode == MODE_NOT_CODED) continue;
2146                                                  frame->motion_flags,                          mv = pMB->mvs[0];
2147                                                  frame->quant, frame->bcode, pParam,                          a = ABS(mv.x - x) + ABS(mv.y - y);
2148                                                  b_mbs, b_mbs,                          if (a < 6) count += 6 - a;
                                                 &mb->b_mvs[0], &pmv_dontcare);  
   
                         i_sad16 =  
                                 sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 i, j, 16, &mb->mvs[0], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 i, j, 16, &mb->b_mvs[0], edged_width),  
                                                   edged_width);  
                     i_sad16 += calc_delta_16(mb->mvs[0].x-f_predMV.x, mb->mvs[0].y-f_predMV.y,  
                                                                 frame->fcode, frame->quant);  
                     i_sad16 += calc_delta_16(mb->b_mvs[0].x-b_predMV.x, mb->b_mvs[0].y-b_predMV.y,  
                                                                 frame->bcode, frame->quant);  
   
                         get_range(&f_min_dx, &f_max_dx, &f_min_dy, &f_max_dy, i, j, 16, iWidth, iHeight,  
                           frame->fcode);  
                         get_range(&b_min_dx, &b_max_dx, &b_min_dy, &b_max_dy, i, j, 16, iWidth, iHeight,  
                           frame->bcode);  
   
 /* Interpolated MC motion vector search, this is tedious and more complicated because there are  
    two values for everything, always one for backward and one for forward ME. Still, we don't gain  
    much from this search, maybe it should simply be skipped and simply current i_sad16 value used  
    as "optimal". */  
   
                         i_sad16 = Diamond16_InterpolMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i * 16 + j * 16 * edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 mb->mvs[0].x, mb->mvs[0].y,  
                                                 mb->b_mvs[0].x, mb->b_mvs[0].y,  
                                                 i_sad16,  
                                                 &f_interpolMV, &b_interpolMV,  
                                                 f_predMV.x, f_predMV.y, b_predMV.x, b_predMV.y,  
                                                 f_min_dx, f_max_dx, f_min_dy, f_max_dy,  
                                                 b_min_dx, b_max_dx, b_min_dy, b_max_dy,  
                                                 edged_width,  1,  
                                                 frame->fcode, frame->bcode,frame->quant,0);  
   
   
 /*  DIRECT MODE DELTA VECTOR SEARCH.  
     This has to be made more effective, but at the moment I'm happy it's running at all */  
   
 /* range is taken without fcode restriction, just a hack instead of writing down the dimensions, of course */  
   
                         get_range(&min_dx, &max_dx, &min_dy, &max_dy, i, j, 16, iWidth, iHeight, 19);  
   
                         d_sad16 = Diamond16_DirectMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i*16 + j*16*edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 TRB,TRD,  
                                                 0,0,  
                                                 d_sad16,  
                                                 &mb->deltamv,  
                                                 mb->directmv, // this has to be pre-initialized with b_mb->mvs[}  
                                         min_dx, max_dx, min_dy, max_dy,  
                                                 edged_width, 1, frame->quant, 0);  
   
   
 //                      i_sad16 = 65535;                /* remove the comment to disable any of the MODEs */  
 //                      f_sad16 = 65535;  
 //                      b_sad16 = 65535;  
 //                      d_sad16 = 65535;  
   
                         if (f_sad16 < b_sad16) {  
                                 best_sad = f_sad16;  
                                 mb->mode = MODE_FORWARD;  
                         } else {  
                                 best_sad = b_sad16;  
                                 mb->mode = MODE_BACKWARD;  
2149                          }                          }
2150    
2151                          if (i_sad16 < best_sad) {          if (count > *bestcount) {
2152                                  best_sad = i_sad16;                  *bestcount = count;
2153                                  mb->mode = MODE_INTERPOLATE;                  *iDirection = dir;
2154                    GMC->x = x; GMC->y = y;
2155            }
2156                          }                          }
2157    
                         if (d_sad16 < best_sad) {  
2158    
2159                                  if (b_mb->mode == MODE_INTER4V)  static VECTOR
2160    GlobalMotionEst(const MACROBLOCK * const pMBs, const MBParam * const pParam, const uint32_t iFcode)
2161                                  {                                  {
2162    
2163                                  /* how to calc vectors is defined in standard. mvs[] and b_mvs[] are only for motion compensation */          uint32_t count, bestcount = 0;
2164                                  /* for the bitstream, the value mb->deltamv is read directly */          int x, y;
2165            VECTOR gmc = {0,0};
2166                              for (k = 0; k < 4; k++) {          int step, min_x, max_x, min_y, max_y;
2167            uint32_t mx, my;
2168                                                  mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);          int iDirection, bDirection;
                             mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)  
                                                                                         ? ((TRB - TRD) * mb->directmv[k].x) / TRD  
                                                     : mb->mvs[k].x - mb->directmv[k].x);  
   
                             mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);  
                         mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)  
                                                                                         ? ((TRB - TRD) * mb->directmv[k].y) / TRD  
                                             : mb->mvs[k].y - mb->directmv[k].y);  
                                         }  
                                 }  
                                 else  
                                 {  
                                         mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);  
2169    
2170                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)          min_x = min_y = -32<<iFcode;
2171                                                                                  ? ((TRB - TRD) * mb->directmv[0].x) / TRD          max_x = max_y = 32<<iFcode;
                                         : mb->mvs[0].x - mb->directmv[0].x);  
2172    
2173                              mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);  //step1: let's find a rough camera panning
2174            for (step = 32; step >= 2; step /= 2) {
2175                    bestcount = 0;
2176                    for (y = min_y; y <= max_y; y += step)
2177                            for (x = min_x ; x <= max_x; x += step) {
2178                                    count = 0;
2179                                    //for all macroblocks
2180                                    for (my = 1; my < pParam->mb_height-1; my++)
2181                                            for (mx = 1; mx < pParam->mb_width-1; mx++) {
2182                                                    const MACROBLOCK *pMB = &pMBs[mx + my * pParam->mb_width];
2183                                                    VECTOR mv;
2184    
2185                          mb->b_mvs[0].y = (int32_t) ((mb->deltamv.y == 0)                                                  if (pMB->mode == MODE_INTRA || pMB->mode == MODE_NOT_CODED)
2186                                                                                  ? ((TRB - TRD) * mb->directmv[0].y) / TRD                                                          continue;
                                             : mb->mvs[0].y - mb->directmv[0].y);  
2187    
2188                                          mb->mvs[3] = mb->mvs[2] = mb->mvs[1] = mb->mvs[0];                                                  mv = pMB->mvs[0];
2189                                          mb->b_mvs[3] = mb->b_mvs[2] = mb->b_mvs[1] = mb->b_mvs[0];                                                  if ( ABS(mv.x - x) <= step && ABS(mv.y - y) <= step )   /* GMC translation is always halfpel-res */
2190                                                            count++;
2191                                            }
2192                                    if (count >= bestcount) { bestcount = count; gmc.x = x; gmc.y = y; }
2193                  }                  }
2194                    min_x = gmc.x - step;
2195                    max_x = gmc.x + step;
2196                    min_y = gmc.y - step;
2197                    max_y = gmc.y + step;
2198    
                                 best_sad = d_sad16;  
                                 mb->mode = MODE_DIRECT;  
2199                          }                          }
2200    
2201                          switch (mb->mode)          if (bestcount < (pParam->mb_height-2)*(pParam->mb_width-2)/10)
2202                          {                  gmc.x = gmc.y = 0; //no camara pan, no GMC
                                 case MODE_FORWARD:  
                                         f_count++;  
                                         f_predMV = mb->mvs[0];  
                                         break;  
                                 case MODE_BACKWARD:  
                                         b_count++;  
                                         b_predMV = mb->b_mvs[0];  
2203    
2204                                          break;  // step2: let's refine camera panning using gradiend-descent approach.
2205                                  case MODE_INTERPOLATE:  // TODO: more warping points may be evaluated here (like in interpolate mode search - two vectors in one diamond)
2206                                          i_count++;          bestcount = 0;
2207                                          mb->mvs[0] = f_interpolMV;          CheckGMC(gmc.x, gmc.y, 255, &iDirection, pMBs, &bestcount, &gmc, pParam);
2208                                          mb->b_mvs[0] = b_interpolMV;          do {
2209                                          f_predMV = mb->mvs[0];                  x = gmc.x; y = gmc.y;
2210                                          b_predMV = mb->b_mvs[0];                  bDirection = iDirection; iDirection = 0;
2211                                          break;                  if (bDirection & 1) CheckGMC(x - 1, y, 1+4+8, &iDirection, pMBs, &bestcount, &gmc, pParam);
2212                                  case MODE_DIRECT:                  if (bDirection & 2) CheckGMC(x + 1, y, 2+4+8, &iDirection, pMBs, &bestcount, &gmc, pParam);
2213                                          d_count++;                  if (bDirection & 4) CheckGMC(x, y - 1, 1+2+4, &iDirection, pMBs, &bestcount, &gmc, pParam);
2214                                          break;                  if (bDirection & 8) CheckGMC(x, y + 1, 1+2+8, &iDirection, pMBs, &bestcount, &gmc, pParam);
                                 default:  
                                         break;  
                         }  
2215    
2216                  }          } while (iDirection);
         }  
2217    
2218  #ifdef _DEBUG_BFRAME_STAT          if (pParam->m_quarterpel) {
2219          fprintf(stderr,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d\n",                  gmc.x *= 2;
2220                                  f_count,b_count,i_count,d_count);                  gmc.y *= 2;     /* we store the halfpel value as pseudo-qpel to make comparison easier */
2221  #endif          }
2222    
2223            return gmc;
2224  }  }

Legend:
Removed from v.346  
changed lines
  Added in v.676

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