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

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

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