[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.12, Mon Oct 21 13:07:33 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*/
714    
715            VECTOR backupMV = *(data->currentQMV);
716            int iDirection; //not needed
717    
718          int32_t iSAD;          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y - 1, 0);
719            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          VECTOR backupMV;          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y, 0);
724            CHECK_CANDIDATE(backupMV.x + 1, backupMV.y, 0);
725    
726          currMV->x = start_x;          CHECK_CANDIDATE(backupMV.x, backupMV.y + 1, 0);
727          currMV->y = start_y;          CHECK_CANDIDATE(backupMV.x, backupMV.y - 1, 0);
728    
729  /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  }
730    
731    static __inline int
732    SkipDecisionP(const IMAGE * current, const IMAGE * reference,
733                                                            const int x, const int y,
734                                                            const uint32_t iEdgedWidth, const uint32_t iQuant)
735    
         do  
736          {          {
737                  iFound = 1;  /*      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                  backupMV = *currMV;          return 1;
749    }
750    
751                  CHECK_MV16_DIRECT_FOUND(backupMV.x - iDiamondSize, backupMV.y);  static __inline void
752                  CHECK_MV16_DIRECT_FOUND(backupMV.x + iDiamondSize, backupMV.y);  SkipMacroblockP(MACROBLOCK *pMB, const int32_t sad)
753                  CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y - iDiamondSize);  {
754                  CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y + iDiamondSize);          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    
758          } while (!iFound);          pMB->qmvs[0].x = pMB->qmvs[1].x = pMB->qmvs[2].x = pMB->qmvs[3].x = 0;
759            pMB->qmvs[0].y = pMB->qmvs[1].y = pMB->qmvs[2].y = pMB->qmvs[3].y = 0;
760    
761          return iMinSAD;          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
762  }  }
763    
764    bool
765  int32_t  MotionEstimation(MBParam * const pParam,
766  AdvDiamond8_MainSearch(const uint8_t * const pRef,                                   FRAMEINFO * const current,
767                                             const uint8_t * const pRefH,                                   FRAMEINFO * const reference,
768                                             const uint8_t * const pRefV,                                   const IMAGE * const pRefH,
769                                             const uint8_t * const pRefHV,                                   const IMAGE * const pRefV,
770                                             const uint8_t * const cur,                                   const IMAGE * const pRefHV,
771                                             const int x,                                   const uint32_t iLimit)
                                            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)  
772  {  {
773            MACROBLOCK *const pMBs = current->mbs;
774            const IMAGE *const pCurrent = &current->image;
775            const IMAGE *const pRef = &reference->image;
776    
777          int32_t iSAD;          const VECTOR zeroMV = { 0, 0 };
   
 /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */  
778    
779          if (iDirection) {          uint32_t x, y;
780                  CHECK_MV8_CANDIDATE(start_x - iDiamondSize, start_y);          uint32_t iIntra = 0;
781                  CHECK_MV8_CANDIDATE(start_x + iDiamondSize, start_y);          int32_t InterBias, quant = current->quant;
782                  CHECK_MV8_CANDIDATE(start_x, start_y - iDiamondSize);          uint8_t *qimage;
783                  CHECK_MV8_CANDIDATE(start_x, start_y + iDiamondSize);  
784            // some pre-initialized thingies for SearchP
785            int32_t temp[5];
786            VECTOR currentMV[5];
787            VECTOR currentQMV[5];
788            int32_t iMinSAD[5];
789            SearchData Data;
790            Data.iEdgedWidth = pParam->edged_width;
791            Data.currentMV = currentMV;
792            Data.currentQMV = currentQMV;
793            Data.iMinSAD = iMinSAD;
794            Data.temp = temp;
795            Data.iFcode = current->fcode;
796            Data.rounding = pParam->m_rounding_type;
797    
798            if((qimage = (uint8_t *) malloc(32 * pParam->edged_width)) == NULL)
799                    return 1; // allocate some mem for qpel interpolated blocks
800                                      // somehow this is dirty since I think we shouldn't use malloc outside
801                                      // encoder_create() - so please fix me!
802    
803            if (sadInit) (*sadInit) ();
804    
805            for (y = 0; y < pParam->mb_height; y++) {
806                    for (x = 0; x < pParam->mb_width; x++)  {
807    
808                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
809                            int32_t sad00 =  pMB->sad16
810                                    = sad16v(pCurrent->y + (x + y * pParam->edged_width) * 16,
811                                                            pRef->y + (x + y * pParam->edged_width) * 16,
812                                                            pParam->edged_width, pMB->sad8 );
813    
814                            if (!(current->global_flags & XVID_LUMIMASKING)) {
815                                    pMB->dquant = NO_CHANGE;
816                                    pMB->quant = current->quant;
817          } else {          } else {
818                  int bDirection = 1 + 2 + 4 + 8;                                  if (pMB->dquant != NO_CHANGE) {
819                                            quant += DQtab[pMB->dquant];
820                                            if (quant > 31) quant = 31;
821                                            else if (quant < 1) quant = 1;
822                                    }
823                                    pMB->quant = quant;
824                            }
825    
826                  do {  //initial skip decision
                         iDirection = 0;  
                         if (bDirection & 1)     //we only want to check left if we came from the right (our last motion was to the left, up-left or down-left)  
                                 CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
827    
828                          if (bDirection & 2)                          if (pMB->dquant == NO_CHANGE && sad00 < pMB->quant * INITIAL_SKIP_THRESH)
829                                  CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);                                  if (SkipDecisionP(pCurrent, pRef, x, y, pParam->edged_width, pMB->quant)) {
830                                            SkipMacroblockP(pMB, sad00);
831                                            continue;
832                                    }
833    
834                          if (bDirection & 4)                          SearchP(pRef->y, pRefH->y, pRefV->y, pRefHV->y, qimage, pCurrent, x,
835                                  CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);                                                  y, current->motion_flags, pMB->quant,
836                                                    &Data, pParam, pMBs, reference->mbs,
837                                                    current->global_flags & XVID_INTER4V, pMB);
838    
839    /* final skip decision, a.k.a. "the vector you found, really that good?" */
840                            if (pMB->dquant == NO_CHANGE && sad00 < pMB->quant * MAX_SAD00_FOR_SKIP
841                                    && ((100*pMB->sad16)/(sad00+1) > FINAL_SKIP_THRESH) )
842                                    if (SkipDecisionP(pCurrent, pRef, x, y, pParam->edged_width, pMB->quant)) {
843                                            SkipMacroblockP(pMB, sad00);
844                                            continue;
845                                    }
846    
847                          if (bDirection & 8)  /* finally, intra decision */
                                 CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
848    
849                          /* now we're doing diagonal checks near our candidate */                          InterBias = MV16_INTER_BIAS;
850                            if (pMB->quant > 8)  InterBias += 50 * (pMB->quant - 8); // to make high quants work
851                            if (y != 0)
852                                    if ((pMB - pParam->mb_width)->mode == MODE_INTER ) InterBias -= 50;
853                            if (x != 0)
854                                    if ((pMB - 1)->mode == MODE_INTER ) InterBias -= 50;
855    
856                          if (iDirection)         //checking if anything found                          if (InterBias < pMB->sad16)  {
857                          {                                  const int32_t deviation =
858                                  bDirection = iDirection;                                          dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,
859                                  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);  
                                 }  
860    
861                                  if (iDirection) {                                  if (deviation < (pMB->sad16 - InterBias)) {
862                                          bDirection += iDirection;                                          if (++iIntra >= iLimit) { free(qimage); return 1; }
863                                          start_x = currMV->x;                                          pMB->mode = MODE_INTRA;
864                                          start_y = currMV->y;                                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =
865                                  }                                                          pMB->mvs[3] = zeroMV;
866                          } else                          //about to quit, eh? not so fast....                                          pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] =
867                          {                                                          pMB->qmvs[3] = zeroMV;
868                                  switch (bDirection) {                                          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =
869                                  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;  
870                                  }                                  }
871                          }                          }
872                  }                  }
                 while (1);                              //forever  
873          }          }
874          return iMinSAD;          free(qimage);
875            return 0;
876  }  }
877    
878    
879  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);  
880    
881          return iMinSAD;  static __inline int
882    make_mask(const VECTOR * const pmv, const int i)
883    {
884            int mask = 255, j;
885            for (j = 0; j < i; j++) {
886                    if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already
887                    if (pmv[i].x == pmv[j].x) {
888                            if (pmv[i].y == pmv[j].y + iDiamondSize) { mask &= ~4; continue; }
889                            if (pmv[i].y == pmv[j].y - iDiamondSize) { mask &= ~8; continue; }
890                    } else
891                            if (pmv[i].y == pmv[j].y) {
892                                    if (pmv[i].x == pmv[j].x + iDiamondSize) { mask &= ~1; continue; }
893                                    if (pmv[i].x == pmv[j].x - iDiamondSize) { mask &= ~2; continue; }
894                            }
895            }
896            return mask;
897  }  }
898    
899  Halfpel8_RefineFuncPtr Halfpel8_Refine;  static __inline void
900    PreparePredictionsP(VECTOR * const pmv, int x, int y, const int iWcount,
901  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)  
902  {  {
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
903    
904          int32_t iSAD;  //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself
         VECTOR backupMV = *currMV;  
905    
906          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y - 1);          if ( (y != 0) && (x != (iWcount-1)) ) {         // [5] top-right neighbour
907          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y - 1);                  pmv[5].x = EVEN(pmv[3].x);
908          CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y - 1);                  pmv[5].y = EVEN(pmv[3].y);
909          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);  
910    
911          return iMinSAD;          if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }// pmv[3] is left neighbour
912  }          else pmv[3].x = pmv[3].y = 0;
913    
914  #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
915        else pmv[4].x = pmv[4].y = 0;
916    
917            // [1] median prediction
918            pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
919    
920            pmv[0].x = pmv[0].y = 0; // [0] is zero; not used in the loop (checked before) but needed here for make_mask
921    
922            pmv[2].x = EVEN(prevMB->mvs[0].x); // [2] is last frame
923            pmv[2].y = EVEN(prevMB->mvs[0].y);
924    
925            if ((x != iWcount-1) && (y != iHcount-1)) {
926                    pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); //[6] right-down neighbour in last frame
927                    pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
928            } else pmv[6].x = pmv[6].y = 0;
929    }
930    
931  int32_t  static void
932  PMVfastSearch16(const uint8_t * const pRef,  SearchP(const uint8_t * const pRef,
933                                  const uint8_t * const pRefH,                                  const uint8_t * const pRefH,
934                                  const uint8_t * const pRefV,                                  const uint8_t * const pRefV,
935                                  const uint8_t * const pRefHV,                                  const uint8_t * const pRefHV,
936                    const uint8_t * const pRefQ,
937                                  const IMAGE * const pCur,                                  const IMAGE * const pCur,
938                                  const int x,                                  const int x,
939                                  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,  
940                                  const uint32_t MotionFlags,                                  const uint32_t MotionFlags,
941                                  const uint32_t iQuant,                                  const uint32_t iQuant,
942                                  const uint32_t iFcode,                  SearchData * const Data,
943                                  const MBParam * const pParam,                                  const MBParam * const pParam,
944                                  const MACROBLOCK * const pMBs,                                  const MACROBLOCK * const pMBs,
945                                  const MACROBLOCK * const prevMBs,                                  const MACROBLOCK * const prevMBs,
946                                  VECTOR * const currMV,                  int inter4v,
947                                  VECTOR * const currPMV)                  MACROBLOCK * const pMB)
948  {  {
         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;  
949    
950          int32_t iDiamondSize;          int i, iDirection = 255, mask, threshA;
951            VECTOR pmv[7];
952    
953          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)()
954          int32_t max_dx;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
955          int32_t min_dy;                                  pParam->width, pParam->height, Data->iFcode, pParam->m_quarterpel);
         int32_t max_dy;  
956    
957          int32_t iFound;          Data->predMV = pmv[0];
958    
959          VECTOR newMV;          Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16;
960          VECTOR backupMV;                        /* just for PMVFAST */          Data->Ref = pRef + (x + Data->iEdgedWidth*y)*16;
961            Data->RefH = pRefH + (x + Data->iEdgedWidth*y) * 16;
962            Data->RefV = pRefV + (x + Data->iEdgedWidth*y) * 16;
963            Data->RefHV = pRefHV + (x + Data->iEdgedWidth*y) * 16;
964            Data->RefQ = pRefQ;
965    
966          VECTOR pmv[4];          Data->lambda16 = lambda_vec16[iQuant];
967          int32_t psad[4];          Data->lambda8 = lambda_vec8[iQuant];
968    
969          MainSearch16FuncPtr MainSearchPtr;          if (!(MotionFlags & PMV_HALFPEL16)) {
970                    Data->min_dx = EVEN(Data->min_dx);
971                    Data->max_dx = EVEN(Data->max_dx);
972                    Data->min_dy = EVEN(Data->min_dy);
973                    Data->max_dy = EVEN(Data->max_dy); }
974    
975            if (pMB->dquant != NO_CHANGE) inter4v = 0;
976    
977            for(i = 0;  i < 5; i++)
978                    Data->currentMV[i].x = Data->currentMV[i].y = 0;
979    
980            if (pParam->m_quarterpel) {
981                    Data->predQMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
982                    i = d_mv_bits(Data->predQMV.x, Data->predQMV.y, Data->iFcode);
983            } else i = d_mv_bits(Data->predMV.x, Data->predMV.y, Data->iFcode);
984    
985            Data->iMinSAD[0] = pMB->sad16 + lambda_vec16[iQuant] * i;
986            Data->iMinSAD[1] = pMB->sad8[0] + lambda_vec8[iQuant] * i;
987            Data->iMinSAD[2] = pMB->sad8[1];
988            Data->iMinSAD[3] = pMB->sad8[2];
989            Data->iMinSAD[4] = pMB->sad8[3];
990    
991          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;          if ((x == 0) && (y == 0)) threshA = 512;
992            else {
993                    threshA = Data->temp[0]; // that's when we keep this SAD atm
994                    if (threshA < 512) threshA = 512;
995                    if (threshA > 1024) threshA = 1024; }
996    
997          int32_t threshA, threshB;          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
998          int32_t bPredEq;                                          prevMBs + x + y * pParam->mb_width);
         int32_t iMinSAD, iSAD;  
999    
1000  /* Get maximum range */          if (pParam->m_quarterpel) CheckCandidate = CheckCandidate16Q;
1001          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,          else
1002                            iFcode);                  if (inter4v) CheckCandidate = CheckCandidate16;
1003                    else CheckCandidate = CheckCandidate16no4v;
1004    
1005  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  /* main loop. checking all predictions */
1006    
1007          if (!(MotionFlags & PMV_HALFPEL16)) {          for (i = 1; i < 7; i++) {
1008                  min_dx = EVEN(min_dx);                  if (!(mask = make_mask(pmv, i)) ) continue;
1009                  max_dx = EVEN(max_dx);                  (*CheckCandidate)(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1010                  min_dy = EVEN(min_dy);                  if (Data->iMinSAD[0] <= threshA) break;
                 max_dy = EVEN(max_dy);  
1011          }          }
1012    
1013          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */          if ((Data->iMinSAD[0] <= threshA) ||
1014          //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);                          (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
1015          bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);                          (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16))) {
1016                    inter4v = 0;
         if ((x == 0) && (y == 0)) {  
                 threshA = 512;  
                 threshB = 1024;  
1017          } 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;  
1018    
1019  /* Step 4: Calculate SAD around the Median prediction.                  MainSearchFunc * MainSearchPtr;
1020     MinSAD=SAD                  if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1021     If Motion Vector equal to Previous frame motion vector                  else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1022     and MinSAD<PrevFrmSAD goto Step 10.                          else MainSearchPtr = DiamondSearch;
1023     If SAD<=256 goto Step 10.  
1024  */                  (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
1025    
1026    /* extended search, diamond starting in 0,0 and in prediction.
1027            note that this search is/might be done in halfpel positions,
1028            which makes it more different than the diamond above */
1029    
1030          currMV->x = start_x;                  if (MotionFlags & PMV_EXTSEARCH16) {
1031          currMV->y = start_y;                          int32_t bSAD;
1032                            VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
1033          if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */                          if (!(MotionFlags & PMV_HALFPELREFINE16)) // who's gonna use extsearch and no halfpel?
1034                  currMV->x = EVEN(currMV->x);                                  startMV.x = EVEN(startMV.x); startMV.y = EVEN(startMV.y);
1035                  currMV->y = EVEN(currMV->y);                          if (!(MVequal(startMV, backupMV))) {
1036          }                                  bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1037    
1038          if (currMV->x > max_dx) {                                  (*CheckCandidate)(startMV.x, startMV.y, 255, &iDirection, Data);
1039                  currMV->x = max_dx;                                  (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
1040          }                                  if (bSAD < Data->iMinSAD[0]) {
1041          if (currMV->x < min_dx) {                                          Data->currentMV[0] = backupMV;
1042                  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;  
1043          }          }
1044    
1045          iMinSAD =                          backupMV = Data->currentMV[0];
1046                  sad16(cur,                          if (MotionFlags & PMV_HALFPELREFINE16) startMV.x = startMV.y = 1;
1047                            get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,                          else startMV.x = startMV.y = 0;
1048                                                   iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);                          if (!(MVequal(startMV, backupMV))) {
1049          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);  
1050    
1051          if ((iMinSAD < 256) ||                                  (*CheckCandidate)(startMV.x, startMV.y, 255, &iDirection, Data);
1052                  ((MVequal(*currMV, prevMB->mvs[0])) &&                                  (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
1053                   ((int32_t) iMinSAD < prevMB->sad16))) {                                  if (bSAD < Data->iMinSAD[0]) {
1054                  if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode                                          Data->currentMV[0] = backupMV;
1055                  {                                          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;  
1056                          }                          }
1057                  }                  }
   
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
1058          }          }
1059    
1060            if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(Data);
1061    
1062  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion          for(i = 0; i < 5; i++) {
1063     vector of the median.                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // initialize qpel vectors
1064     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2                  Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
1065  */          }
   
         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;  
1066    
1067  /*          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.  
 */  
1068    
1069  // (0,0) is always possible                  CheckCandidate = CheckCandidate16_qpel;
1070                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1071                                    pParam->width, pParam->height, Data->iFcode, 0);
1072    
1073          if (!MVzero(pmv[0]))                  QuarterpelRefine(Data);
1074                  CHECK_MV16_ZERO;          }
1075    
1076  // previous frame MV is always possible          if (inter4v) {
1077                    SearchData Data8;
1078                    Data8.iFcode = Data->iFcode;
1079                    Data8.lambda8 = Data->lambda8;
1080                    Data8.iEdgedWidth = Data->iEdgedWidth;
1081                    Data8.RefQ = Data->RefQ;
1082                    Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
1083                    Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
1084                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
1085                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
1086            }
1087    
1088          if (!MVzero(prevMB->mvs[0]))          if (!(inter4v) ||
1089                  if (!MVequal(prevMB->mvs[0], pmv[0]))                  (Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
1090                          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);                          Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {
1091    // INTER MODE
1092                    pMB->mode = MODE_INTER;
1093                    pMB->mvs[0] = pMB->mvs[1]
1094                            = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
1095    
1096  // left neighbour, if allowed                  pMB->qmvs[0] = pMB->qmvs[1]
1097                            = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1098    
1099          if (!MVzero(pmv[1]))                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
1100                  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);  
                                 }  
1101    
1102                                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);                  if(pParam->m_quarterpel) {
1103                          }                          pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predQMV.x;
1104  // 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);  
1105                                          }                                          }
1106                                          CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);                  else {
1107                            pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1108  // 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);  
1109                                                                                  }                                                                                  }
1110                                                                                  CHECK_MV16_CANDIDATE(pmv[3].x,          } else {
1111                                                                                                                           pmv[3].y);  // INTER4V MODE; all other things are already set in Search8
1112                    pMB->mode = MODE_INTER4V;
1113                    pMB->sad16 = Data->iMinSAD[1] + Data->iMinSAD[2] +
1114                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * iQuant;
1115                                                                          }                                                                          }
1116                                  }                                  }
1117    
1118          if ((MVzero(*currMV)) &&  static void
1119                  (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  Search8(const SearchData * const OldData,
1120                  iMinSAD -= MV16_00_BIAS;                  const int x, const int y,
1121                    const uint32_t MotionFlags,
1122                    const MBParam * const pParam,
1123                    MACROBLOCK * const pMB,
1124                    const MACROBLOCK * const pMBs,
1125                    const int block,
1126                    SearchData * const Data)
1127    {
1128            Data->iMinSAD = OldData->iMinSAD + 1 + block;
1129            Data->currentMV = OldData->currentMV + 1 + block;
1130            Data->currentQMV = OldData->currentQMV + 1 + block;
1131    
1132            if(pParam->m_quarterpel) {
1133                    Data->predQMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2 , y/2, block);
1134                    if (block != 0) *(Data->iMinSAD) += Data->lambda8 *
1135                                                                            d_mv_bits(      Data->currentQMV->x - Data->predQMV.x,
1136                                                                                                    Data->currentQMV->y - Data->predQMV.y,
1137                                                                                                    Data->iFcode);
1138                    CheckCandidate = CheckCandidate8Q;
1139            } else {
1140                    Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2 , y/2, block);
1141                    if (block != 0) *(Data->iMinSAD) += Data->lambda8 *
1142                                                                            d_mv_bits(      Data->currentMV->x - Data->predMV.x,
1143                                                                                                    Data->currentMV->y - Data->predMV.y,
1144                                                                                                    Data->iFcode);
1145                    CheckCandidate = CheckCandidate8;
1146            }
1147    
1148  /* 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.  
 */  
1149    
1150          if ((iMinSAD <= threshA) ||                  Data->Ref = OldData->Ref + 8 * ((block&1) + pParam->edged_width*(block>>1));
1151                  (MVequal(*currMV, prevMB->mvs[0]) &&                  Data->RefH = OldData->RefH + 8 * ((block&1) + pParam->edged_width*(block>>1));
1152                   ((int32_t) iMinSAD < prevMB->sad16))) {                  Data->RefV = OldData->RefV + 8 * ((block&1) + pParam->edged_width*(block>>1));
1153                  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;  
         }  
1154    
1155                    Data->Cur = OldData->Cur + 8 * ((block&1) + pParam->edged_width*(block>>1));
1156    
1157  /************ (Diamond Search)  **************/                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1158  /*                                  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.  
 */  
1159    
1160          if (MotionFlags & PMV_USESQUARES16)                  if (MotionFlags & PMV_EXTSEARCH8) {
1161                  MainSearchPtr = Square16_MainSearch;                          int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
1162    
1163          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                          MainSearchFunc *MainSearchPtr;
1164                            if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
1165                                    else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1166                                            else MainSearchPtr = DiamondSearch;
1167    
1168                            (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);
1169    
1170  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                          if(*(Data->iMinSAD) < temp_sad) {
1171          iSAD =                                          Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1172                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                          Data->currentQMV->y = 2 * Data->currentMV->y;
1173                                                    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;  
1174          }          }
1175    
1176          if (MotionFlags & PMV_EXTSEARCH16) {                  if (MotionFlags & PMV_HALFPELREFINE8) {
1177  /* extended: search (up to) two more times: orignal prediction and (0,0) */                          int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
1178    
1179                  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);  
1180    
1181                          if (iSAD < iMinSAD) {                          if(*(Data->iMinSAD) < temp_sad) { // we have found a better match
1182                                  *currMV = newMV;                                  Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1183                                  iMinSAD = iSAD;                                  Data->currentQMV->y = 2 * Data->currentMV->y;
1184                          }                          }
1185                  }                  }
1186    
1187                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                  if(pParam->m_quarterpel) {
1188                          iSAD =                          if((!(Data->currentQMV->x & 1)) && (!(Data->currentQMV->y & 1)) &&
1189                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                                  (MotionFlags & PMV_QUARTERPELREFINE8)) {
1190                                                                    iMinSAD, &newMV, center_x, center_y,                          CheckCandidate = CheckCandidate8_qpel;
1191                                                                    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,
1192                                                                    iEdgedWidth, iDiamondSize, iFcode,                                  pParam->width, pParam->height, OldData->iFcode, pParam->m_quarterpel);
1193                                                                    iQuant, iFound);                          QuarterpelRefine(Data);
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
1194                          }                          }
1195                  }                  }
1196          }          }
1197    
1198  /*          if(pParam->m_quarterpel) {
1199     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.                  pMB->pmvs[block].x = Data->currentQMV->x - Data->predQMV.x;
1200  */                  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);  
1201                  }                  }
1202          } else {          else {
1203                  currMV->x = start_x;                  pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1204                  currMV->y = start_y;                  pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
         }  
         return iMinSAD;  
1205  }  }
1206    
1207            pMB->mvs[block] = *(Data->currentMV);
1208            pMB->qmvs[block] = *(Data->currentQMV);
1209    
1210            pMB->sad8[block] =  4 * (*Data->iMinSAD);
1211    }
1212    
1213    /* B-frames code starts here */
1214    
1215  int32_t  static __inline VECTOR
1216  Square8_MainSearch(const uint8_t * const pRef,  ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1217                                          const uint8_t * const pRefH,  {
1218                                          const uint8_t * const pRefV,  /* the stupidiest function ever */
1219                                          const uint8_t * const pRefHV,          if (mode == MODE_FORWARD) return pMB->mvs[0];
1220                                          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;  
1221  }  }
1222    
1223    static void __inline
1224    PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
1225                                                            const uint32_t iWcount,
1226                                                            const MACROBLOCK * const pMB,
1227                                                            const uint32_t mode_curr)
1228    {
1229    
1230            // [0] is prediction
1231            pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
1232    
1233            pmv[1].x = pmv[1].y = 0; // [1] is zero
1234    
1235            pmv[2] = ChoosePred(pMB, mode_curr);
1236            pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
1237    
1238  int32_t          if ((y != 0)&&(x != (int)(iWcount+1))) {                        // [3] top-right neighbour
1239  Halfpel8_Refine_c(const uint8_t * const pRef,                  pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
1240                                  const uint8_t * const pRefH,                  pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
1241                                  const uint8_t * const pRefV,          } else pmv[3].x = pmv[3].y = 0;
1242                                  const uint8_t * const pRefHV,  
1243                                  const uint8_t * const cur,          if (y != 0) {
1244                                  const int x,                  pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
1245                                  const int y,                  pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
1246                                  VECTOR * const currMV,          } else pmv[4].x = pmv[4].y = 0;
                                 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) */  
1247    
1248          int32_t iSAD;          if (x != 0) {
1249          VECTOR backupMV = *currMV;                  pmv[5] = ChoosePred(pMB-1, mode_curr);
1250                    pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1251            } else pmv[5].x = pmv[5].y = 0;
1252    
1253          CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y - 1);          if ((x != 0)&&(y != 0)) {
1254          CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y - 1);                  pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
1255          CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y - 1);                  pmv[6].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1256          CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y);          } else pmv[6].x = pmv[6].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);  
1257    
1258          return iMinSAD;  // more?
1259  }  }
1260    
1261    
1262  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)  /* search backward or forward, for b-frames */
1263    static void
1264  int32_t  SearchBF(       const uint8_t * const pRef,
 PMVfastSearch8(const uint8_t * const pRef,  
1265                             const uint8_t * const pRefH,                             const uint8_t * const pRefH,
1266                             const uint8_t * const pRefV,                             const uint8_t * const pRefV,
1267                             const uint8_t * const pRefHV,                             const uint8_t * const pRefHV,
1268                             const IMAGE * const pCur,                             const IMAGE * const pCur,
1269                             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,  
1270                             const uint32_t MotionFlags,                             const uint32_t MotionFlags,
                            const uint32_t iQuant,  
1271                             const uint32_t iFcode,                             const uint32_t iFcode,
1272                             const MBParam * const pParam,                             const MBParam * const pParam,
1273                             const MACROBLOCK * const pMBs,                          MACROBLOCK * const pMB,
1274                             const MACROBLOCK * const prevMBs,                          const VECTOR * const predMV,
1275                             VECTOR * const currMV,                          int32_t * const best_sad,
1276                             VECTOR * const currPMV)                          const int32_t mode_current,
1277                            SearchData * const Data)
1278  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
   
         const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;  
   
         int32_t iDiamondSize;  
1279    
1280          int32_t min_dx;          const int32_t iEdgedWidth = pParam->edged_width;
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
1281    
1282          VECTOR pmv[4];          int i, iDirection, mask;
1283          int32_t psad[4];          VECTOR pmv[7];
1284          VECTOR newMV;          MainSearchFunc *MainSearchPtr;
1285          VECTOR backupMV;          *Data->iMinSAD = MV_MAX_ERROR;
1286          VECTOR startMV;          Data->iFcode = iFcode;
1287    
1288  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          Data->Ref = pRef + (x + y * iEdgedWidth) * 16;
1289          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;          Data->RefH = pRefH + (x + y * iEdgedWidth) * 16;
1290            Data->RefV = pRefV + (x + y * iEdgedWidth) * 16;
1291            Data->RefHV = pRefHV + (x + y * iEdgedWidth) * 16;
1292    
1293           int32_t threshA, threshB;          Data->predMV = *predMV;
         int32_t iFound, bPredEq;  
         int32_t iMinSAD, iSAD;  
1294    
1295          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,
1296                                    pParam->width, pParam->height, iFcode, pParam->m_quarterpel);
1297    
1298          MainSearch8FuncPtr MainSearchPtr;          pmv[0] = Data->predMV;
1299            PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);
1300    
1301          /* Init variables */          Data->currentMV->x = Data->currentMV->y = 0;
         startMV.x = start_x;  
         startMV.y = start_y;  
1302    
1303          /* Get maximum range */          CheckCandidate = CheckCandidate16no4v;
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,  
                           iFcode);  
1304    
1305          if (!(MotionFlags & PMV_HALFPELDIAMOND8)) {  // main loop. checking all predictions
1306                  min_dx = EVEN(min_dx);          for (i = 0; i < 8; i++) {
1307                  max_dx = EVEN(max_dx);                  if (!(mask = make_mask(pmv, i)) ) continue;
1308                  min_dy = EVEN(min_dy);                  CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
                 max_dy = EVEN(max_dy);  
1309          }          }
1310    
1311          /* because we might use IF (dx>max_dx) THEN dx=max_dx; */          if (MotionFlags & PMV_USESQUARES16)
1312          //bPredEq = get_pmvdata(pMBs, (x >> 1), (y >> 1), iWcount, iSubBlock, pmv, psad);                  MainSearchPtr = SquareSearch;
1313          bPredEq = get_pmvdata2(pMBs, iWcount, 0, (x >> 1), (y >> 1), iSubBlock, pmv, psad);          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
1314                    MainSearchPtr = AdvDiamondSearch;
1315          if ((x == 0) && (y == 0)) {                  else MainSearchPtr = DiamondSearch;
                 threshA = 512 / 4;  
                 threshB = 1024 / 4;  
1316    
1317          } 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.  
 */  
1318    
1319            HalfpelRefine(Data);
1320    
1321  // Prepare for main loop  // three bits are needed to code backward mode. four for forward
1322    // we treat the bits just like they were vector's
1323            if (mode_current == MODE_FORWARD) *Data->iMinSAD +=  4 * Data->lambda16 * 2;
1324            else *Data->iMinSAD +=  3 * Data->lambda16 * 2;
1325    
1326            if (*Data->iMinSAD < *best_sad) {
1327                    *best_sad = *Data->iMinSAD;
1328                    pMB->mode = mode_current;
1329                    pMB->pmvs[0].x = Data->currentMV->x - predMV->x;
1330                    pMB->pmvs[0].y = Data->currentMV->y - predMV->y;
1331                    if (mode_current == MODE_FORWARD) pMB->mvs[0] = *(Data->currentMV+2) = *Data->currentMV;
1332                    else pMB->b_mvs[0] = *(Data->currentMV+1) = *Data->currentMV; //we store currmv for interpolate search
1333            }
1334    
1335    if (MotionFlags & PMV_USESQUARES8)  }
       MainSearchPtr = Square8_MainSearch;  
   else  
1336    
1337          if (MotionFlags & PMV_ADVANCEDDIAMOND8)  static int32_t
1338                  MainSearchPtr = AdvDiamond8_MainSearch;  SearchDirect(const IMAGE * const f_Ref,
1339          else                                  const uint8_t * const f_RefH,
1340                  MainSearchPtr = Diamond8_MainSearch;                                  const uint8_t * const f_RefV,
1341                                    const uint8_t * const f_RefHV,
1342                                    const IMAGE * const b_Ref,
1343                                    const uint8_t * const b_RefH,
1344                                    const uint8_t * const b_RefV,
1345                                    const uint8_t * const b_RefHV,
1346                                    const IMAGE * const pCur,
1347                                    const int x, const int y,
1348                                    const uint32_t MotionFlags,
1349                                    const int32_t TRB, const int32_t TRD,
1350                                    const MBParam * const pParam,
1351                                    MACROBLOCK * const pMB,
1352                                    const MACROBLOCK * const b_mb,
1353                                    int32_t * const best_sad,
1354                                    SearchData * const Data)
1355    
1356    {
1357            int32_t skip_sad;
1358            int k;
1359    
1360            MainSearchFunc *MainSearchPtr;
1361    
1362            *Data->iMinSAD = 256*4096;
1363            Data->referencemv = b_mb->mvs;
1364    
1365            Data->Ref = f_Ref->y + (x + Data->iEdgedWidth*y) * 16;
1366            Data->RefH = f_RefH + (x + Data->iEdgedWidth*y) * 16;
1367            Data->RefV = f_RefV + (x + Data->iEdgedWidth*y) * 16;
1368            Data->RefHV = f_RefHV + (x + Data->iEdgedWidth*y) * 16;
1369            Data->bRef = b_Ref->y + (x + Data->iEdgedWidth*y) * 16;
1370            Data->bRefH = b_RefH + (x + Data->iEdgedWidth*y) * 16;
1371            Data->bRefV = b_RefV + (x + Data->iEdgedWidth*y) * 16;
1372            Data->bRefHV = b_RefHV + (x + Data->iEdgedWidth*y) * 16;
1373    
1374            Data->max_dx = 2 * pParam->width - 2 * (x) * 16;
1375            Data->max_dy = 2 * pParam->height - 2 * (y) * 16;
1376            Data->min_dx = -(2 * 16 + 2 * (x) * 16);
1377            Data->min_dy = -(2 * 16 + 2 * (y) * 16);
1378    
1379            for (k = 0; k < 4; k++) {
1380                    pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);
1381                    pMB->b_mvs[k].x = Data->directmvB[k].x = ((TRB - TRD) * Data->referencemv[k].x) / TRD;
1382                    pMB->mvs[k].y = Data->directmvF[k].y = ((TRB * Data->referencemv[k].y) / TRD);
1383                    pMB->b_mvs[k].y = Data->directmvB[k].y = ((TRB - TRD) * Data->referencemv[k].y) / TRD;
1384    
1385                    if ( ( pMB->b_mvs[k].x > Data->max_dx ) || ( pMB->b_mvs[k].x < Data->min_dx )
1386                            || ( pMB->b_mvs[k].y > Data->max_dy ) || ( pMB->b_mvs[k].y < Data->min_dy )) {
1387    
1388                            *best_sad = 256*4096; // in that case, we won't use direct mode
1389                            pMB->mode = MODE_DIRECT; // just to make sure it doesn't say "MODE_DIRECT_NONE_MV"
1390                            pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;
1391                            return 0;
1392                    }
1393                    if (b_mb->mode != MODE_INTER4V) {
1394                            pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mvs[0];
1395                            pMB->b_mvs[1] = pMB->b_mvs[2] = pMB->b_mvs[3] = pMB->b_mvs[0];
1396                            Data->directmvF[1] = Data->directmvF[2] = Data->directmvF[3] = Data->directmvF[0];
1397                            Data->directmvB[1] = Data->directmvB[2] = Data->directmvB[3] = Data->directmvB[0];
1398                            break;
1399                    }
1400            }
1401    
1402          *currMV = startMV;          if (b_mb->mode == MODE_INTER4V)
1403                    CheckCandidate = CheckCandidateDirect;
1404            else CheckCandidate = CheckCandidateDirectno4v;
1405    
1406          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.  
 */  
1407    
1408          if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))  // skip decision
1409                  iDiamondSize = 1;               // 1 halfpel!          if (*Data->iMinSAD - 2 * Data->lambda16 < (uint32_t)pMB->quant * SKIP_THRESH_B) {
1410          else                  //possible skip - checking chroma. everything copied from MC
1411                  iDiamondSize = 2;               // 2 halfpel = 1 full pixel!                  //this is not full chroma compensation, only it's fullpel approximation. should work though
1412                    int sum, dx, dy, b_dx, b_dy;
1413    
1414          if (!(MotionFlags & PMV_HALFPELDIAMOND8))                  sum = pMB->mvs[0].x + pMB->mvs[1].x + pMB->mvs[2].x + pMB->mvs[3].x;
1415                  iDiamondSize *= 2;                  dx = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1416    
1417                    sum = pMB->mvs[0].y + pMB->mvs[1].y + pMB->mvs[2].y + pMB->mvs[3].y;
1418                    dy = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1419    
1420  /*                  sum = pMB->b_mvs[0].x + pMB->b_mvs[1].x + pMB->b_mvs[2].x + pMB->b_mvs[3].x;
1421     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;  
         }  
1422    
1423          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;
1424  /* 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));
1425    
1426                  if (!(MVequal(pmv[0], backupMV))) {                  sum = sad8bi(pCur->u + 8*x + 8*y*(Data->iEdgedWidth/2),
1427                          iSAD =                                          f_Ref->u + (y*8 + dy/2) * (Data->iEdgedWidth/2) + x*8 + dx/2,
1428                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                          b_Ref->u + (y*8 + b_dy/2) * (Data->iEdgedWidth/2) + x*8 + b_dx/2,
1429                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,                                          Data->iEdgedWidth/2);
1430                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,                  sum += sad8bi(pCur->v + 8*x + 8*y*(Data->iEdgedWidth/2),
1431                                                                    iDiamondSize, iFcode, iQuant, iFound);                                          f_Ref->v + (y*8 + dy/2) * (Data->iEdgedWidth/2) + x*8 + dx/2,
1432                                            b_Ref->v + (y*8 + b_dy/2) * (Data->iEdgedWidth/2) + x*8 + b_dx/2,
1433                                            Data->iEdgedWidth/2);
1434    
1435                          if (iSAD < iMinSAD) {                  if (sum < MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) {
1436                                  *currMV = newMV;                          pMB->mode = MODE_DIRECT_NONE_MV;
1437                                  iMinSAD = iSAD;                          return *Data->iMinSAD;
1438                          }                          }
1439                  }                  }
1440    
1441                  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);  
1442    
1443                          if (iSAD < iMinSAD) {  //  DIRECT MODE DELTA VECTOR SEARCH.
1444                                  *currMV = newMV;  //      This has to be made more effective, but at the moment I'm happy it's running at all
1445                                  iMinSAD = iSAD;  
1446                          }          if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1447                  }                  else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1448          }                          else MainSearchPtr = DiamondSearch;
1449    
1450            (*MainSearchPtr)(0, 0, Data, 255);
1451    
1452  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.          HalfpelRefine(Data);
    By performing an optional local half-pixel search, we can refine this result even further.  
 */  
1453    
1454    PMVfast8_Terminate_with_Refine:          *Data->iMinSAD +=  1 * Data->lambda16 * 2; // one bit is needed to code direct mode
1455          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step          *best_sad = *Data->iMinSAD;
                 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);  
1456    
1457            if (b_mb->mode == MODE_INTER4V)
1458                    pMB->mode = MODE_DIRECT;
1459            else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation
1460    
1461    PMVfast8_Terminate_without_Refine:          pMB->pmvs[3] = *Data->currentMV;
         currPMV->x = currMV->x - center_x;  
         currPMV->y = currMV->y - center_y;  
1462    
1463          return iMinSAD;          for (k = 0; k < 4; k++) {
1464                    pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
1465                    pMB->b_mvs[k].x = ((Data->currentMV->x == 0)
1466                                                            ? Data->directmvB[k].x
1467                                                            : pMB->mvs[k].x - Data->referencemv[k].x);
1468                    pMB->mvs[k].y = (Data->directmvF[k].y + Data->currentMV->y);
1469                    pMB->b_mvs[k].y = ((Data->currentMV->y == 0)
1470                                                            ? Data->directmvB[k].y
1471                                                            : pMB->mvs[k].y - Data->referencemv[k].y);
1472                    if (b_mb->mode != MODE_INTER4V) {
1473                            pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1474                            pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1475                            break;
1476                    }
1477            }
1478            return skip_sad;
1479  }  }
1480    
1481  int32_t  
1482  EPZSSearch16(const uint8_t * const pRef,  static __inline void
1483                           const uint8_t * const pRefH,  SearchInterpolate(const uint8_t * const f_Ref,
1484                           const uint8_t * const pRefV,                                  const uint8_t * const f_RefH,
1485                           const uint8_t * const pRefHV,                                  const uint8_t * const f_RefV,
1486                                    const uint8_t * const f_RefHV,
1487                                    const uint8_t * const b_Ref,
1488                                    const uint8_t * const b_RefH,
1489                                    const uint8_t * const b_RefV,
1490                                    const uint8_t * const b_RefHV,
1491                           const IMAGE * const pCur,                           const IMAGE * const pCur,
1492                           const int x,                                  const int x, const int y,
1493                           const int y,                                  const uint32_t fcode,
1494                          const int start_x,                                  const uint32_t bcode,
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
1495                           const uint32_t MotionFlags,                           const uint32_t MotionFlags,
                          const uint32_t iQuant,  
                          const uint32_t iFcode,  
1496                           const MBParam * const pParam,                           const MBParam * const pParam,
1497                           const MACROBLOCK * const pMBs,                                  const VECTOR * const f_predMV,
1498                           const MACROBLOCK * const prevMBs,                                  const VECTOR * const b_predMV,
1499                           VECTOR * const currMV,                                  MACROBLOCK * const pMB,
1500                           VECTOR * const currPMV)                                  int32_t * const best_sad,
1501                                    SearchData * const fData)
1502    
1503  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const uint32_t iHcount = pParam->mb_height;  
1504    
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
1505          const int32_t iEdgedWidth = pParam->edged_width;          const int32_t iEdgedWidth = pParam->edged_width;
1506    
1507          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          int iDirection, i, j;
1508            SearchData bData;
1509    
1510          int32_t min_dx;          *(bData.iMinSAD = fData->iMinSAD) = 4096*256;
1511          int32_t max_dx;          bData.Cur = fData->Cur;
1512          int32_t min_dy;          fData->iEdgedWidth = bData.iEdgedWidth = iEdgedWidth;
1513          int32_t max_dy;          bData.currentMV = fData->currentMV + 1;
1514            bData.lambda16 = fData->lambda16;
1515            fData->iFcode = bData.bFcode = fcode; fData->bFcode = bData.iFcode = bcode;
1516    
1517            bData.bRef = fData->Ref = f_Ref + (x + y * iEdgedWidth) * 16;
1518            bData.bRefH = fData->RefH = f_RefH + (x + y * iEdgedWidth) * 16;
1519            bData.bRefV = fData->RefV = f_RefV + (x + y * iEdgedWidth) * 16;
1520            bData.bRefHV = fData->RefHV = f_RefHV + (x + y * iEdgedWidth) * 16;
1521            bData.Ref = fData->bRef = b_Ref + (x + y * iEdgedWidth) * 16;
1522            bData.RefH = fData->bRefH = b_RefH + (x + y * iEdgedWidth) * 16;
1523            bData.RefV = fData->bRefV = b_RefV + (x + y * iEdgedWidth) * 16;
1524            bData.RefHV = fData->bRefHV = b_RefHV + (x + y * iEdgedWidth) * 16;
1525    
1526            bData.bpredMV = fData->predMV = *f_predMV;
1527            fData->bpredMV = bData.predMV = *b_predMV;
1528    
1529            fData->currentMV[0] = fData->currentMV[3]; //forward search stored it's vector here. backward stored it in the place it's needed
1530            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);
1531            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);
1532    
1533            if (fData->currentMV[0].x > fData->max_dx) fData->currentMV[0].x = fData->max_dx;
1534            if (fData->currentMV[0].x < fData->min_dx) fData->currentMV[0].x = fData->min_dy;
1535            if (fData->currentMV[0].y > fData->max_dy) fData->currentMV[0].y = fData->max_dx;
1536            if (fData->currentMV[0].y > fData->min_dy) fData->currentMV[0].y = fData->min_dy;
1537    
1538            if (fData->currentMV[1].x > bData.max_dx) fData->currentMV[1].x = bData.max_dx;
1539            if (fData->currentMV[1].x < bData.min_dx) fData->currentMV[1].x = bData.min_dy;
1540            if (fData->currentMV[1].y > bData.max_dy) fData->currentMV[1].y = bData.max_dx;
1541            if (fData->currentMV[1].y > bData.min_dy) fData->currentMV[1].y = bData.min_dy;
1542    
1543          VECTOR newMV;          CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, 255, &iDirection, fData);
         VECTOR backupMV;  
1544    
1545          VECTOR pmv[4];  //diamond. I wish we could use normal mainsearch functions (square, advdiamond)
         int32_t psad[8];  
1546    
1547          static MACROBLOCK *oldMBs = NULL;          do {
1548                    iDirection = 255;
1549                    // forward MV moves
1550                    i = fData->currentMV[0].x; j = fData->currentMV[0].y;
1551    
1552                    CheckCandidateInt(i + 1, j, 0, &iDirection, fData);
1553                    CheckCandidateInt(i, j + 1, 0, &iDirection, fData);
1554                    CheckCandidateInt(i - 1, j, 0, &iDirection, fData);
1555                    CheckCandidateInt(i, j - 1, 0, &iDirection, fData);
1556    
1557                    // backward MV moves
1558                    i = fData->currentMV[1].x; j = fData->currentMV[1].y;
1559                    fData->currentMV[2] = fData->currentMV[0];
1560    
1561                    CheckCandidateInt(i + 1, j, 0, &iDirection, &bData);
1562                    CheckCandidateInt(i, j + 1, 0, &iDirection, &bData);
1563                    CheckCandidateInt(i - 1, j, 0, &iDirection, &bData);
1564                    CheckCandidateInt(i, j - 1, 0, &iDirection, &bData);
1565    
1566            } while (!(iDirection));
1567    
1568    // two bits are needed to code interpolate mode. we treat the bits just like they were vector's
1569            *fData->iMinSAD +=  2 * fData->lambda16 * 2;
1570    
1571            if (*fData->iMinSAD < *best_sad) {
1572                    *best_sad = *fData->iMinSAD;
1573                    pMB->mvs[0] = fData->currentMV[0];
1574                    pMB->b_mvs[0] = fData->currentMV[1];
1575                    pMB->mode = MODE_INTERPOLATE;
1576    
1577                    pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;
1578                    pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;
1579                    pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;
1580                    pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;
1581            }
1582    }
1583    
 //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;  
         const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;  
         MACROBLOCK *oldMB = NULL;  
1584    
1585           int32_t thresh2;  void
1586          int32_t bPredEq;  MotionEstimationBVOP(MBParam * const pParam,
1587          int32_t iMinSAD, iSAD = 9999;                                           FRAMEINFO * const frame,
1588                                             const int32_t time_bp,
1589                                             const int32_t time_pp,
1590                                             // forward (past) reference
1591                                             const MACROBLOCK * const f_mbs,
1592                                             const IMAGE * const f_ref,
1593                                             const IMAGE * const f_refH,
1594                                             const IMAGE * const f_refV,
1595                                             const IMAGE * const f_refHV,
1596                                             // backward (future) reference
1597                                             const MACROBLOCK * const b_mbs,
1598                                             const IMAGE * const b_ref,
1599                                             const IMAGE * const b_refH,
1600                                             const IMAGE * const b_refV,
1601                                             const IMAGE * const b_refHV)
1602    {
1603            uint32_t i, j;
1604            int32_t best_sad, skip_sad;
1605            int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;
1606            static const VECTOR zeroMV={0,0};
1607    
1608          MainSearch16FuncPtr MainSearchPtr;          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
1609    
1610          if (oldMBs == NULL) {          const int32_t TRB = time_pp - time_bp;
1611                  oldMBs = (MACROBLOCK *) calloc(iWcount * iHcount, sizeof(MACROBLOCK));          const int32_t TRD = time_pp;
 //      fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));  
         }  
         oldMB = oldMBs + x + y * iWcount;  
1612    
1613  /* Get maximum range */  // some pre-inintialized data for the rest of the search
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
1614    
1615          if (!(MotionFlags & PMV_HALFPEL16)) {          SearchData Data;
1616                  min_dx = EVEN(min_dx);          int32_t iMinSAD;
1617                  max_dx = EVEN(max_dx);          VECTOR currentMV[3];
1618                  min_dy = EVEN(min_dy);          Data.iEdgedWidth = pParam->edged_width;
1619                  max_dy = EVEN(max_dy);          Data.currentMV = currentMV;
1620          }          Data.iMinSAD = &iMinSAD;
1621          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */          Data.lambda16 = lambda_vec16[frame->quant];
         //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.  
 */  
1622    
1623  // Prepare for main loop          // note: i==horizontal, j==vertical
1624    
1625          currMV->x = start_x;          for (j = 0; j < pParam->mb_height; j++) {
         currMV->y = start_y;  
1626    
1627          if (!(MotionFlags & PMV_HALFPEL16)) {                  f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
                 currMV->x = EVEN(currMV->x);  
                 currMV->y = EVEN(currMV->y);  
         }  
1628    
1629          if (currMV->x > max_dx)                  for (i = 0; i < pParam->mb_width; i++) {
1630                  currMV->x = max_dx;                          MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
1631          if (currMV->x < min_dx)                          const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
                 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 **************/  
1632    
1633  // previous frame MV  /* special case, if collocated block is SKIPed: encoding is forward (0,0), cpb=0 without further ado */
1634          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);                          if (b_mb->mode == MODE_NOT_CODED) {
1635                                    pMB->mode = MODE_NOT_CODED;
1636                                    continue;
1637                            }
1638    
1639  // set threshhold based on Min of Prediction and SAD of collocated block                          Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
1640  // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want                          pMB->quant = frame->quant;
1641    /* direct search comes first, because it (1) checks for SKIP-mode
1642            and (2) sets very good predictions for forward and backward search */
1643    
1644                            skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
1645                                                                            b_ref, b_refH->y, b_refV->y, b_refHV->y,
1646                                                                            &frame->image,
1647                                                                            i, j,
1648                                                                            frame->motion_flags,
1649                                                                            TRB, TRD,
1650                                                                            pParam,
1651                                                                            pMB, b_mb,
1652                                                                            &best_sad,
1653                                                                            &Data);
1654    
1655          if ((x == 0) && (y == 0)) {                          if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
                 thresh2 = 512;  
         } else {  
 /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */  
1656    
1657                  thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;  //                      best_sad = 256*4096; //uncomment to disable Directsearch.
1658          }  //      To disable any other mode, just comment the function call
1659    
1660  // MV=(0,0) is often a good choice                          // forward search
1661                            SearchBF(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
1662                                                    &frame->image, i, j,
1663                                                    frame->motion_flags,
1664                                                    frame->fcode, pParam,
1665                                                    pMB, &f_predMV, &best_sad,
1666                                                    MODE_FORWARD, &Data);
1667    
1668          CHECK_MV16_ZERO;                          // backward search
1669                            SearchBF(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
1670                                                    &frame->image, i, j,
1671                                                    frame->motion_flags,
1672                                                    frame->bcode, pParam,
1673                                                    pMB, &b_predMV, &best_sad,
1674                                                    MODE_BACKWARD, &Data);
1675    
1676                            // interpolate search comes last, because it uses data from forward and backward as prediction
1677    
1678  // left neighbour, if allowed                          SearchInterpolate(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
1679          if (x != 0) {                                                  b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
1680                  if (!(MotionFlags & PMV_HALFPEL16)) {                                                  &frame->image,
1681                          pmv[1].x = EVEN(pmv[1].x);                                                  i, j,
1682                          pmv[1].y = EVEN(pmv[1].y);                                                  frame->fcode, frame->bcode,
1683                  }                                                  frame->motion_flags,
1684                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);                                                  pParam,
1685          }                                                  &f_predMV, &b_predMV,
1686  // top neighbour, if allowed                                                  pMB, &best_sad,
1687          if (y != 0) {                                                  &Data);
                 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);  
1688    
1689  // top right neighbour, if allowed                          switch (pMB->mode) {
1690                  if ((uint32_t) x != (iWcount - 1)) {                                  case MODE_FORWARD:
1691                          if (!(MotionFlags & PMV_HALFPEL16)) {                                          f_count++;
1692                                  pmv[3].x = EVEN(pmv[3].x);                                          f_predMV = pMB->mvs[0];
1693                                  pmv[3].y = EVEN(pmv[3].y);                                          break;
1694                                    case MODE_BACKWARD:
1695                                            b_count++;
1696                                            b_predMV = pMB->b_mvs[0];
1697                                            break;
1698                                    case MODE_INTERPOLATE:
1699                                            i_count++;
1700                                            f_predMV = pMB->mvs[0];
1701                                            b_predMV = pMB->b_mvs[0];
1702                                            break;
1703                                    case MODE_DIRECT:
1704                                    case MODE_DIRECT_NO4V:
1705                                            d_count++;
1706                                            break;
1707                                    default:
1708                                            break;
1709                          }                          }
                         CHECK_MV16_CANDIDATE(pmv[3].x, pmv[3].y);  
1710                  }                  }
1711          }          }
1712    
1713  /* Terminate if MinSAD <= T_2  //      fprintf(debug,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d, N: %04d\n",
1714     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  //                              f_count,b_count,i_count,d_count,n_count);
 */  
1715    
         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;  
1716          }          }
1717    
1718  /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/  /* Hinted ME starts here */
   
         backupMV = prevMB->mvs[0];      // collocated MV  
         backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x);     // acceleration X  
         backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y);     // acceleration Y  
1719    
1720          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y);  static void
1721    Search8hinted(const SearchData * const OldData,
1722  // left neighbour                          const int x, const int y,
1723          if (x != 0)                          const uint32_t MotionFlags,
1724                  CHECK_MV16_CANDIDATE((prevMB - 1)->mvs[0].x, (prevMB - 1)->mvs[0].y);                          const MBParam * const pParam,
1725                            MACROBLOCK * const pMB,
1726  // top neighbour                          const MACROBLOCK * const pMBs,
1727          if (y != 0)                          const int block,
1728                  CHECK_MV16_CANDIDATE((prevMB - iWcount)->mvs[0].x,                          SearchData * const Data)
1729                                                           (prevMB - iWcount)->mvs[0].y);  {
1730            int32_t temp_sad;
1731  // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs          MainSearchFunc *MainSearchPtr;
1732            Data->iMinSAD = OldData->iMinSAD + 1 + block;
1733          if ((uint32_t) x != iWcount - 1)          Data->currentMV = OldData->currentMV + 1 + block;
1734                  CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);          Data->currentQMV = OldData->currentQMV + 1 + block;
1735            Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2 , y/2, block);
1736    
1737            if(pParam->m_quarterpel) {
1738                    Data->predQMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2 , y/2, block);
1739                    if (block != 0) *(Data->iMinSAD) += Data->lambda8 *
1740                                                                            d_mv_bits(      Data->currentQMV->x - Data->predQMV.x,
1741                                                                                                    Data->currentQMV->y - Data->predQMV.y,
1742                                                                                                    Data->iFcode);
1743                    CheckCandidate = CheckCandidate8Q;
1744            } else {
1745                    if (block != 0) *(Data->iMinSAD) += Data->lambda8 *
1746                                                                            d_mv_bits(      Data->currentMV->x - Data->predMV.x,
1747                                                                                                    Data->currentMV->y - Data->predMV.y,
1748                                                                                                    Data->iFcode);
1749                    CheckCandidate = CheckCandidate8;
1750            }
1751    
1752  // bottom neighbour, dito          Data->Ref = OldData->Ref + 8 * ((block&1) + pParam->edged_width*(block>>1));
1753          if ((uint32_t) y != iHcount - 1)          Data->RefH = OldData->RefH + 8 * ((block&1) + pParam->edged_width*(block>>1));
1754                  CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,          Data->RefV = OldData->RefV + 8 * ((block&1) + pParam->edged_width*(block>>1));
1755                                                           (prevMB + iWcount)->mvs[0].y);          Data->RefHV = OldData->RefHV + 8 * ((block&1) + pParam->edged_width*(block>>1));
1756    
1757  /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */          Data->Cur = OldData->Cur + 8 * ((block&1) + pParam->edged_width*(block>>1));
         if (iMinSAD <= thresh2) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
         }  
1758    
1759  /************ (if Diamond Search)  **************/          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1760                                    pParam->width, pParam->height, OldData->iFcode, pParam->m_quarterpel);
1761    
1762          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          temp_sad = *(Data->iMinSAD); // store current MinSAD
1763    
1764          if (MotionFlags & PMV_USESQUARES16)          if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
1765                  MainSearchPtr = Square16_MainSearch;                  else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1766          else                          else MainSearchPtr = DiamondSearch;
          if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
1767    
1768  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);
1769    
1770          iSAD =          if(*(Data->iMinSAD) < temp_sad) {
1771                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,                  Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1772                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,                  Data->currentQMV->y = 2 * Data->currentMV->y;
                                                   min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);  
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
1773          }          }
1774    
1775            if (MotionFlags & PMV_HALFPELREFINE8) {
1776                    temp_sad = *(Data->iMinSAD); // store current MinSAD
1777    
1778          if (MotionFlags & PMV_EXTSEARCH16) {                  HalfpelRefine(Data); // perform halfpel refine of current best vector
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
1779    
1780                  if (!(MVequal(pmv[0], backupMV))) {                  if(*(Data->iMinSAD) < temp_sad) { // we have found a better match
1781                          iSAD =                          Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1782                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                          Data->currentQMV->y = 2 * Data->currentMV->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);  
1783                  }                  }
   
                 if (iSAD < iMinSAD) {  
                         *currMV = newMV;  
                         iMinSAD = iSAD;  
1784                  }                  }
1785    
1786                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          if(pParam->m_quarterpel) {
1787                          iSAD =                  if((!(Data->currentQMV->x & 1)) && (!(Data->currentQMV->y & 1)) &&
1788                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                          (MotionFlags & PMV_QUARTERPELREFINE8)) {
1789                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,                          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1790                                                                    max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);                                  pParam->width, pParam->height, Data->iFcode, 0);
1791                            CheckCandidate = CheckCandidate8_qpel;
1792                          if (iSAD < iMinSAD) {                          QuarterpelRefine(Data);
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
1793                  }                  }
1794            pMB->pmvs[block].x = Data->currentQMV->x - Data->predQMV.x;
1795            pMB->pmvs[block].y = Data->currentQMV->y - Data->predQMV.y;
1796            } else {
1797                    pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1798                    pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
1799          }          }
1800    
1801  /***************        Choose best MV found     **************/          pMB->mvs[block] = *(Data->currentMV);
1802            pMB->qmvs[block] = *(Data->currentQMV);
1803    
1804    EPZS16_Terminate_with_Refine:          pMB->sad8[block] =  4 * (*Data->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);  
   
   EPZS16_Terminate_without_Refine:  
   
         *oldMB = *prevMB;  
   
         currPMV->x = currMV->x - center_x;  
         currPMV->y = currMV->y - center_y;  
         return iMinSAD;  
1805  }  }
1806    
1807    static void
1808  int32_t  SearchPhinted ( const uint8_t * const pRef,
 EPZSSearch8(const uint8_t * const pRef,  
1809                          const uint8_t * const pRefH,                          const uint8_t * const pRefH,
1810                          const uint8_t * const pRefV,                          const uint8_t * const pRefV,
1811                          const uint8_t * const pRefHV,                          const uint8_t * const pRefHV,
1812                          const IMAGE * const pCur,                          const IMAGE * const pCur,
1813                          const int x,                          const int x,
1814                          const int y,                          const int y,
                         const int start_x,  
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
1815                          const uint32_t MotionFlags,                          const uint32_t MotionFlags,
1816                          const uint32_t iQuant,                          const uint32_t iQuant,
                         const uint32_t iFcode,  
1817                          const MBParam * const pParam,                          const MBParam * const pParam,
1818                          const MACROBLOCK * const pMBs,                          const MACROBLOCK * const pMBs,
1819                          const MACROBLOCK * const prevMBs,                                  int inter4v,
1820                          VECTOR * const currMV,                                  MACROBLOCK * const pMB,
1821                          VECTOR * const currPMV)                                  SearchData * const Data)
1822  {  {
 /* Please not that EPZS might not be a good choice for 8x8-block motion search ! */  
1823    
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
1824          const int32_t iEdgedWidth = pParam->edged_width;          const int32_t iEdgedWidth = pParam->edged_width;
1825    
1826          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;          int i, t;
1827            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;  
1828    
1829          VECTOR pmv[4];          Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1830          int32_t psad[8];          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1831                                    pParam->width, pParam->height, Data->iFcode, pParam->m_quarterpel);
1832    
1833            Data->Cur = pCur->y + (x + y * iEdgedWidth) * 16;
1834            Data->Ref = pRef + (x + iEdgedWidth*y)*16;
1835            Data->RefH = pRefH + (x + iEdgedWidth*y) * 16;
1836            Data->RefV = pRefV + (x + iEdgedWidth*y) * 16;
1837            Data->RefHV = pRefHV + (x + iEdgedWidth*y) * 16;
1838            Data->lambda16 = lambda_vec16[iQuant];
1839            Data->lambda8 = lambda_vec8[iQuant];
1840    
1841          const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);          if (!(MotionFlags & PMV_HALFPEL16)) {
1842                    Data->min_dx = EVEN(Data->min_dx);
1843  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;                  Data->max_dx = EVEN(Data->max_dx);
1844          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;                  Data->min_dy = EVEN(Data->min_dy);
1845                    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);  
1846          }          }
         /* 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);  
1847    
1848            for(i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;
1849    
1850  /* 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  
1851    
1852            if(pParam->m_quarterpel) CheckCandidate = CheckCandidate16Q;
1853            else
1854                    if (inter4v) CheckCandidate = CheckCandidate16;
1855                    else CheckCandidate = CheckCandidate16no4v;
1856    
1857          if (!(MotionFlags & PMV_HALFPEL8)) {          pMB->mvs[0].x = EVEN(pMB->mvs[0].x);
1858                  currMV->x = EVEN(currMV->x);          pMB->mvs[0].y = EVEN(pMB->mvs[0].y);
1859                  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
1860            if (pMB->mvs[0].x < Data->min_dx) pMB->mvs[0].x = Data->min_dx;
1861            if (pMB->mvs[0].y > Data->max_dy) pMB->mvs[0].y = Data->max_dy;
1862            if (pMB->mvs[0].y < Data->min_dy) pMB->mvs[0].y = Data->min_dy;
1863    
1864            (*CheckCandidate)(pMB->mvs[0].x, pMB->mvs[0].y, 0, &t, Data);
1865    
1866            if (pMB->mode == MODE_INTER4V)
1867                    for (i = 1; i < 4; i++) { // all four vectors will be used as four predictions for 16x16 search
1868                            pMB->mvs[i].x = EVEN(pMB->mvs[i].x);
1869                            pMB->mvs[i].y = EVEN(pMB->mvs[i].y);
1870                            if (!(make_mask(pMB->mvs, i)))
1871                                    (*CheckCandidate)(pMB->mvs[i].x, pMB->mvs[i].y, 0, &t, Data);
1872          }          }
1873    
1874          if (currMV->x > max_dx)          if (MotionFlags & PMV_USESQUARES16)
1875                  currMV->x = max_dx;                  MainSearchPtr = SquareSearch;
1876          if (currMV->x < min_dx)          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
1877                  currMV->x = min_dx;                  MainSearchPtr = AdvDiamondSearch;
1878          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 ******************/  
   
1879    
1880          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);  
1881    
1882            if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(Data);
1883    
1884  // thresh1 is fixed to 256          for(i = 0; i < 5; i++) {
1885          if (iMinSAD < 256 / 4) {                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // initialize qpel vectors
1886                  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;  
1887          }          }
1888    
1889  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/          if((pParam->m_quarterpel) && (MotionFlags & PMV_QUARTERPELREFINE16)) {
1890                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1891                                    pParam->width, pParam->height, Data->iFcode, 0);
1892  // MV=(0,0) is often a good choice                  CheckCandidate = CheckCandidate16_qpel;
1893          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);  
         }  
 // 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);  
1894                  }                  }
                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
1895    
1896  // top right neighbour, if allowed          if (inter4v) {
1897                  if (psad[3] != MV_MAX_ERROR) {                  SearchData Data8;
1898                          if (!(MotionFlags & PMV_HALFPEL8)) {                  Data8.iFcode = Data->iFcode;
1899                                  pmv[3].x = EVEN(pmv[3].x);                  Data8.lambda8 = Data->lambda8;
1900                                  pmv[3].y = EVEN(pmv[3].y);                  Data8.iEdgedWidth = Data->iEdgedWidth;
1901                    Data8.RefQ = Data->RefQ;
1902                    Search8hinted(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
1903                    Search8hinted(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
1904                    Search8hinted(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
1905                    Search8hinted(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
1906                          }                          }
                         CHECK_MV8_CANDIDATE(pmv[3].x, pmv[3].y);  
                 }  
         }  
   
 /*  // this bias is zero anyway, at the moment!  
1907    
1908          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)          if (!(inter4v) ||
1909                  iMinSAD -= MV8_00_BIAS;                  (Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] + Data->iMinSAD[3] +
1910                                                            Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {
1911    // INTER MODE
1912                    pMB->mode = MODE_INTER;
1913                    pMB->mvs[0] = pMB->mvs[1]
1914                            = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
1915    
1916  */                  pMB->qmvs[0] = pMB->qmvs[1]
1917                            = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1918    
1919  /* Terminate if MinSAD <= T_2                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
1920     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]                          pMB->sad8[2] = pMB->sad8[3] =  Data->iMinSAD[0];
 */  
1921    
1922          if (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */                  if(pParam->m_quarterpel) {
1923                  if (MotionFlags & PMV_QUICKSTOP8)                          pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predQMV.x;
1924                          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;  
1925          }          }
1926                    else {
1927  /************ (Diamond Search)  **************/                          pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1928                            pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
1929          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                  }
1930            } else {
1931          if (!(MotionFlags & PMV_HALFPELDIAMOND8))  // INTER4V MODE; all other things are already set in Search8hinted
1932                  iDiamondSize *= 2;                  pMB->mode = MODE_INTER4V;
1933                    pMB->sad16 = Data->iMinSAD[1] + Data->iMinSAD[2] + Data->iMinSAD[3]
1934  /* 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;  
1935          }          }
1936    
1937          if (MotionFlags & PMV_EXTSEARCH8) {  }
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
1938    
1939                  if (!(MVequal(pmv[0], backupMV))) {  void
1940                          iSAD =  MotionEstimationHinted( MBParam * const pParam,
1941                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                                  FRAMEINFO * const current,
1942                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,                                                  FRAMEINFO * const reference,
1943                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,                                                  const IMAGE * const pRefH,
1944                                                                    iDiamondSize, iFcode, iQuant, 0);                                                  const IMAGE * const pRefV,
1945                                                    const IMAGE * const pRefHV)
1946    {
1947            MACROBLOCK *const pMBs = current->mbs;
1948            const IMAGE *const pCurrent = &current->image;
1949            const IMAGE *const pRef = &reference->image;
1950    
1951                          if (iSAD < iMinSAD) {          uint32_t x, y;
1952                                  *currMV = newMV;          uint8_t * qimage;
1953                                  iMinSAD = iSAD;          int32_t temp[5], quant = current->quant;
1954            int32_t iMinSAD[5];
1955            VECTOR currentMV[5], currentQMV[5];
1956            SearchData Data;
1957            Data.iEdgedWidth = pParam->edged_width;
1958            Data.currentMV = currentMV;
1959            Data.currentQMV = currentQMV;
1960            Data.iMinSAD = iMinSAD;
1961            Data.temp = temp;
1962            Data.iFcode = current->fcode;
1963            Data.rounding = pParam->m_rounding_type;
1964    
1965            if((qimage = (uint8_t *) malloc(32 * pParam->edged_width)) == NULL)
1966                    return; // allocate some mem for qpel interpolated blocks
1967                                      // somehow this is dirty since I think we shouldn't use malloc outside
1968                                      // encoder_create() - so please fix me!
1969    
1970            Data.RefQ = qimage;
1971    
1972            if (sadInit) (*sadInit) ();
1973    
1974            for (y = 0; y < pParam->mb_height; y++) {
1975                    for (x = 0; x < pParam->mb_width; x++)  {
1976    
1977                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1978    
1979    //intra mode is copied from the first pass. At least for the time being
1980                            if  ((pMB->mode == MODE_INTRA) || (pMB->mode == MODE_NOT_CODED) ) continue;
1981    
1982    
1983                            if (!(current->global_flags & XVID_LUMIMASKING)) {
1984                                    pMB->dquant = NO_CHANGE;
1985                                    pMB->quant = current->quant; }
1986                            else {
1987                                    if (pMB->dquant != NO_CHANGE) {
1988                                            quant += DQtab[pMB->dquant];
1989                                            if (quant > 31) quant = 31;
1990                                            else if (quant < 1) quant = 1;
1991                          }                          }
1992                                    pMB->quant = quant;
1993                  }                  }
1994    
1995                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                          SearchPhinted(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1996                          iSAD =                                                          y, current->motion_flags, pMB->quant,
1997                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                                                          pParam, pMBs, current->global_flags & XVID_INTER4V, pMB,
1998                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,                                                          &Data);
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, 0);  
1999    
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
2000                          }                          }
2001                  }                  }
2002            free(qimage);
2003          }          }
2004    
2005  /***************        Choose best MV found     **************/  static __inline int
2006    MEanalyzeMB (   const uint8_t * const pRef,
2007    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,  
2008                                  const int x,                                  const int x,
2009                                  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,  
2010                                  const MBParam * const pParam,                                  const MBParam * const pParam,
2011                                  const MACROBLOCK * const pMBs,                                  const MACROBLOCK * const pMBs,
2012                                  const MACROBLOCK * const prevMBs,                                  MACROBLOCK * const pMB,
2013                                  VECTOR * const currMV,                                  SearchData * const Data)
                                 VECTOR * const currPMV)  
 {  
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
   
         const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;  
         const VECTOR zeroMV = { 0, 0 };  
   
         int32_t iDiamondSize;  
   
         int32_t min_dx;  
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
   
         int32_t iFound;  
   
         VECTOR newMV;  
         VECTOR backupMV;  
   
         VECTOR pmv[4];  
         int32_t psad[4];  
   
         MainSearch16FuncPtr MainSearchPtr;  
   
         const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;  
         MACROBLOCK *const pMB = pMBs + x + y * iWcount;  
   
         int32_t threshA, threshB;  
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD;  
   
   
 /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
   
 /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  
   
         if ((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);  
         }  
   
         iMinSAD =  
                 sad16(cur,  
                           get_iref_mv(pRef, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->i_mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->i_sad16))) {  
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
2014                  {                  {
                         if (!MVzero(*currMV)) {  
                                 iMinSAD += MV16_00_BIAS;  
                                 CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures  
                                 iMinSAD -= MV16_00_BIAS;  
                         }  
                 }  
2015    
2016                  if (MotionFlags & PMV_EARLYSTOP16)          int i = 255, mask;
2017                          goto PMVfastInt16_Terminate_with_Refine;          VECTOR pmv[3];
         }  
2018    
2019            *(Data->iMinSAD) = MV_MAX_ERROR;
2020            Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
2021            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
2022                                    pParam->width, pParam->height, Data->iFcode, pParam->m_quarterpel);
2023    
2024  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion          Data->Cur = pCur + (x + y * pParam->edged_width) * 16;
2025     vector of the median.          Data->Ref = pRef + (x + y * pParam->edged_width) * 16;
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
2026    
2027          if ((bPredEq) && (MVequal(pmv[0], prevMB->i_mvs[0])))          CheckCandidate = CheckCandidate16no4vI;
                 iFound = 2;  
2028    
2029  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          pmv[1].x = EVEN(pMB->mvs[0].x);
2030     Otherwise select large Diamond Search.          pmv[1].y = EVEN(pMB->mvs[0].y);
2031  */          pmv[0].x = EVEN(Data->predMV.x);
2032            pmv[0].y = EVEN(Data->predMV.y);
2033            pmv[2].x = pmv[2].y = 0;
2034    
2035          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))          CheckCandidate16no4vI(pmv[0].x, pmv[0].y, 255, &i, Data);
2036                  iDiamondSize = 2;               // halfpel units!          if (!(mask = make_mask(pmv, 1)))
2037          else                  CheckCandidate16no4vI(pmv[1].x, pmv[1].y, mask, &i, Data);
2038                  iDiamondSize = 4;               // halfpel units!          if (!(mask = make_mask(pmv, 2)))
2039                    CheckCandidate16no4vI(0, 0, mask, &i, Data);
 /*  
    Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  
    Also calculate (0,0) but do not subtract offset.  
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset.  
 */  
   
 // (0,0) is often a good choice  
   
         if (!MVzero(pmv[0]))  
                 CHECK_MV16_ZERO;  
   
 // previous frame MV is always possible  
   
         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 */  
   
   
 /* 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);  
2040    
2041          if (iSAD < iMinSAD) {          DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, i);
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
   
         if (MotionFlags & PMV_EXTSEARCH16) {  
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
2042    
2043                  if (!(MVequal(pmv[0], backupMV))) {          pMB->mvs[0] = *Data->currentMV;
                         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);  
2044    
2045                          if (iSAD < iMinSAD) {          return *(Data->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;  
                         }  
                 }  
2046          }          }
2047    
2048  /*  #define INTRA_THRESH    1350
2049     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  #define INTER_THRESH    900
 */  
2050    
2051  PMVfastInt16_Terminate_with_Refine:  int
2052    MEanalysis(     const IMAGE * const pRef,
2053          pMB->i_mvs[0] = pMB->i_mvs[1] = pMB->i_mvs[2] = pMB->i_mvs[3] = pMB->i_mv16 = *currMV;                          const IMAGE * const pCurrent,
2054          pMB->i_sad8[0] = pMB->i_sad8[1] = pMB->i_sad8[2] = pMB->i_sad8[3] = pMB->i_sad16 = iMinSAD;                          MBParam * const pParam,
2055                            MACROBLOCK * const pMBs,
2056          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step                          const uint32_t iFcode)
                 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;  
 }  
   
   
   
 /* ***********************************************************  
         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)  
2057  {  {
2058          const int mb_width = pParam->mb_width;          uint32_t x, y, intra = 0;
2059          const int mb_height = pParam->mb_height;          int sSAD = 0;
         const int edged_width = pParam->edged_width;  
   
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
   
         int i, j, k;  
   
         static const VECTOR zeroMV={0,0};  
   
         int f_sad16;    /* forward (as usual) search */  
         int b_sad16;    /* backward (only in b-frames) search */  
         int i_sad16;    /* interpolated (both direction, b-frames only) */  
         int d_sad16;    /* direct mode (assume almost linear motion) */  
   
         int best_sad;  
   
         VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/  
         VECTOR f_interpolMV, b_interpolMV;  
         VECTOR pmv_dontcare;  
2060    
2061          int min_dx, max_dx, min_dy, max_dy;          VECTOR currentMV;
2062          int f_min_dx, f_max_dx, f_min_dy, f_max_dy;          int32_t iMinSAD;
2063          int b_min_dx, b_max_dx, b_min_dy, b_max_dy;          SearchData Data;
2064            Data.iEdgedWidth = pParam->edged_width;
2065          int f_count=0;          Data.currentMV = &currentMV;
2066          int b_count=0;          Data.iMinSAD = &iMinSAD;
2067          int i_count=0;          Data.iFcode = iFcode;
2068          int d_count=0;  
2069            if (sadInit) (*sadInit) ();
2070    
2071            for (y = 1; y < pParam->mb_height-1; y++) {
2072                    for (x = 1; x < pParam->mb_width-1; x++) {
2073                            int sad, dev;
2074                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
2075    
2076          const int64_t TRB = (int32_t)time_pp - (int32_t)time_bp;                          sad = MEanalyzeMB(pRef->y, pCurrent->y, x, y,
2077      const int64_t TRD = (int32_t)time_pp;                                                                  pParam, pMBs, pMB, &Data);
2078    
2079          // fprintf(stderr,"TRB = %lld  TRD = %lld  time_bp =%d time_pp =%d\n\n",TRB,TRD,time_bp,time_pp);                          if (sad > INTRA_THRESH) {
2080          // note: i==horizontal, j==vertical                                  dev = dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,
2081          for (j = 0; j < mb_height; j++) {                                                            pParam->edged_width);
2082                                    if (dev + INTRA_THRESH < sad) intra++;
2083                  f_predMV = zeroMV;      /* prediction is reset at left boundary */                                  if (intra > (pParam->mb_height-2)*(pParam->mb_width-2)/2) return 2;  // I frame
                 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;  
2084                          }                          }
2085                            sSAD += sad;
                         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);  
2086                                  }                                  }
2087                          }                          }
2088                          else          sSAD /= (pParam->mb_height-2)*(pParam->mb_width-2);
2089                          {          if (sSAD > INTER_THRESH ) return 1; //P frame
2090                                  mb->directmv[3] = mb->directmv[2] = mb->directmv[1] =          emms();
2091                                          mb->directmv[0] = b_mb->mvs[0];          return 0; // B frame
   
                                 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);  
2092    
2093              }              }
                     d_sad16 += calc_delta_16(mb->deltamv.x, mb->deltamv.y, 1, frame->quant);  
2094    
2095                          // forward search  int
2096                          f_sad16 = SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  FindFcode(      const MBParam * const pParam,
2097                                                  &frame->image, i, j,                          const FRAMEINFO * const current)
                                                 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);  
   
   
                         // backward search  
                         b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 &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;  
                         }  
   
                         if (d_sad16 < best_sad) {  
   
                                 if (b_mb->mode == MODE_INTER4V)  
                                 {  
   
                                 /* how to calc vectors is defined in standard. mvs[] and b_mvs[] are only for motion compensation */  
                                 /* for the bitstream, the value mb->deltamv is read directly */  
   
                             for (k = 0; k < 4; 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);  
                                         }  
                                 }  
                                 else  
2098                                  {                                  {
2099                                          mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);          uint32_t x, y;
2100            int max = 0, min = 0, i;
                     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->deltamv.y == 0)  
                                                                                 ? ((TRB - TRD) * mb->directmv[0].y) / TRD  
                                             : mb->mvs[0].y - mb->directmv[0].y);  
   
                                         mb->mvs[3] = mb->mvs[2] = mb->mvs[1] = mb->mvs[0];  
                                         mb->b_mvs[3] = mb->b_mvs[2] = mb->b_mvs[1] = mb->b_mvs[0];  
                 }  
2101    
2102                                  best_sad = d_sad16;          for (y = 0; y < pParam->mb_height; y++) {
2103                                  mb->mode = MODE_DIRECT;                  for (x = 0; x < pParam->mb_width; x++) {
                         }  
2104    
2105                          switch (mb->mode)                          MACROBLOCK *pMB = &current->mbs[x + y * pParam->mb_width];
2106                          {                          for(i = 0; i < (pMB->mode == MODE_INTER4V ? 4:1); i++) {
2107                                  case MODE_FORWARD:                                  if (pMB->mvs[i].x > max) max = pMB->mvs[i].x;
2108                                          f_count++;                                  if (pMB->mvs[i].y > max) max = pMB->mvs[i].y;
                                         f_predMV = mb->mvs[0];  
                                         break;  
                                 case MODE_BACKWARD:  
                                         b_count++;  
                                         b_predMV = mb->b_mvs[0];  
2109    
2110                                          break;                                  if (pMB->mvs[i].x < min) min = pMB->mvs[i].x;
2111                                  case MODE_INTERPOLATE:                                  if (pMB->mvs[i].y < min) min = pMB->mvs[i].y;
                                         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;  
2112                          }                          }
   
2113                  }                  }
2114          }          }
2115    
2116  #ifdef _DEBUG_BFRAME_STAT          min = -min;
2117          fprintf(stderr,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d\n",          max += 1;
2118                                  f_count,b_count,i_count,d_count);          if (min > max) max = min;
2119  #endif          if (pParam->m_quarterpel) max *= 2;
2120    
2121            for (i = 1; (max > 32 << (i - 1)); i++);
2122            return i;
2123  }  }

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

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