[cvs] / xvidcore / src / motion / motion_est.c Repository:
ViewVC logotype

Diff of /xvidcore/src/motion/motion_est.c

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

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

Legend:
Removed from v.1.44  
changed lines
  Added in v.1.44.2.13

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