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

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

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