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

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

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