[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.2.8, Sat Oct 12 13:56:16 2002 UTC revision 1.46, Sat Sep 7 09:12:22 2002 UTC
# Line 1  Line 1 
1  /**************************************************************************  /*****************************************************************************
2   *   *
3   *      XVID MPEG-4 VIDEO CODEC   *      XVID MPEG-4 VIDEO CODEC
4   *      motion estimation   *  - Motion Estimation module -
5     *
6     *  Copyright(C) 2002 Christoph Lampert <gruel@web.de>
7     *  Copyright(C) 2002 Michael Militzer <michael@xvid.org>
8     *  Copyright(C) 2002 Edouard Gomez <ed.gomez@wanadoo.fr>
9   *   *
10   *      This program is an implementation of a part of one or more MPEG-4   *      This program is an implementation of a part of one or more MPEG-4
11   *      Video tools as specified in ISO/IEC 14496-2 standard.  Those intending   *      Video tools as specified in ISO/IEC 14496-2 standard.  Those intending
# Line 24  Line 28 
28   *   *
29   *      You should have received a copy of the GNU General Public License   *      You should have received a copy of the GNU General Public License
30   *      along with this program; if not, write to the Free Software   *      along with this program; if not, write to the Free Software
31   *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
32   *   *
33   *************************************************************************/   *************************************************************************/
34    
# Line 37  Line 41 
41  #include "../prediction/mbprediction.h"  #include "../prediction/mbprediction.h"
42  #include "../global.h"  #include "../global.h"
43  #include "../utils/timer.h"  #include "../utils/timer.h"
 #include "../image/interpolate8x8.h"  
 #include "motion_est.h"  
44  #include "motion.h"  #include "motion.h"
45  #include "sad.h"  #include "sad.h"
 #include "../utils/emms.h"  
46    
 #define INITIAL_SKIP_THRESH     (10)  
 #define FINAL_SKIP_THRESH       (50)  
 #define MAX_SAD00_FOR_SKIP      (20)  
 #define MAX_CHROMA_SAD_FOR_SKIP (22)  
 #define SKIP_THRESH_B (25)  
47    
 #define CHECK_CANDIDATE(X,Y,D) { \  
 (*CheckCandidate)((const int)(X),(const int)(Y), (D), &iDirection, data ); }  
48    
49  #define GET_REFERENCE(X, Y, REF) { \  static int32_t lambda_vec16[32] =       /* rounded values for lambda param for weight of motion bits as in modified H.26L */
50          switch ( ((X&1)<<1) + (Y&1) ) \  { 0, (int) (1.00235 + 0.5), (int) (1.15582 + 0.5), (int) (1.31976 + 0.5),
51          { \                  (int) (1.49591 + 0.5), (int) (1.68601 + 0.5),
52                  case 0 : REF = data->Ref + (X)/2 + ((Y)/2)*(data->iEdgedWidth); break; \          (int) (1.89187 + 0.5), (int) (2.11542 + 0.5), (int) (2.35878 + 0.5),
53                  case 1 : REF = data->RefV + (X)/2 + (((Y)-1)/2)*(data->iEdgedWidth); break; \                  (int) (2.62429 + 0.5), (int) (2.91455 + 0.5),
54                  case 2 : REF = data->RefH + ((X)-1)/2 + ((Y)/2)*(data->iEdgedWidth); break; \          (int) (3.23253 + 0.5), (int) (3.58158 + 0.5), (int) (3.96555 + 0.5),
55                  default : REF = data->RefHV + ((X)-1)/2 + (((Y)-1)/2)*(data->iEdgedWidth); break; \                  (int) (4.38887 + 0.5), (int) (4.85673 + 0.5),
56          } \          (int) (5.37519 + 0.5), (int) (5.95144 + 0.5), (int) (6.59408 + 0.5),
57  }                  (int) (7.31349 + 0.5), (int) (8.12242 + 0.5),
58            (int) (9.03669 + 0.5), (int) (10.0763 + 0.5), (int) (11.2669 + 0.5),
59                    (int) (12.6426 + 0.5), (int) (14.2493 + 0.5),
60            (int) (16.1512 + 0.5), (int) (18.442 + 0.5), (int) (21.2656 + 0.5),
61                    (int) (24.8580 + 0.5), (int) (29.6436 + 0.5),
62            (int) (36.4949 + 0.5)
63    };
64    
65    static int32_t *lambda_vec8 = lambda_vec16;     /* same table for INTER and INTER4V for now */
66    
67    
68    
69  #define iDiamondSize 2  // mv.length table
70    static const uint32_t mvtab[33] = {
71            1, 2, 3, 4, 6, 7, 7, 7,
72            9, 9, 9, 10, 10, 10, 10, 10,
73            10, 10, 10, 10, 10, 10, 10, 10,
74            10, 11, 11, 11, 11, 11, 11, 12, 12
75    };
76    
77  static __inline int  
78  d_mv_bits(int x, int y, const uint32_t iFcode)  static __inline uint32_t
79    mv_bits(int32_t component,
80                    const uint32_t iFcode)
81  {  {
82          int xb, yb;          if (component == 0)
83                    return 1;
84    
85          if (x == 0) xb = 1;          if (component < 0)
86          else {                  component = -component;
                 if (x < 0) x = -x;  
                 x += (1 << (iFcode - 1)) - 1;  
                 x >>= (iFcode - 1);  
                 if (x > 32) x = 32;  
                 xb = mvtab[x] + iFcode;  
         }  
87    
88          if (y == 0) yb = 1;          if (iFcode == 1) {
89          else {                  if (component > 32)
90                  if (y < 0) y = -y;                          component = 32;
91                  y += (1 << (iFcode - 1)) - 1;  
92                  y >>= (iFcode - 1);                  return mvtab[component] + 1;
                 if (y > 32) y = 32;  
                 yb = mvtab[y] + iFcode;  
         }  
         return xb + yb;  
93  }  }
94    
95            component += (1 << (iFcode - 1)) - 1;
96            component >>= (iFcode - 1);
97    
98  /* CHECK_CANDIATE FUNCTIONS START */          if (component > 32)
99                    component = 32;
100    
101  static void          return mvtab[component] + 1 + iFcode - 1;
102  CheckCandidate16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)  }
 {  
         int t;  
         const uint8_t * Reference;  
103    
         if (( x > data->max_dx) || ( x < data->min_dx)  
                 || ( y > data->max_dy) || (y < data->min_dy)) return;  
104    
105          switch ( ((x&1)<<1) + (y&1) ) {  static __inline uint32_t
106                  case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;  calc_delta_16(const int32_t dx,
107                  case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;                            const int32_t dy,
108                  case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;                            const uint32_t iFcode,
109                  default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;                            const uint32_t iQuant)
110    {
111            return NEIGH_TEND_16X16 * lambda_vec16[iQuant] * (mv_bits(dx, iFcode) +
112                                                                                                              mv_bits(dy, iFcode));
113          }          }
114    
115          data->temp[0] = sad16v(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);  static __inline uint32_t
116    calc_delta_8(const int32_t dx,
117                             const int32_t dy,
118                             const uint32_t iFcode,
119                             const uint32_t iQuant)
120    {
121            return NEIGH_TEND_8X8 * lambda_vec8[iQuant] * (mv_bits(dx, iFcode) +
122                                                                                                       mv_bits(dy, iFcode));
123    }
124    
125          t = d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);  bool
126          data->temp[0] += lambda_vec16[data->iQuant] * t;  MotionEstimation(MBParam * const pParam,
127          data->temp[1] += lambda_vec8[data->iQuant] * t;                                   FRAMEINFO * const current,
128                                     FRAMEINFO * const reference,
129                                     const IMAGE * const pRefH,
130                                     const IMAGE * const pRefV,
131                                     const IMAGE * const pRefHV,
132                                     const uint32_t iLimit)
133    {
134            const uint32_t iWcount = pParam->mb_width;
135            const uint32_t iHcount = pParam->mb_height;
136            MACROBLOCK *const pMBs = current->mbs;
137            MACROBLOCK *const prevMBs = reference->mbs;
138            const IMAGE *const pCurrent = &current->image;
139            const IMAGE *const pRef = &reference->image;
140    
141          if (data->temp[0] < data->iMinSAD[0]) {          static const VECTOR zeroMV = { 0, 0 };
142                  data->iMinSAD[0] = data->temp[0];          VECTOR predMV;
                 data->currentMV[0].x = x; data->currentMV[0].y = y;  
                 *dir = Direction; }  
143    
144          if (data->temp[1] < data->iMinSAD[1]) {          int32_t x, y;
145                  data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }          int32_t iIntra = 0;
146          if (data->temp[2] < data->iMinSAD[2]) {          VECTOR pmv;
                 data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }  
         if (data->temp[3] < data->iMinSAD[3]) {  
                 data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }  
         if (data->temp[4] < data->iMinSAD[4]) {  
                 data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }  
147    
148  }          if (sadInit)
149                    (*sadInit) ();
150    
151  static void          for (y = 0; y < iHcount; y++)   {
152  CheckCandidate16no4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)                  for (x = 0; x < iWcount; x ++)  {
 {  
         int32_t sad;  
         const uint8_t * Reference;  
153    
154          if (( x > data->max_dx) || ( x < data->min_dx)                          MACROBLOCK *const pMB = &pMBs[x + y * iWcount];
                 || ( y > data->max_dy) || (y < data->min_dy)) return;  
155    
156          switch ( ((x&1)<<1) + (y&1) )                          if (pMB->mode == MODE_NOT_CODED)
157          {                                  continue;
                 case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;  
                 case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;  
                 case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;  
                 default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;  
         }  
158    
159          sad = lambda_vec16[data->iQuant] *                          predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
                         d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);  
         sad += sad16(data->Cur, Reference, data->iEdgedWidth, MV_MAX_ERROR);  
160    
161          if (sad < *(data->iMinSAD)) {                          pMB->sad16 =
162                  *(data->iMinSAD) = sad;                                  SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,
163                  data->currentMV[0].x = x; data->currentMV[0].y = y;                                                   x, y, predMV.x, predMV.y, predMV.x, predMV.y,
164                  *dir = Direction; }                                                   current->motion_flags, current->quant,
165  }                                                   current->fcode, pParam, pMBs, prevMBs, &pMB->mv16,
166                                                     &pMB->pmvs[0]);
167    
168  static void                          if (0 < (pMB->sad16 - MV16_INTER_BIAS)) {
169  CheckCandidate16_qpel(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)                                  int32_t deviation;
170    
171  // CheckCandidate16 variant which expects x and y in quarter pixel resolution                                  deviation =
172  // Important: This is no general usable routine! x and y must be +/-1 (qpel resolution!)                                          dev16(pCurrent->y + x * 16 + y * 16 * pParam->edged_width,
173  // around currentMV!                                                    pParam->edged_width);
 {  
         int t;  
         uint8_t * Reference = (uint8_t *) data->RefQ;  
         const uint8_t *ref1, *ref2, *ref3, *ref4;  
         VECTOR halfpelMV = *(data->currentMV);  
174    
175          int32_t iEdgedWidth = data->iEdgedWidth;                                  if (deviation < (pMB->sad16 - MV16_INTER_BIAS)) {
176          uint32_t rounding = data->rounding;                                          pMB->mode = MODE_INTRA;
177                                            pMB->mv16 = pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =
178                                                    pMB->mvs[3] = zeroMV;
179                                            pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =
180                                                    pMB->sad8[3] = 0;
181    
182          if (( x > data->max_dx) || ( x < data->min_dx)                                          iIntra++;
183                  || ( y > data->max_dy) || (y < data->min_dy)) return;                                          if (iIntra >= iLimit)
184                                                    return 1;
185    
186          switch( ((x&1)<<1) + (y&1) )                                          continue;
187          {                                  }
188          case 0: // pure halfpel position - shouldn't happen during a refinement step                          }
                 GET_REFERENCE(halfpelMV.x, halfpelMV.y, (const uint8_t *) Reference);  
                 break;  
189    
190          case 1: // x halfpel, y qpel - top or bottom during qpel refinement                          pmv = pMB->pmvs[0];
191                  GET_REFERENCE(halfpelMV.x, halfpelMV.y, ref1);                          if (current->global_flags & XVID_INTER4V)
192                  GET_REFERENCE(halfpelMV.x, y - halfpelMV.y, ref2);                                  if ((!(current->global_flags & XVID_LUMIMASKING) ||
193                                             pMB->dquant == NO_CHANGE)) {
194                                            int32_t sad8 = IMV16X16 * current->quant;
195    
196                                            if (sad8 < pMB->sad16) {
197                                                    sad8 += pMB->sad8[0] =
198                                                            SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,
199                                                                            pCurrent, 2 * x, 2 * y,
200                                                                            pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,
201                                                                            current->motion_flags,
202                                                                            current->quant, current->fcode, pParam,
203                                                                            pMBs, prevMBs, &pMB->mvs[0],
204                                                                            &pMB->pmvs[0]);
205                                            }
206                                            if (sad8 < pMB->sad16) {
207    
208                                                    predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 1);
209                                                    sad8 += pMB->sad8[1] =
210                                                            SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,
211                                                                            pCurrent, 2 * x + 1, 2 * y,
212                                                                            pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,
213                                                                            current->motion_flags,
214                                                                            current->quant, current->fcode, pParam,
215                                                                            pMBs, prevMBs, &pMB->mvs[1],
216                                                                            &pMB->pmvs[1]);
217                                            }
218                                            if (sad8 < pMB->sad16) {
219                                                    predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 2);
220                                                    sad8 += pMB->sad8[2] =
221                                                            SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,
222                                                                            pCurrent, 2 * x, 2 * y + 1,
223                                                                            pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,
224                                                                            current->motion_flags,
225                                                                            current->quant, current->fcode, pParam,
226                                                                            pMBs, prevMBs, &pMB->mvs[2],
227                                                                            &pMB->pmvs[2]);
228                                            }
229                                            if (sad8 < pMB->sad16) {
230                                                    predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 3);
231                                                    sad8 += pMB->sad8[3] =
232                                                            SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,
233                                                                            pCurrent, 2 * x + 1, 2 * y + 1,
234                                                                            pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,
235                                                                            current->motion_flags,
236                                                                            current->quant, current->fcode, pParam,
237                                                                            pMBs, prevMBs,
238                                                                            &pMB->mvs[3],
239                                                                            &pMB->pmvs[3]);
240                                            }
241    
242                                            /* decide: MODE_INTER or MODE_INTER4V
243                                               mpeg4:   if (sad8 < pMB->sad16 - nb/2+1) use_inter4v
244                                             */
245    
246                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding);                                          if (sad8 < pMB->sad16) {
247                  interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding);                                                  pMB->mode = MODE_INTER4V;
248                  interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding);                                                  pMB->sad8[0] *= 4;
249                  interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding);                                                  pMB->sad8[1] *= 4;
250                  break;                                                  pMB->sad8[2] *= 4;
251                                                    pMB->sad8[3] *= 4;
252                                                    continue;
253                                            }
254    
255          case 2: // x qpel, y halfpel - left or right during qpel refinement                                  }
                 GET_REFERENCE(halfpelMV.x, halfpelMV.y, ref1);  
                 GET_REFERENCE(x - halfpelMV.x, halfpelMV.y, ref2);  
256    
257                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding);                          pMB->mode = MODE_INTER;
258                  interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding);                          pMB->pmvs[0] = pmv;     /* pMB->pmvs[1] = pMB->pmvs[2] = pMB->pmvs[3]  are not needed for INTER */
259                  interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding);                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mv16;
260                  interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding);                          pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] =
261                  break;                                  pMB->sad16;
262                            }
263                            }
264    
265            return 0;
266    }
267    
         default: // x and y in qpel resolution - the "corners" (top left/right and  
                          // bottom left/right) during qpel refinement  
                 GET_REFERENCE(halfpelMV.x, halfpelMV.y, ref1);  
                 GET_REFERENCE(halfpelMV.x, y - halfpelMV.y, ref2);  
                 GET_REFERENCE(x - halfpelMV.x, halfpelMV.y, ref3);  
                 GET_REFERENCE(x - halfpelMV.x, y - halfpelMV.y, ref4);  
268    
269                  interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);  #define CHECK_MV16_ZERO {\
270                  interpolate8x8_avg4(Reference+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, rounding);    if ( (0 <= max_dx) && (0 >= min_dx) \
271                  interpolate8x8_avg4(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, rounding);      && (0 <= max_dy) && (0 >= min_dy) ) \
272                  interpolate8x8_avg4(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, rounding);    { \
273                  break;      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \
274        iSAD += calc_delta_16(-center_x, -center_y, (uint8_t)iFcode, iQuant);\
275        if (iSAD < iMinSAD) \
276        {  iMinSAD=iSAD; currMV->x=0; currMV->y=0; }  }     \
277    }
278    
279    #define NOCHECK_MV16_CANDIDATE(X,Y) { \
280        iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \
281        iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\
282        if (iSAD < iMinSAD) \
283        {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \
284    }
285    
286    #define CHECK_MV16_CANDIDATE(X,Y) { \
287      if ( ((X) <= max_dx) && ((X) >= min_dx) \
288        && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
289      { \
290        iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \
291        iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\
292        if (iSAD < iMinSAD) \
293        {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \
294          }          }
295    
296          data->temp[0] = sad16v(data->Cur, Reference, data->iEdgedWidth, data->temp+1);  #define CHECK_MV16_CANDIDATE_DIR(X,Y,D) { \
297      if ( ((X) <= max_dx) && ((X) >= min_dx) \
298        && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
299      { \
300        iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \
301        iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\
302        if (iSAD < iMinSAD) \
303        {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \
304    }
305    
306          t = d_mv_bits(x - data->predQMV.x, y - data->predQMV.y, data->iFcode);  #define CHECK_MV16_CANDIDATE_FOUND(X,Y,D) { \
307          data->temp[0] += lambda_vec16[data->iQuant] * t;    if ( ((X) <= max_dx) && ((X) >= min_dx) \
308          data->temp[1] += lambda_vec8[data->iQuant] * t;      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
309      { \
310        iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \
311        iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\
312        if (iSAD < iMinSAD) \
313        {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \
314    }
315    
         if (data->temp[0] < data->iMinSAD[0]) {  
                 data->iMinSAD[0] = data->temp[0];  
                 data->currentQMV[0].x = x; data->currentQMV[0].y = y;  
         /*      *dir = Direction;*/ }  
316    
317          if (data->temp[1] < data->iMinSAD[1]) {  #define CHECK_MV8_ZERO {\
318                  data->iMinSAD[1] = data->temp[1]; data->currentQMV[1].x = x; data->currentQMV[1].y = y; }    iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, 0, 0 , iEdgedWidth), iEdgedWidth); \
319          if (data->temp[2] < data->iMinSAD[2]) {    iSAD += calc_delta_8(-center_x, -center_y, (uint8_t)iFcode, iQuant);\
320                  data->iMinSAD[2] = data->temp[2]; data->currentQMV[2].x = x; data->currentQMV[2].y = y; }    if (iSAD < iMinSAD) \
321          if (data->temp[3] < data->iMinSAD[3]) {    { iMinSAD=iSAD; currMV->x=0; currMV->y=0; } \
                 data->iMinSAD[3] = data->temp[3]; data->currentQMV[3].x = x; data->currentQMV[3].y = y; }  
         if (data->temp[4] < data->iMinSAD[4]) {  
                 data->iMinSAD[4] = data->temp[4]; data->currentQMV[4].x = x; data->currentQMV[4].y = y; }  
322  }  }
323    
324  static void  #define NOCHECK_MV8_CANDIDATE(X,Y) \
325  CheckCandidate16no4v_qpel(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)    { \
326        iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \
327        iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\
328        if (iSAD < iMinSAD) \
329        {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \
330    }
331    
332  // CheckCandidate16no4v variant which expects x and y in quarter pixel resolution  #define CHECK_MV8_CANDIDATE(X,Y) { \
333  // Important: This is no general usable routine! x and y must be +/-1 (qpel resolution!)    if ( ((X) <= max_dx) && ((X) >= min_dx) \
334  // around currentMV!      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
335  {    { \
336          int32_t sad;      iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \
337          uint8_t * Reference = (uint8_t *) data->RefQ;      iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\
338          const uint8_t *ref1, *ref2, *ref3, *ref4;      if (iSAD < iMinSAD) \
339          VECTOR halfpelMV = *(data->currentMV);      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \
340    }
341    
342          int32_t iEdgedWidth = data->iEdgedWidth;  #define CHECK_MV8_CANDIDATE_DIR(X,Y,D) { \
343          uint32_t rounding = data->rounding;    if ( ((X) <= max_dx) && ((X) >= min_dx) \
344        && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
345      { \
346        iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \
347        iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\
348        if (iSAD < iMinSAD) \
349        {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \
350    }
351    
352          if (( x > data->max_dx) || ( x < data->min_dx)  #define CHECK_MV8_CANDIDATE_FOUND(X,Y,D) { \
353                  || ( y > data->max_dy) || (y < data->min_dy)) return;    if ( ((X) <= max_dx) && ((X) >= min_dx) \
354        && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
355      { \
356        iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \
357        iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\
358        if (iSAD < iMinSAD) \
359        {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \
360    }
361    
362          switch( ((x&1)<<1) + (y&1) )  /* too slow and not fully functional at the moment */
363    /*
364    int32_t ZeroSearch16(
365                                            const uint8_t * const pRef,
366                                            const uint8_t * const pRefH,
367                                            const uint8_t * const pRefV,
368                                            const uint8_t * const pRefHV,
369                                            const IMAGE * const pCur,
370                                            const int x, const int y,
371                                            const uint32_t MotionFlags,
372                                            const uint32_t iQuant,
373                                            const uint32_t iFcode,
374                                            MBParam * const pParam,
375                                            const MACROBLOCK * const pMBs,
376                                            const MACROBLOCK * const prevMBs,
377                                            VECTOR * const currMV,
378                                            VECTOR * const currPMV)
379          {          {
380          case 0: // pure halfpel position - shouldn't happen during a refinement step          const int32_t iEdgedWidth = pParam->edged_width;
381                  GET_REFERENCE(halfpelMV.x, halfpelMV.y, (const uint8_t *) Reference);          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;
382                  break;          int32_t iSAD;
383            VECTOR pred;
384    
         case 1: // x halfpel, y qpel - top or bottom during qpel refinement  
                 GET_REFERENCE(halfpelMV.x, halfpelMV.y, ref1);  
                 GET_REFERENCE(halfpelMV.x, y - halfpelMV.y, ref2);  
385    
386                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding);          pred = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
                 interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding);  
                 interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding);  
                 interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding);  
                 break;  
387    
388          case 2: // x qpel, y halfpel - left or right during qpel refinement          iSAD = sad16( cur,
389                  GET_REFERENCE(halfpelMV.x, halfpelMV.y, ref1);                  get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth),
390                  GET_REFERENCE(x - halfpelMV.x, halfpelMV.y, ref2);                  iEdgedWidth, MV_MAX_ERROR);
391            if (iSAD <= iQuant * 96)
392                    iSAD -= MV16_00_BIAS;
393    
394                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding);          currMV->x = 0;
395                  interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding);          currMV->y = 0;
396                  interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding);          currPMV->x = -pred.x;
397                  interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding);          currPMV->y = -pred.y;
                 break;  
398    
399          default: // x and y in qpel resolution - the "corners" (top left/right and          return iSAD;
                          // bottom left/right) during qpel refinement  
                 GET_REFERENCE(halfpelMV.x, halfpelMV.y, ref1);  
                 GET_REFERENCE(halfpelMV.x, y - halfpelMV.y, ref2);  
                 GET_REFERENCE(x - halfpelMV.x, halfpelMV.y, ref3);  
                 GET_REFERENCE(x - halfpelMV.x, y - halfpelMV.y, ref4);  
400    
                 interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);  
                 interpolate8x8_avg4(Reference+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, rounding);  
                 interpolate8x8_avg4(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, rounding);  
                 interpolate8x8_avg4(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, rounding);  
                 break;  
401          }          }
402    */
403    
404          sad = lambda_vec16[data->iQuant] *  int32_t
405                          d_mv_bits(x - data->predQMV.x, y - data->predQMV.y, data->iFcode);  Diamond16_MainSearch(const uint8_t * const pRef,
406          sad += sad16(data->Cur, Reference, data->iEdgedWidth, MV_MAX_ERROR);                                           const uint8_t * const pRefH,
407                                             const uint8_t * const pRefV,
408                                             const uint8_t * const pRefHV,
409                                             const uint8_t * const cur,
410                                             const int x,
411                                             const int y,
412                                       const int start_x,
413                                       const int start_y,
414                                       int iMinSAD,
415                                       VECTOR * const currMV,
416                                       const int center_x,
417                                       const int center_y,
418                                             const int32_t min_dx,
419                                             const int32_t max_dx,
420                                             const int32_t min_dy,
421                                             const int32_t max_dy,
422                                             const int32_t iEdgedWidth,
423                                             const int32_t iDiamondSize,
424                                             const int32_t iFcode,
425                                             const int32_t iQuant,
426                                             int iFound)
427    {
428    /* Do a diamond search around given starting point, return SAD of best */
429    
430            int32_t iDirection = 0;
431            int32_t iDirectionBackup;
432            int32_t iSAD;
433            VECTOR backupMV;
434    
435            backupMV.x = start_x;
436            backupMV.y = start_y;
437    
438    /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */
439    
440            CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);
441            CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);
442            CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);
443            CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);
444    
445          if (sad < *(data->iMinSAD)) {          if (iDirection) {
446                  *(data->iMinSAD) = sad;                  while (!iFound) {
447                  data->currentQMV[0].x = x; data->currentQMV[0].y = y;                          iFound = 1;
448  //              *dir = Direction;                          backupMV = *currMV;
449                            iDirectionBackup = iDirection;
450    
451                            if (iDirectionBackup != 2)
452                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
453                                                                                       backupMV.y, 1);
454                            if (iDirectionBackup != 1)
455                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
456                                                                                       backupMV.y, 2);
457                            if (iDirectionBackup != 4)
458                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x,
459                                                                                       backupMV.y - iDiamondSize, 3);
460                            if (iDirectionBackup != 3)
461                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x,
462                                                                                       backupMV.y + iDiamondSize, 4);
463          }          }
464            } else {
465                    currMV->x = start_x;
466                    currMV->y = start_y;
467            }
468            return iMinSAD;
469  }  }
470    
471  static void  int32_t
472  CheckCandidate16no4vI(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)  Square16_MainSearch(const uint8_t * const pRef,
473  {                                          const uint8_t * const pRefH,
474          int32_t sad;                                          const uint8_t * const pRefV,
475                                            const uint8_t * const pRefHV,
476                                            const uint8_t * const cur,
477                                            const int x,
478                                            const int y,
479                                       const int start_x,
480                                       const int start_y,
481                                       int iMinSAD,
482                                       VECTOR * const currMV,
483                                       const int center_x,
484                                       const int center_y,
485                                            const int32_t min_dx,
486                                            const int32_t max_dx,
487                                            const int32_t min_dy,
488                                            const int32_t max_dy,
489                                            const int32_t iEdgedWidth,
490                                            const int32_t iDiamondSize,
491                                            const int32_t iFcode,
492                                            const int32_t iQuant,
493                                            int iFound)
494    {
495    /* Do a square search around given starting point, return SAD of best */
496    
497            int32_t iDirection = 0;
498            int32_t iSAD;
499            VECTOR backupMV;
500    
501            backupMV.x = start_x;
502            backupMV.y = start_y;
503    
504    /* It's one search with full square pattern, and new parts for all following diamonds */
505    
506    /*   new direction are extra, so 1-4 is normal diamond
507          537
508          1*2
509          648
510    */
511    
512            CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);
513            CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);
514            CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);
515            CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);
516    
517            CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,
518                                                             backupMV.y - iDiamondSize, 5);
519            CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,
520                                                             backupMV.y + iDiamondSize, 6);
521            CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,
522                                                             backupMV.y - iDiamondSize, 7);
523            CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,
524                                                             backupMV.y + iDiamondSize, 8);
525    
         if (( x > data->max_dx) || ( x < data->min_dx)  
                 || ( y > data->max_dy) || (y < data->min_dy)) return;  
526    
527          sad = lambda_vec16[data->iQuant] *          if (iDirection) {
528                          d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);                  while (!iFound) {
529                            iFound = 1;
530                            backupMV = *currMV;
531    
532          sad += sad16(data->Cur, data->Ref + x/2 + (y/2)*(data->iEdgedWidth),                          switch (iDirection) {
533                                          data->iEdgedWidth, 256*4096);                          case 1:
534                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
535                                                                                       backupMV.y, 1);
536                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
537                                                                                     backupMV.y - iDiamondSize, 5);
538                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
539                                                                                     backupMV.y - iDiamondSize, 7);
540                                    break;
541                            case 2:
542                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
543                                                                                     2);
544                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
545                                                                                     backupMV.y + iDiamondSize, 6);
546                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
547                                                                                     backupMV.y + iDiamondSize, 8);
548                                    break;
549    
550          if (sad < *(data->iMinSAD)) {                          case 3:
551                  *(data->iMinSAD) = sad;                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
552                  data->currentMV[0].x = x; data->currentMV[0].y = y;                                                                                   4);
553                  *dir = Direction; }                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
554  }                                                                                   backupMV.y - iDiamondSize, 7);
555                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
556                                                                                     backupMV.y + iDiamondSize, 8);
557                                    break;
558    
559                            case 4:
560                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
561                                                                                     3);
562                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
563                                                                                     backupMV.y - iDiamondSize, 5);
564                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
565                                                                                     backupMV.y + iDiamondSize, 6);
566                                    break;
567    
568                            case 5:
569                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,
570                                                                                     1);
571                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
572                                                                                     3);
573                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
574                                                                                     backupMV.y - iDiamondSize, 5);
575                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
576                                                                                     backupMV.y + iDiamondSize, 6);
577                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
578                                                                                     backupMV.y - iDiamondSize, 7);
579                                    break;
580    
581                            case 6:
582                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
583                                                                                     2);
584                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
585                                                                                     3);
586    
587                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
588                                                                                     backupMV.y - iDiamondSize, 5);
589                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
590                                                                                     backupMV.y + iDiamondSize, 6);
591                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
592                                                                                     backupMV.y + iDiamondSize, 8);
593    
594  static void                                  break;
 CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)  
 {  
         int32_t sad;  
         const int xb = data->currentMV[1].x;  
         const int yb = data->currentMV[1].y;  
         const uint8_t *ReferenceF, *ReferenceB;  
595    
596          if (( xf > data->max_dx) || ( xf < data->min_dx)                          case 7:
597                  || ( yf > data->max_dy) || (yf < data->min_dy)) return;                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
598                                                                                       backupMV.y, 1);
599                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
600                                                                                     4);
601                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
602                                                                                     backupMV.y - iDiamondSize, 5);
603                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
604                                                                                     backupMV.y - iDiamondSize, 7);
605                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
606                                                                                     backupMV.y + iDiamondSize, 8);
607                                    break;
608    
609          switch ( ((xf&1)<<1) + (yf&1) ) {                          case 8:
610                  case 0 : ReferenceF = data->Ref + xf/2 + (yf/2)*(data->iEdgedWidth); break;                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
611                  case 1 : ReferenceF = data->RefV + xf/2 + ((yf-1)/2)*(data->iEdgedWidth); break;                                                                                   2);
612                  case 2 : ReferenceF = data->RefH + (xf-1)/2 + (yf/2)*(data->iEdgedWidth); break;                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
613                  default : ReferenceF = data->RefHV + (xf-1)/2 + ((yf-1)/2)*(data->iEdgedWidth); break;                                                                                   4);
614                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
615                                                                                     backupMV.y + iDiamondSize, 6);
616                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
617                                                                                     backupMV.y - iDiamondSize, 7);
618                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
619                                                                                     backupMV.y + iDiamondSize, 8);
620                                    break;
621                            default:
622                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,
623                                                                                     1);
624                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
625                                                                                     2);
626                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
627                                                                                     3);
628                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
629                                                                                     4);
630    
631                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
632                                                                                     backupMV.y - iDiamondSize, 5);
633                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
634                                                                                     backupMV.y + iDiamondSize, 6);
635                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
636                                                                                     backupMV.y - iDiamondSize, 7);
637                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
638                                                                                     backupMV.y + iDiamondSize, 8);
639                                    break;
640          }          }
641                    }
642          switch ( ((xb&1)<<1) + (yb&1) ) {          } else {
643                  case 0 : ReferenceB = data->bRef + xb/2 + (yb/2)*(data->iEdgedWidth); break;                  currMV->x = start_x;
644                  case 1 : ReferenceB = data->bRefV + xb/2 + ((yb-1)/2)*(data->iEdgedWidth); break;                  currMV->y = start_y;
645                  case 2 : ReferenceB = data->bRefH + (xb-1)/2 + (yb/2)*(data->iEdgedWidth); break;          }
646                  default : ReferenceB = data->bRefHV + (xb-1)/2 + ((yb-1)/2)*(data->iEdgedWidth); break;          return iMinSAD;
647          }          }
648    
         sad = lambda_vec16[data->iQuant] *  
                         ( d_mv_bits(xf - data->predMV.x, yf - data->predMV.y, data->iFcode) +  
                           d_mv_bits(xb - data->bpredMV.x, yb - data->bpredMV.y, data->iFcode) );  
649    
650          sad += sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);  int32_t
651    Full16_MainSearch(const uint8_t * const pRef,
652                                      const uint8_t * const pRefH,
653                                      const uint8_t * const pRefV,
654                                      const uint8_t * const pRefHV,
655                                      const uint8_t * const cur,
656                                      const int x,
657                                      const int y,
658                                       const int start_x,
659                                       const int start_y,
660                                       int iMinSAD,
661                                       VECTOR * const currMV,
662                                       const int center_x,
663                                       const int center_y,
664                                      const int32_t min_dx,
665                                      const int32_t max_dx,
666                                      const int32_t min_dy,
667                                      const int32_t max_dy,
668                                      const int32_t iEdgedWidth,
669                                      const int32_t iDiamondSize,
670                                      const int32_t iFcode,
671                                      const int32_t iQuant,
672                                      int iFound)
673    {
674            int32_t iSAD;
675            int32_t dx, dy;
676            VECTOR backupMV;
677    
678            backupMV.x = start_x;
679            backupMV.y = start_y;
680    
681            for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)
682                    for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)
683                            NOCHECK_MV16_CANDIDATE(dx, dy);
684    
685          if (sad < *(data->iMinSAD)) {          return iMinSAD;
                 *(data->iMinSAD) = sad;  
                 data->currentMV->x = xf; data->currentMV->y = yf;  
                 *dir = Direction; }  
686  }  }
687    
688  static void  int32_t
689  CheckCandidateDirect(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)  AdvDiamond16_MainSearch(const uint8_t * const pRef,
690                                                    const uint8_t * const pRefH,
691                                                    const uint8_t * const pRefV,
692                                                    const uint8_t * const pRefHV,
693                                                    const uint8_t * const cur,
694                                                    const int x,
695                                                    const int y,
696                                               int start_x,
697                                               int start_y,
698                                               int iMinSAD,
699                                               VECTOR * const currMV,
700                                               const int center_x,
701                                               const int center_y,
702                                                    const int32_t min_dx,
703                                                    const int32_t max_dx,
704                                                    const int32_t min_dy,
705                                                    const int32_t max_dy,
706                                                    const int32_t iEdgedWidth,
707                                                    const int32_t iDiamondSize,
708                                                    const int32_t iFcode,
709                                                    const int32_t iQuant,
710                                                    int iDirection)
711  {  {
         int32_t sad;  
         int k;  
         const uint8_t *ReferenceF;  
         const uint8_t *ReferenceB;  
         VECTOR mvs, b_mvs;  
712    
713          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;          int32_t iSAD;
714    
715          sad = lambda_vec16[data->iQuant] * d_mv_bits(x, y, 1);  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
716    
717          for (k = 0; k < 4; k++) {          if (iDirection) {
718                  mvs.x = data->directmvF[k].x + x;                  CHECK_MV16_CANDIDATE(start_x - iDiamondSize, start_y);
719                  b_mvs.x = ((x == 0) ?                  CHECK_MV16_CANDIDATE(start_x + iDiamondSize, start_y);
720                          data->directmvB[k].x                  CHECK_MV16_CANDIDATE(start_x, start_y - iDiamondSize);
721                          : mvs.x - data->referencemv[k].x);                  CHECK_MV16_CANDIDATE(start_x, start_y + iDiamondSize);
722            } else {
723                    int bDirection = 1 + 2 + 4 + 8;
724    
725                  mvs.y = data->directmvF[k].y + y;                  do {
726                  b_mvs.y = ((y == 0) ?                          iDirection = 0;
727                          data->directmvB[k].y                          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)
728                          : mvs.y - data->referencemv[k].y);                                  CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);
729    
730                  if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )                          if (bDirection & 2)
731                          || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )                                  CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);
                         || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )  
                         || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;  
732    
733                  switch ( ((mvs.x&1)<<1) + (mvs.y&1) ) {                          if (bDirection & 4)
734                          case 0 : ReferenceF = data->Ref + mvs.x/2 + (mvs.y/2)*(data->iEdgedWidth); break;                                  CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);
                         case 1 : ReferenceF = data->RefV + mvs.x/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;  
                         case 2 : ReferenceF = data->RefH + (mvs.x-1)/2 + (mvs.y/2)*(data->iEdgedWidth); break;  
                         default : ReferenceF = data->RefHV + (mvs.x-1)/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;  
                 }  
735    
736                  switch ( ((b_mvs.x&1)<<1) + (b_mvs.y&1) ) {                          if (bDirection & 8)
737                          case 0 : ReferenceB = data->bRef + b_mvs.x/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;                                  CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);
                         case 1 : ReferenceB = data->bRefV + b_mvs.x/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;  
                         case 2 : ReferenceB = data->bRefH + (b_mvs.x-1)/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;  
                         default : ReferenceB = data->bRefHV + (b_mvs.x-1)/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;  
                 }  
738    
739                  sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),                          /* now we're doing diagonal checks near our candidate */
                                                 ReferenceF + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),  
                                                 ReferenceB + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),  
                                                 data->iEdgedWidth);  
                 if (sad > *(data->iMinSAD)) return;  
         }  
740    
741          if (sad < *(data->iMinSAD)) {                          if (iDirection)         //checking if anything found
742                  *(data->iMinSAD) = sad;                          {
743                  data->currentMV->x = x; data->currentMV->y = y;                                  bDirection = iDirection;
744                  *dir = Direction; }                                  iDirection = 0;
745                                    start_x = currMV->x;
746                                    start_y = currMV->y;
747                                    if (bDirection & 3)     //our candidate is left or right
748                                    {
749                                            CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);
750                                            CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);
751                                    } else                  // what remains here is up or down
752                                    {
753                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);
754                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);
755  }  }
756    
757  static void                                  if (iDirection) {
758  CheckCandidateDirectno4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)                                          bDirection += iDirection;
759                                            start_x = currMV->x;
760                                            start_y = currMV->y;
761                                    }
762                            } else                          //about to quit, eh? not so fast....
763  {  {
764          int32_t sad;                                  switch (bDirection) {
765          const uint8_t *ReferenceF;                                  case 2:
766          const uint8_t *ReferenceB;                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
767          VECTOR mvs, b_mvs;                                                                                           start_y - iDiamondSize, 2 + 4);
768                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
769                                                                                             start_y + iDiamondSize, 2 + 8);
770                                            break;
771                                    case 1:
772    
773          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
774                                                                                             start_y - iDiamondSize, 1 + 4);
775                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
776                                                                                             start_y + iDiamondSize, 1 + 8);
777                                            break;
778                                    case 2 + 4:
779                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
780                                                                                             start_y - iDiamondSize, 1 + 4);
781                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
782                                                                                             start_y - iDiamondSize, 2 + 4);
783                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
784                                                                                             start_y + iDiamondSize, 2 + 8);
785                                            break;
786                                    case 4:
787                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
788                                                                                             start_y - iDiamondSize, 2 + 4);
789                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
790                                                                                             start_y - iDiamondSize, 1 + 4);
791                                            break;
792                                    case 8:
793                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
794                                                                                             start_y + iDiamondSize, 2 + 8);
795                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
796                                                                                             start_y + iDiamondSize, 1 + 8);
797                                            break;
798                                    case 1 + 4:
799                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
800                                                                                             start_y + iDiamondSize, 1 + 8);
801                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
802                                                                                             start_y - iDiamondSize, 1 + 4);
803                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
804                                                                                             start_y - iDiamondSize, 2 + 4);
805                                            break;
806                                    case 2 + 8:
807                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
808                                                                                             start_y - iDiamondSize, 1 + 4);
809                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
810                                                                                             start_y + iDiamondSize, 1 + 8);
811                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
812                                                                                             start_y + iDiamondSize, 2 + 8);
813                                            break;
814                                    case 1 + 8:
815                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
816                                                                                             start_y - iDiamondSize, 2 + 4);
817                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
818                                                                                             start_y + iDiamondSize, 2 + 8);
819                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
820                                                                                             start_y + iDiamondSize, 1 + 8);
821                                            break;
822                                    default:                //1+2+4+8 == we didn't find anything at all
823                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
824                                                                                             start_y - iDiamondSize, 1 + 4);
825                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
826                                                                                             start_y + iDiamondSize, 1 + 8);
827                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
828                                                                                             start_y - iDiamondSize, 2 + 4);
829                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
830                                                                                             start_y + iDiamondSize, 2 + 8);
831                                            break;
832                                    }
833                                    if (!iDirection)
834                                            break;          //ok, the end. really
835                                    else {
836                                            bDirection = iDirection;
837                                            start_x = currMV->x;
838                                            start_y = currMV->y;
839                                    }
840                            }
841                    }
842                    while (1);                              //forever
843            }
844            return iMinSAD;
845    }
846    
847                  sad = lambda_vec16[data->iQuant] * d_mv_bits(x, y, 1);  #define CHECK_MV16_F_INTERPOL(X,Y) { \
848      if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \
849        && ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \
850      { \
851        iSAD = sad16bi( cur, \
852                            get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \
853                            get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, b_currMV->x, b_currMV->y, iEdgedWidth),   \
854                            iEdgedWidth); \
855        iSAD += calc_delta_16((X) - f_center_x, (Y) - f_center_y, (uint8_t)f_iFcode, iQuant);\
856        iSAD += calc_delta_16(b_currMV->x - b_center_x, b_currMV->y - b_center_y, (uint8_t)b_iFcode, iQuant);\
857        if (iSAD < iMinSAD) \
858        {  iMinSAD=iSAD; f_currMV->x=(X); f_currMV->y=(Y); } } \
859    }
860    
861          mvs.x = data->directmvF[0].x + x;  #define CHECK_MV16_F_INTERPOL_FOUND(X,Y) { \
862          b_mvs.x = ((x == 0) ?    if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \
863                  data->directmvB[0].x      && ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \
864                  : mvs.x - data->referencemv[0].x);    { \
865        iSAD = sad16bi( cur, \
866                            get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \
867                            get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, b_currMV->x, b_currMV->y, iEdgedWidth),   \
868                            iEdgedWidth); \
869        iSAD += calc_delta_16((X) - f_center_x, (Y) - f_center_y, (uint8_t)f_iFcode, iQuant);\
870        iSAD += calc_delta_16(b_currMV->x - b_center_x, b_currMV->y - b_center_y, (uint8_t)b_iFcode, iQuant);\
871        if (iSAD < iMinSAD) \
872        {  iMinSAD=iSAD; f_currMV->x=(X); f_currMV->y=(Y); iFound=0;} } \
873    }
874    
875          mvs.y = data->directmvF[0].y + y;  #define CHECK_MV16_B_INTERPOL(X,Y) { \
876          b_mvs.y = ((y == 0) ?    if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \
877                  data->directmvB[0].y      && ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \
878                  : mvs.y - data->referencemv[0].y);    { \
879        iSAD = sad16bi( cur, \
880                            get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth),   \
881                            get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \
882                            iEdgedWidth); \
883        iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\
884        iSAD += calc_delta_16((X) - b_center_x, (Y) - b_center_y, (uint8_t)b_iFcode, iQuant);\
885        if (iSAD < iMinSAD) \
886        {  iMinSAD=iSAD; b_currMV->x=(X); b_currMV->y=(Y); } } \
887    }
888    
889          if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )  #define CHECK_MV16_B_INTERPOL_FOUND(X,Y) { \
890                  || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )    if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \
891                  || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )      && ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \
892                  || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;    { \
893        iSAD = sad16bi( cur, \
894                            get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth),   \
895                            get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \
896                            iEdgedWidth); \
897        iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\
898        iSAD += calc_delta_16((X) - b_center_x, (Y) - b_center_y, (uint8_t)b_iFcode, iQuant);\
899        if (iSAD < iMinSAD) \
900        {  iMinSAD=iSAD; b_currMV->x=(X); b_currMV->y=(Y); iFound=0;} } \
901    }
902    
903    int32_t
904    Diamond16_InterpolMainSearch(
905                                            const uint8_t * const f_pRef,
906                                             const uint8_t * const f_pRefH,
907                                             const uint8_t * const f_pRefV,
908                                             const uint8_t * const f_pRefHV,
909    
910                                             const uint8_t * const cur,
911    
912                                            const uint8_t * const b_pRef,
913                                             const uint8_t * const b_pRefH,
914                                             const uint8_t * const b_pRefV,
915                                             const uint8_t * const b_pRefHV,
916    
917          switch ( ((mvs.x&1)<<1) + (mvs.y&1) ) {                                           const int x,
918                  case 0 : ReferenceF = data->Ref + mvs.x/2 + (mvs.y/2)*(data->iEdgedWidth); break;                                           const int y,
                 case 1 : ReferenceF = data->RefV + mvs.x/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;  
                 case 2 : ReferenceF = data->RefH + (mvs.x-1)/2 + (mvs.y/2)*(data->iEdgedWidth); break;  
                 default : ReferenceF = data->RefHV + (mvs.x-1)/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;  
         }  
919    
920          switch ( ((b_mvs.x&1)<<1) + (b_mvs.y&1) ) {                                     const int f_start_x,
921                  case 0 : ReferenceB = data->bRef + b_mvs.x/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;                                     const int f_start_y,
922                  case 1 : ReferenceB = data->bRefV + b_mvs.x/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;                                     const int b_start_x,
923                  case 2 : ReferenceB = data->bRefH + (b_mvs.x-1)/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;                                     const int b_start_y,
924                  default : ReferenceB = data->bRefHV + (b_mvs.x-1)/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;  
925                                       int iMinSAD,
926                                       VECTOR * const f_currMV,
927                                       VECTOR * const b_currMV,
928    
929                                       const int f_center_x,
930                                       const int f_center_y,
931                                       const int b_center_x,
932                                       const int b_center_y,
933    
934                                        const int32_t f_min_dx,
935                                            const int32_t f_max_dx,
936                                            const int32_t f_min_dy,
937                                            const int32_t f_max_dy,
938    
939                                        const int32_t b_min_dx,
940                                            const int32_t b_max_dx,
941                                            const int32_t b_min_dy,
942                                            const int32_t b_max_dy,
943    
944                                            const int32_t iEdgedWidth,
945                                            const int32_t iDiamondSize,
946    
947                                            const int32_t f_iFcode,
948                                            const int32_t b_iFcode,
949    
950                                            const int32_t iQuant,
951                                            int iFound)
952    {
953    /* Do a diamond search around given starting point, return SAD of best */
954    
955            int32_t iSAD;
956    
957            VECTOR f_backupMV;
958            VECTOR b_backupMV;
959    
960            f_currMV->x = f_start_x;
961            f_currMV->y = f_start_y;
962            b_currMV->x = b_start_x;
963            b_currMV->y = b_start_y;
964    
965            do
966            {
967                    iFound = 1;
968    
969                    f_backupMV = *f_currMV;
970    
971                    CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x - iDiamondSize, f_backupMV.y);
972                    CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x + iDiamondSize, f_backupMV.y);
973                    CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y - iDiamondSize);
974                    CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y + iDiamondSize);
975    
976                    b_backupMV = *b_currMV;
977    
978                    CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x - iDiamondSize, b_backupMV.y);
979                    CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x + iDiamondSize, b_backupMV.y);
980                    CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y - iDiamondSize);
981                    CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y + iDiamondSize);
982    
983            } while (!iFound);
984    
985            return iMinSAD;
986    }
987    
988    /* Sorry, these MACROS really got too large... I'll turn them into function soon! */
989    
990    #define CHECK_MV16_DIRECT_FOUND(X,Y) \
991            if ( (X)>=(-32) && (X)<=(31) && ((Y)>=-32) && ((Y)<=31) ) \
992            { int k;\
993            VECTOR mvs,b_mvs;       \
994            iSAD = 0;\
995            for (k = 0; k < 4; k++) {       \
996                                            mvs.x = (int32_t) ((TRB * directmv[k].x) / TRD + (X));          \
997                        b_mvs.x = (int32_t) (((X) == 0)                                                     \
998                                                                                    ? ((TRB - TRD) * directmv[k].x) / TRD   \
999                                                : mvs.x - directmv[k].x);                           \
1000                                                                                                                                                                    \
1001                        mvs.y = (int32_t) ((TRB * directmv[k].y) / TRD + (Y));              \
1002                            b_mvs.y = (int32_t) (((Y) == 0)                                                         \
1003                                                                                    ? ((TRB - TRD) * directmv[k].y) / TRD   \
1004                                                : mvs.y - directmv[k].y);                           \
1005                                                                                                                                                                    \
1006      if ( (mvs.x <= max_dx) && (mvs.x >= min_dx) \
1007        && (mvs.y <= max_dy) && (mvs.y >= min_dy)  \
1008            && (b_mvs.x <= max_dx) && (b_mvs.x >= min_dx)  \
1009        && (b_mvs.y <= max_dy) && (b_mvs.y >= min_dy) ) { \
1010                iSAD += sad8bi( cur + 8*(k&1) + 8*(k>>1)*iEdgedWidth,                                                                                                       \
1011                            get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \
1012                                            mvs.x, mvs.y, iEdgedWidth),                                                             \
1013                            get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \
1014                                            b_mvs.x, b_mvs.y, iEdgedWidth),                                                         \
1015                            iEdgedWidth); \
1016                    }       \
1017            else    \
1018                    iSAD = 65535;   \
1019            } \
1020            iSAD += calc_delta_16((X),(Y), 1, iQuant);\
1021            if (iSAD < iMinSAD) \
1022                {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iFound=0; } \
1023          }          }
1024    
         sad += sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);  
1025    
         if (sad < *(data->iMinSAD)) {  
                 *(data->iMinSAD) = sad;  
                 data->currentMV->x = x; data->currentMV->y = y;  
                 *dir = Direction; }  
 }  
1026    
1027  static void  int32_t
1028  CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)  Diamond16_DirectMainSearch(
1029  {                                          const uint8_t * const f_pRef,
1030          int32_t sad;                                          const uint8_t * const f_pRefH,
1031          const uint8_t * Reference;                                          const uint8_t * const f_pRefV,
1032                                            const uint8_t * const f_pRefHV,
1033    
1034          if (( x > data->max_dx) || ( x < data->min_dx)                                          const uint8_t * const cur,
                 || ( y > data->max_dy) || (y < data->min_dy)) return;  
1035    
1036          switch ( ((x&1)<<1) + (y&1) )                                          const uint8_t * const b_pRef,
1037          {                                          const uint8_t * const b_pRefH,
1038                  case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;                                          const uint8_t * const b_pRefV,
1039                  case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;                                          const uint8_t * const b_pRefHV,
                 case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;  
                 default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;  
         }  
1040    
1041          sad = sad8(data->Cur, Reference, data->iEdgedWidth);                                          const int x,
1042          sad += lambda_vec8[data->iQuant] * d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);                                          const int y,
1043    
1044          if (sad < *(data->iMinSAD)) {                                          const int TRB,
1045                  *(data->iMinSAD) = sad;                                          const int TRD,
                 data->currentMV->x = x; data->currentMV->y = y;  
                 *dir = Direction; }  
 }  
1046    
1047  static void                                      const int start_x,
1048  CheckCandidate8_qpel(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)                                      const int start_y,
 // CheckCandidate16no4v variant which expects x and y in quarter pixel resolution  
 // Important: This is no general usable routine! x and y must be +/-1 (qpel resolution!)  
 // around currentMV!  
1049    
1050  {                                      int iMinSAD,
1051          int32_t sad;                                      VECTOR * const currMV,
1052          uint8_t *Reference = (uint8_t *) data->RefQ;                                          const VECTOR * const directmv,
         const uint8_t *ref1, *ref2, *ref3, *ref4;  
         VECTOR halfpelMV = *(data->currentMV);  
1053    
1054          int32_t iEdgedWidth = data->iEdgedWidth;                                      const int32_t min_dx,
1055          uint32_t rounding = data->rounding;                                          const int32_t max_dx,
1056                                            const int32_t min_dy,
1057                                            const int32_t max_dy,
1058    
1059          if (( x > data->max_dx) || ( x < data->min_dx)                                          const int32_t iEdgedWidth,
1060                  || ( y > data->max_dy) || (y < data->min_dy)) return;                                          const int32_t iDiamondSize,
1061    
1062          switch( ((x&1)<<1) + (y&1) )                                          const int32_t iQuant,
1063                                            int iFound)
1064          {          {
1065          case 0: // pure halfpel position - shouldn't happen during a refinement step  /* Do a diamond search around given starting point, return SAD of best */
                 GET_REFERENCE(halfpelMV.x, halfpelMV.y, (const uint8_t *) Reference);  
                 break;  
1066    
1067          case 1: // x halfpel, y qpel - top or bottom during qpel refinement          int32_t iSAD;
                 GET_REFERENCE(halfpelMV.x, halfpelMV.y, ref1);  
                 GET_REFERENCE(halfpelMV.x, y - halfpelMV.y, ref2);  
1068    
1069                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding);          VECTOR backupMV;
                 break;  
1070    
1071          case 2: // x qpel, y halfpel - left or right during qpel refinement          currMV->x = start_x;
1072                  GET_REFERENCE(halfpelMV.x, halfpelMV.y, ref1);          currMV->y = start_y;
                 GET_REFERENCE(x - halfpelMV.x, halfpelMV.y, ref2);  
1073    
1074                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding);  /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */
                 break;  
1075    
1076          default: // x and y in qpel resolution - the "corners" (top left/right and          do
1077                           // bottom left/right) during qpel refinement          {
1078                  GET_REFERENCE(halfpelMV.x, halfpelMV.y, ref1);                  iFound = 1;
                 GET_REFERENCE(halfpelMV.x, y - halfpelMV.y, ref2);  
                 GET_REFERENCE(x - halfpelMV.x, halfpelMV.y, ref3);  
                 GET_REFERENCE(x - halfpelMV.x, y - halfpelMV.y, ref4);  
1079    
1080                  interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);                  backupMV = *currMV;
                 break;  
         }  
1081    
1082          sad = sad8(data->Cur, Reference, data->iEdgedWidth);                  CHECK_MV16_DIRECT_FOUND(backupMV.x - iDiamondSize, backupMV.y);
1083          sad += lambda_vec8[data->iQuant] * d_mv_bits(x - data->predQMV.x, y - data->predQMV.y, data->iFcode);                  CHECK_MV16_DIRECT_FOUND(backupMV.x + iDiamondSize, backupMV.y);
1084                    CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y - iDiamondSize);
1085                    CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y + iDiamondSize);
1086    
1087          if (sad < *(data->iMinSAD)) {          } while (!iFound);
                 *(data->iMinSAD) = sad;  
                 data->currentQMV->x = x; data->currentQMV->y = y;  
                 *dir = Direction; }  
 }  
1088    
1089  /* CHECK_CANDIATE FUNCTIONS END */          return iMinSAD;
1090    }
1091    
 /* MAINSEARCH FUNCTIONS START */  
1092    
1093  static void  int32_t
1094  AdvDiamondSearch(int x, int y, const SearchData * const data, int bDirection)  AdvDiamond8_MainSearch(const uint8_t * const pRef,
1095                                               const uint8_t * const pRefH,
1096                                               const uint8_t * const pRefV,
1097                                               const uint8_t * const pRefHV,
1098                                               const uint8_t * const cur,
1099                                               const int x,
1100                                               const int y,
1101                                               int start_x,
1102                                               int start_y,
1103                                               int iMinSAD,
1104                                               VECTOR * const currMV,
1105                                               const int center_x,
1106                                               const int center_y,
1107                                               const int32_t min_dx,
1108                                               const int32_t max_dx,
1109                                               const int32_t min_dy,
1110                                               const int32_t max_dy,
1111                                               const int32_t iEdgedWidth,
1112                                               const int32_t iDiamondSize,
1113                                               const int32_t iFcode,
1114                                               const int32_t iQuant,
1115                                               int iDirection)
1116  {  {
1117    
1118            int32_t iSAD;
1119    
1120  /* 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) */
1121    
1122                  int iDirection;          if (iDirection) {
1123                    CHECK_MV8_CANDIDATE(start_x - iDiamondSize, start_y);
1124                    CHECK_MV8_CANDIDATE(start_x + iDiamondSize, start_y);
1125                    CHECK_MV8_CANDIDATE(start_x, start_y - iDiamondSize);
1126                    CHECK_MV8_CANDIDATE(start_x, start_y + iDiamondSize);
1127            } else {
1128                    int bDirection = 1 + 2 + 4 + 8;
1129    
1130                  do {                  do {
1131                          iDirection = 0;                          iDirection = 0;
1132                          if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);                          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)
1133                          if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);                                  CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);
1134                          if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);  
1135                          if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);                          if (bDirection & 2)
1136                                    CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);
1137    
1138                            if (bDirection & 4)
1139                                    CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);
1140    
1141                            if (bDirection & 8)
1142                                    CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);
1143    
1144                          /* now we're doing diagonal checks near our candidate */                          /* now we're doing diagonal checks near our candidate */
1145    
1146                          if (iDirection) {               //checking if anything found                          if (iDirection)         //checking if anything found
1147                            {
1148                                  bDirection = iDirection;                                  bDirection = iDirection;
1149                                  iDirection = 0;                                  iDirection = 0;
1150                                  x = data->currentMV->x; y = data->currentMV->y;                                  start_x = currMV->x;
1151                                  if (bDirection & 3) {   //our candidate is left or right                                  start_y = currMV->y;
1152                                          CHECK_CANDIDATE(x, y + iDiamondSize, 8);                                  if (bDirection & 3)     //our candidate is left or right
1153                                          CHECK_CANDIDATE(x, y - iDiamondSize, 4);                                  {
1154                                  } else {                        // what remains here is up or down                                          CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);
1155                                          CHECK_CANDIDATE(x + iDiamondSize, y, 2);                                          CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);
1156                                          CHECK_CANDIDATE(x - iDiamondSize, y, 1); }                                  } else                  // what remains here is up or down
1157                                    {
1158                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);
1159                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);
1160                                    }
1161    
1162                                  if (iDirection) {                                  if (iDirection) {
1163                                          bDirection += iDirection;                                          bDirection += iDirection;
1164                                          x = data->currentMV->x; y = data->currentMV->y; }                                          start_x = currMV->x;
1165                          } else {                                //about to quit, eh? not so fast....                                          start_y = currMV->y;
1166                                    }
1167                            } else                          //about to quit, eh? not so fast....
1168                            {
1169                                  switch (bDirection) {                                  switch (bDirection) {
1170                                  case 2:                                  case 2:
1171                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1172                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);                                                                                          start_y - iDiamondSize, 2 + 4);
1173                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1174                                                                                            start_y + iDiamondSize, 2 + 8);
1175                                          break;                                          break;
1176                                  case 1:                                  case 1:
1177                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1178                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);                                                                                          start_y - iDiamondSize, 1 + 4);
1179                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1180                                                                                            start_y + iDiamondSize, 1 + 8);
1181                                          break;                                          break;
1182                                  case 2 + 4:                                  case 2 + 4:
1183                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1184                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);                                                                                          start_y - iDiamondSize, 1 + 4);
1185                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1186                                                                                            start_y - iDiamondSize, 2 + 4);
1187                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1188                                                                                            start_y + iDiamondSize, 2 + 8);
1189                                          break;                                          break;
1190                                  case 4:                                  case 4:
1191                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1192                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);                                                                                          start_y - iDiamondSize, 2 + 4);
1193                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1194                                                                                            start_y - iDiamondSize, 1 + 4);
1195                                          break;                                          break;
1196                                  case 8:                                  case 8:
1197                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1198                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);                                                                                          start_y + iDiamondSize, 2 + 8);
1199                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1200                                                                                            start_y + iDiamondSize, 1 + 8);
1201                                          break;                                          break;
1202                                  case 1 + 4:                                  case 1 + 4:
1203                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1204                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);                                                                                          start_y + iDiamondSize, 1 + 8);
1205                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1206                                                                                            start_y - iDiamondSize, 1 + 4);
1207                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1208                                                                                            start_y - iDiamondSize, 2 + 4);
1209                                          break;                                          break;
1210                                  case 2 + 8:                                  case 2 + 8:
1211                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1212                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);                                                                                          start_y - iDiamondSize, 1 + 4);
1213                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1214                                                                                            start_y + iDiamondSize, 1 + 8);
1215                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1216                                                                                            start_y + iDiamondSize, 2 + 8);
1217                                          break;                                          break;
1218                                  case 1 + 8:                                  case 1 + 8:
1219                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1220                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);                                                                                          start_y - iDiamondSize, 2 + 4);
1221                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1222                                                                                            start_y + iDiamondSize, 2 + 8);
1223                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1224                                                                                            start_y + iDiamondSize, 1 + 8);
1225                                          break;                                          break;
1226                                  default:                //1+2+4+8 == we didn't find anything at all                                  default:                //1+2+4+8 == we didn't find anything at all
1227                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1228                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);                                                                                          start_y - iDiamondSize, 1 + 4);
1229                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1230                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);                                                                                          start_y + iDiamondSize, 1 + 8);
1231                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1232                                                                                            start_y - iDiamondSize, 2 + 4);
1233                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1234                                                                                            start_y + iDiamondSize, 2 + 8);
1235                                          break;                                          break;
1236                                  }                                  }
1237                                  if (!iDirection) break;         //ok, the end. really                                  if (!(iDirection))
1238                                            break;          //ok, the end. really
1239                                    else {
1240                                  bDirection = iDirection;                                  bDirection = iDirection;
1241                                  x = data->currentMV->x; y = data->currentMV->y;                                          start_x = currMV->x;
1242                                            start_y = currMV->y;
1243                                    }
1244                          }                          }
1245                  }                  }
1246                  while (1);                              //forever                  while (1);                              //forever
1247  }  }
1248            return iMinSAD;
1249    }
1250    
1251    
1252  static void  int32_t
1253  SquareSearch(int x, int y, const SearchData * const data, int bDirection)  Full8_MainSearch(const uint8_t * const pRef,
1254                                     const uint8_t * const pRefH,
1255                                     const uint8_t * const pRefV,
1256                                     const uint8_t * const pRefHV,
1257                                     const uint8_t * const cur,
1258                                     const int x,
1259                                     const int y,
1260                               const int start_x,
1261                               const int start_y,
1262                               int iMinSAD,
1263                               VECTOR * const currMV,
1264                               const int center_x,
1265                               const int center_y,
1266                                     const int32_t min_dx,
1267                                     const int32_t max_dx,
1268                                     const int32_t min_dy,
1269                                     const int32_t max_dy,
1270                                     const int32_t iEdgedWidth,
1271                                     const int32_t iDiamondSize,
1272                                     const int32_t iFcode,
1273                                     const int32_t iQuant,
1274                                     int iFound)
1275    {
1276            int32_t iSAD;
1277            int32_t dx, dy;
1278            VECTOR backupMV;
1279    
1280            backupMV.x = start_x;
1281            backupMV.y = start_y;
1282    
1283            for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)
1284                    for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)
1285                            NOCHECK_MV8_CANDIDATE(dx, dy);
1286    
1287            return iMinSAD;
1288    }
1289    
1290    Halfpel8_RefineFuncPtr Halfpel8_Refine;
1291    
1292    int32_t
1293    Halfpel16_Refine(const uint8_t * const pRef,
1294                                     const uint8_t * const pRefH,
1295                                     const uint8_t * const pRefV,
1296                                     const uint8_t * const pRefHV,
1297                                     const uint8_t * const cur,
1298                                     const int x,
1299                                     const int y,
1300                                     VECTOR * const currMV,
1301                                     int32_t iMinSAD,
1302                               const int center_x,
1303                               const int center_y,
1304                                     const int32_t min_dx,
1305                                     const int32_t max_dx,
1306                                     const int32_t min_dy,
1307                                     const int32_t max_dy,
1308                                     const int32_t iFcode,
1309                                     const int32_t iQuant,
1310                                     const int32_t iEdgedWidth)
1311  {  {
1312          int iDirection;  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */
1313    
1314          do {          int32_t iSAD;
1315                  iDirection = 0;          VECTOR backupMV = *currMV;
                 if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);  
                 if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);  
                 if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);  
                 if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128);  
                 if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64);  
                 if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128);  
                 if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128);  
                 if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128);  
1316    
1317                  bDirection = iDirection;          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y - 1);
1318                  x = data->currentMV->x; y = data->currentMV->y;          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y - 1);
1319          } while (iDirection);          CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y - 1);
1320            CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y);
1321            CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y);
1322            CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y + 1);
1323            CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y + 1);
1324            CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y + 1);
1325    
1326            return iMinSAD;
1327  }  }
1328    
1329  static void  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)
1330  DiamondSearch(int x, int y, const SearchData * const data, int bDirection)  
1331    
1332    
1333    int32_t
1334    PMVfastSearch16(const uint8_t * const pRef,
1335                                    const uint8_t * const pRefH,
1336                                    const uint8_t * const pRefV,
1337                                    const uint8_t * const pRefHV,
1338                                    const IMAGE * const pCur,
1339                                    const int x,
1340                                    const int y,
1341                                    const int start_x,      /* start is searched first, so it should contain the most */
1342                                    const int start_y,  /* likely motion vector for this block */
1343                                    const int center_x,     /* center is from where length of MVs is measured */
1344                                    const int center_y,
1345                                    const uint32_t MotionFlags,
1346                                    const uint32_t iQuant,
1347                                    const uint32_t iFcode,
1348                                    const MBParam * const pParam,
1349                                    const MACROBLOCK * const pMBs,
1350                                    const MACROBLOCK * const prevMBs,
1351                                    VECTOR * const currMV,
1352                                    VECTOR * const currPMV)
1353  {  {
1354            const uint32_t iWcount = pParam->mb_width;
1355            const int32_t iWidth = pParam->width;
1356            const int32_t iHeight = pParam->height;
1357            const int32_t iEdgedWidth = pParam->edged_width;
1358    
1359  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;
1360    
1361                  int iDirection;          int32_t iDiamondSize;
1362    
1363                  do {          int32_t min_dx;
1364                          iDirection = 0;          int32_t max_dx;
1365                          if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);          int32_t min_dy;
1366                          if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);          int32_t max_dy;
                         if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);  
                         if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);  
1367    
1368                          /* now we're doing diagonal checks near our candidate */          int32_t iFound;
1369    
1370                          if (iDirection) {               //checking if anything found          VECTOR newMV;
1371                                  bDirection = iDirection;          VECTOR backupMV;                        /* just for PMVFAST */
                                 iDirection = 0;  
                                 x = data->currentMV->x; y = data->currentMV->y;  
                                 if (bDirection & 3) {   //our candidate is left or right  
                                         CHECK_CANDIDATE(x, y + iDiamondSize, 8);  
                                         CHECK_CANDIDATE(x, y - iDiamondSize, 4);  
                                 } else {                        // what remains here is up or down  
                                         CHECK_CANDIDATE(x + iDiamondSize, y, 2);  
                                         CHECK_CANDIDATE(x - iDiamondSize, y, 1); }  
1372    
1373                                  bDirection += iDirection;          VECTOR pmv[4];
1374                                  x = data->currentMV->x; y = data->currentMV->y;          int32_t psad[4];
1375    
1376            MainSearch16FuncPtr MainSearchPtr;
1377    
1378            const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;
1379    
1380            int32_t threshA, threshB;
1381            int32_t bPredEq;
1382            int32_t iMinSAD, iSAD;
1383    
1384    /* Get maximum range */
1385            get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,
1386                              iFcode);
1387    
1388    /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */
1389    
1390            if (!(MotionFlags & PMV_HALFPEL16)) {
1391                    min_dx = EVEN(min_dx);
1392                    max_dx = EVEN(max_dx);
1393                    min_dy = EVEN(min_dy);
1394                    max_dy = EVEN(max_dy);
1395                          }                          }
1396    
1397            /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */
1398            //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);
1399            bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);
1400    
1401            if ((x == 0) && (y == 0)) {
1402                    threshA = 512;
1403                    threshB = 1024;
1404            } else {
1405                    threshA = psad[0];
1406                    threshB = threshA + 256;
1407                    if (threshA < 512)
1408                            threshA = 512;
1409                    if (threshA > 1024)
1410                            threshA = 1024;
1411                    if (threshB > 1792)
1412                            threshB = 1792;
1413                  }                  }
1414                  while (iDirection);  
1415            iFound = 0;
1416    
1417    /* Step 4: Calculate SAD around the Median prediction.
1418       MinSAD=SAD
1419       If Motion Vector equal to Previous frame motion vector
1420       and MinSAD<PrevFrmSAD goto Step 10.
1421       If SAD<=256 goto Step 10.
1422    */
1423    
1424            currMV->x = start_x;
1425            currMV->y = start_y;
1426    
1427            if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */
1428                    currMV->x = EVEN(currMV->x);
1429                    currMV->y = EVEN(currMV->y);
1430  }  }
1431    
1432  /* MAINSEARCH FUNCTIONS END */          if (currMV->x > max_dx) {
1433                    currMV->x = max_dx;
1434            }
1435            if (currMV->x < min_dx) {
1436                    currMV->x = min_dx;
1437            }
1438            if (currMV->y > max_dy) {
1439                    currMV->y = max_dy;
1440            }
1441            if (currMV->y < min_dy) {
1442                    currMV->y = min_dy;
1443            }
1444    
1445  /* HALFPELREFINE COULD BE A MAINSEARCH FUNCTION, BUT THERE IS NO NEED FOR IT */          iMinSAD =
1446                    sad16(cur,
1447                              get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,
1448                                                     iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);
1449            iMinSAD +=
1450                    calc_delta_16(currMV->x - center_x, currMV->y - center_y,
1451                                              (uint8_t) iFcode, iQuant);
1452    
1453  static void          if ((iMinSAD < 256) ||
1454  HalfpelRefine(const SearchData * const data)                  ((MVequal(*currMV, prevMB->mvs[0])) &&
1455                     ((int32_t) iMinSAD < prevMB->sad16))) {
1456                    if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode
1457  {  {
1458  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */                          if (!MVzero(*currMV)) {
1459                                    iMinSAD += MV16_00_BIAS;
1460                                    CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures
1461                                    iMinSAD -= MV16_00_BIAS;
1462                            }
1463                    }
1464    
1465                    if (MotionFlags & PMV_QUICKSTOP16)
1466                            goto PMVfast16_Terminate_without_Refine;
1467                    if (MotionFlags & PMV_EARLYSTOP16)
1468                            goto PMVfast16_Terminate_with_Refine;
1469            }
1470    
1471    
1472    /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion
1473       vector of the median.
1474       If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2
1475    */
1476    
1477            if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[0])))
1478                    iFound = 2;
1479    
1480    /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.
1481       Otherwise select large Diamond Search.
1482    */
1483    
1484            if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))
1485                    iDiamondSize = 1;               // halfpel!
1486            else
1487                    iDiamondSize = 2;               // halfpel!
1488    
1489            if (!(MotionFlags & PMV_HALFPELDIAMOND16))
1490                    iDiamondSize *= 2;
1491    
1492          VECTOR backupMV = *(data->currentMV);  /*
1493          int iDirection; //not needed     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.
1494       Also calculate (0,0) but do not subtract offset.
1495       Let MinSAD be the smallest SAD up to this point.
1496       If MV is (0,0) subtract offset.
1497    */
1498    
1499          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y - 1, 0);  // (0,0) is always possible
         CHECK_CANDIDATE(backupMV.x + 1, backupMV.y - 1, 0);  
         CHECK_CANDIDATE(backupMV.x - 1, backupMV.y + 1, 0);  
         CHECK_CANDIDATE(backupMV.x + 1, backupMV.y + 1, 0);  
1500    
1501          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y, 0);          if (!MVzero(pmv[0]))
1502          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y, 0);                  CHECK_MV16_ZERO;
1503    
1504          CHECK_CANDIDATE(backupMV.x, backupMV.y + 1, 0);  // previous frame MV is always possible
1505          CHECK_CANDIDATE(backupMV.x, backupMV.y - 1, 0);  
1506            if (!MVzero(prevMB->mvs[0]))
1507                    if (!MVequal(prevMB->mvs[0], pmv[0]))
1508                            CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);
1509    
1510    // left neighbour, if allowed
1511    
1512            if (!MVzero(pmv[1]))
1513                    if (!MVequal(pmv[1], prevMB->mvs[0]))
1514                            if (!MVequal(pmv[1], pmv[0])) {
1515                                    if (!(MotionFlags & PMV_HALFPEL16)) {
1516                                            pmv[1].x = EVEN(pmv[1].x);
1517                                            pmv[1].y = EVEN(pmv[1].y);
1518  }  }
1519    
1520                                    CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);
1521                            }
1522    // top neighbour, if allowed
1523            if (!MVzero(pmv[2]))
1524                    if (!MVequal(pmv[2], prevMB->mvs[0]))
1525                            if (!MVequal(pmv[2], pmv[0]))
1526                                    if (!MVequal(pmv[2], pmv[1])) {
1527                                            if (!(MotionFlags & PMV_HALFPEL16)) {
1528                                                    pmv[2].x = EVEN(pmv[2].x);
1529                                                    pmv[2].y = EVEN(pmv[2].y);
1530                                            }
1531                                            CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);
1532    
1533  static void  // top right neighbour, if allowed
1534  QuarterpelRefine(const SearchData * const data)                                          if (!MVzero(pmv[3]))
1535  {                                                  if (!MVequal(pmv[3], prevMB->mvs[0]))
1536  /* Perform quarter pixel refinement*/                                                          if (!MVequal(pmv[3], pmv[0]))
1537                                                                    if (!MVequal(pmv[3], pmv[1]))
1538                                                                            if (!MVequal(pmv[3], pmv[2])) {
1539                                                                                    if (!(MotionFlags & PMV_HALFPEL16)) {
1540                                                                                            pmv[3].x = EVEN(pmv[3].x);
1541                                                                                            pmv[3].y = EVEN(pmv[3].y);
1542                                                                                    }
1543                                                                                    CHECK_MV16_CANDIDATE(pmv[3].x,
1544                                                                                                                             pmv[3].y);
1545                                                                            }
1546                                    }
1547    
1548          VECTOR backupMV = *(data->currentQMV);          if ((MVzero(*currMV)) &&
1549          int iDirection; //not needed                  (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )
1550                    iMinSAD -= MV16_00_BIAS;
1551    
         CHECK_CANDIDATE(backupMV.x - 1, backupMV.y - 1, 0);  
         CHECK_CANDIDATE(backupMV.x + 1, backupMV.y - 1, 0);  
         CHECK_CANDIDATE(backupMV.x - 1, backupMV.y + 1, 0);  
         CHECK_CANDIDATE(backupMV.x + 1, backupMV.y + 1, 0);  
1552    
1553          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y, 0);  /* Step 6: If MinSAD <= thresa goto Step 10.
1554          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y, 0);     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.
1555    */
1556    
1557          CHECK_CANDIDATE(backupMV.x, backupMV.y + 1, 0);          if ((iMinSAD <= threshA) ||
1558          CHECK_CANDIDATE(backupMV.x, backupMV.y - 1, 0);                  (MVequal(*currMV, prevMB->mvs[0]) &&
1559                     ((int32_t) iMinSAD < prevMB->sad16))) {
1560                    if (MotionFlags & PMV_QUICKSTOP16)
1561                            goto PMVfast16_Terminate_without_Refine;
1562                    if (MotionFlags & PMV_EARLYSTOP16)
1563                            goto PMVfast16_Terminate_with_Refine;
1564            }
1565    
1566    
1567    /************ (Diamond Search)  **************/
1568    /*
1569       Step 7: Perform Diamond search, with either the small or large diamond.
1570       If Found=2 only examine one Diamond pattern, and afterwards goto step 10
1571       Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.
1572       If center then goto step 10.
1573       Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.
1574       Refine by using small diamond and goto step 10.
1575    */
1576    
1577            if (MotionFlags & PMV_USESQUARES16)
1578                    MainSearchPtr = Square16_MainSearch;
1579            else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
1580                    MainSearchPtr = AdvDiamond16_MainSearch;
1581            else
1582                    MainSearchPtr = Diamond16_MainSearch;
1583    
1584            backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */
1585    
1586    
1587    /* default: use best prediction as starting point for one call of PMVfast_MainSearch */
1588            iSAD =
1589                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,
1590                                                      currMV->x, currMV->y, iMinSAD, &newMV, center_x, center_y,
1591                                                      min_dx, max_dx,
1592                                                      min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,
1593                                                      iQuant, iFound);
1594    
1595            if (iSAD < iMinSAD) {
1596                    *currMV = newMV;
1597                    iMinSAD = iSAD;
1598  }  }
1599    
1600  static __inline int          if (MotionFlags & PMV_EXTSEARCH16) {
1601  SkipDecisionP(const IMAGE * current, const IMAGE * reference,  /* extended: search (up to) two more times: orignal prediction and (0,0) */
                                                         const int x, const int y,  
                                                         const uint32_t iEdgedWidth, const uint32_t iQuant)  
1602    
1603  {                  if (!(MVequal(pmv[0], backupMV))) {
1604  /*      keep repeating checks for all b-frames before this P frame,                          iSAD =
1605          to make sure that SKIP is possible (todo)                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,
1606          how: if skip is not possible set sad00 to a very high value */                                                                    center_x, center_y, iMinSAD, &newMV, center_x, center_y,
1607                                                                      min_dx, max_dx, min_dy, max_dy, iEdgedWidth,
1608          uint32_t sadC = sad8(current->u + x*8 + y*(iEdgedWidth/2)*8,                                                                    iDiamondSize, iFcode, iQuant, iFound);
                                         reference->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2);  
         if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;  
         sadC += sad8(current->v + (x + y*(iEdgedWidth/2))*8,  
                                         reference->v + (x + y*(iEdgedWidth/2))*8, iEdgedWidth/2);  
         if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;  
1609    
1610          return 1;                          if (iSAD < iMinSAD) {
1611                                    *currMV = newMV;
1612                                    iMinSAD = iSAD;
1613                            }
1614  }  }
1615    
1616  static __inline void                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {
1617  SkipMacroblockP(MACROBLOCK *pMB, const int32_t sad)                          iSAD =
1618  {                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,
1619          pMB->mode = MODE_NOT_CODED;                                                                    iMinSAD, &newMV, center_x, center_y,
1620          pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = 0;                                                                    min_dx, max_dx, min_dy, max_dy,
1621          pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = 0;                                                                    iEdgedWidth, iDiamondSize, iFcode,
1622                                                                      iQuant, iFound);
1623    
1624                            if (iSAD < iMinSAD) {
1625                                    *currMV = newMV;
1626                                    iMinSAD = iSAD;
1627                            }
1628                    }
1629            }
1630    
1631    /*
1632       Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.
1633    */
1634    
1635          pMB->qmvs[0].x = pMB->qmvs[1].x = pMB->qmvs[2].x = pMB->qmvs[3].x = 0;    PMVfast16_Terminate_with_Refine:
1636          pMB->qmvs[0].y = pMB->qmvs[1].y = pMB->qmvs[2].y = pMB->qmvs[3].y = 0;          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step
1637                    iMinSAD =
1638                            Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,
1639                                                             iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,
1640                                                             iFcode, iQuant, iEdgedWidth);
1641    
1642          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;    PMVfast16_Terminate_without_Refine:
1643            currPMV->x = currMV->x - center_x;
1644            currPMV->y = currMV->y - center_y;
1645            return iMinSAD;
1646  }  }
1647    
 bool  
 MotionEstimation(MBParam * const pParam,  
                                  FRAMEINFO * const current,  
                                  FRAMEINFO * const reference,  
                                  const IMAGE * const pRefH,  
                                  const IMAGE * const pRefV,  
                                  const IMAGE * const pRefHV,  
                                  const uint32_t iLimit)  
 {  
         MACROBLOCK *const pMBs = current->mbs;  
         const IMAGE *const pCurrent = &current->image;  
         const IMAGE *const pRef = &reference->image;  
1648    
         const VECTOR zeroMV = { 0, 0 };  
1649    
1650          uint32_t x, y;  
1651          uint32_t iIntra = 0;  
1652          int32_t InterBias, quant = current->quant;  
1653          uint8_t *qimage;  int32_t
1654    Diamond8_MainSearch(const uint8_t * const pRef,
1655          // some pre-initialized thingies for SearchP                                          const uint8_t * const pRefH,
1656          int32_t temp[5];                                          const uint8_t * const pRefV,
1657          VECTOR currentMV[5];                                          const uint8_t * const pRefHV,
1658          VECTOR currentQMV[5];                                          const uint8_t * const cur,
1659          int32_t iMinSAD[5];                                          const int x,
1660          SearchData Data;                                          const int y,
1661          Data.iEdgedWidth = pParam->edged_width;                                          int32_t start_x,
1662          Data.currentMV = currentMV;                                          int32_t start_y,
1663          Data.currentQMV = currentQMV;                                          int32_t iMinSAD,
1664          Data.iMinSAD = iMinSAD;                                          VECTOR * const currMV,
1665          Data.temp = temp;                                     const int center_x,
1666          Data.iFcode = current->fcode;                                     const int center_y,
1667          Data.rounding = pParam->m_rounding_type;                                          const int32_t min_dx,
1668                                            const int32_t max_dx,
1669          if((qimage = (uint8_t *) malloc(32 * pParam->edged_width)) == NULL)                                          const int32_t min_dy,
1670                  return 1; // allocate some mem for qpel interpolated blocks                                          const int32_t max_dy,
1671                                    // somehow this is dirty since I think we shouldn't use malloc outside                                          const int32_t iEdgedWidth,
1672                                    // encoder_create() - so please fix me!                                          const int32_t iDiamondSize,
1673                                            const int32_t iFcode,
1674          if (sadInit) (*sadInit) ();                                          const int32_t iQuant,
1675                                            int iFound)
1676          for (y = 0; y < pParam->mb_height; y++) {  {
1677                  for (x = 0; x < pParam->mb_width; x++)  {  /* Do a diamond search around given starting point, return SAD of best */
1678    
1679                          MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];          int32_t iDirection = 0;
1680                          int32_t sad00 =  pMB->sad16          int32_t iDirectionBackup;
1681                                  = sad16v(pCurrent->y + (x + y * pParam->edged_width) * 16,          int32_t iSAD;
1682                                                          pRef->y + (x + y * pParam->edged_width) * 16,          VECTOR backupMV;
1683                                                          pParam->edged_width, pMB->sad8 );  
1684            backupMV.x = start_x;
1685                          if (!(current->global_flags & XVID_LUMIMASKING)) {          backupMV.y = start_y;
1686                                  pMB->dquant = NO_CHANGE;  
1687                                  pMB->quant = current->quant; }  /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */
1688                          else  
1689                                  if (pMB->dquant != NO_CHANGE) {          CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);
1690                                          quant += DQtab[pMB->dquant];          CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);
1691                                          if (quant > 31) quant = 31;          CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);
1692                                          else if (quant < 1) quant = 1;          CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);
1693                                          pMB->quant = quant;  
1694            if (iDirection) {
1695                    while (!iFound) {
1696                            iFound = 1;
1697                            backupMV = *currMV;     // since iDirection!=0, this is well defined!
1698                            iDirectionBackup = iDirection;
1699    
1700                            if (iDirectionBackup != 2)
1701                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1702                                                                                      backupMV.y, 1);
1703                            if (iDirectionBackup != 1)
1704                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1705                                                                                      backupMV.y, 2);
1706                            if (iDirectionBackup != 4)
1707                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x,
1708                                                                                      backupMV.y - iDiamondSize, 3);
1709                            if (iDirectionBackup != 3)
1710                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x,
1711                                                                                      backupMV.y + iDiamondSize, 4);
1712                    }
1713            } else {
1714                    currMV->x = start_x;
1715                    currMV->y = start_y;
1716                                  }                                  }
1717            return iMinSAD;
1718    }
1719    
1720    
1721    
1722    
1723    int32_t
1724    Square8_MainSearch(const uint8_t * const pRef,
1725                                            const uint8_t * const pRefH,
1726                                            const uint8_t * const pRefV,
1727                                            const uint8_t * const pRefHV,
1728                                            const uint8_t * const cur,
1729                                            const int x,
1730                                            const int y,
1731                                            int32_t start_x,
1732                                            int32_t start_y,
1733                                            int32_t iMinSAD,
1734                                            VECTOR * const currMV,
1735                                       const int center_x,
1736                                       const int center_y,
1737                                            const int32_t min_dx,
1738                                            const int32_t max_dx,
1739                                            const int32_t min_dy,
1740                                            const int32_t max_dy,
1741                                            const int32_t iEdgedWidth,
1742                                            const int32_t iDiamondSize,
1743                                            const int32_t iFcode,
1744                                            const int32_t iQuant,
1745                                            int iFound)
1746    {
1747    /* Do a square search around given starting point, return SAD of best */
1748    
1749            int32_t iDirection = 0;
1750            int32_t iSAD;
1751            VECTOR backupMV;
1752    
1753            backupMV.x = start_x;
1754            backupMV.y = start_y;
1755    
1756    /* It's one search with full square pattern, and new parts for all following diamonds */
1757    
1758    /*   new direction are extra, so 1-4 is normal diamond
1759          537
1760          1*2
1761          648
1762    */
1763    
1764            CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);
1765            CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);
1766            CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);
1767            CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);
1768    
1769            CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,
1770                                                             backupMV.y - iDiamondSize, 5);
1771            CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,
1772                                                             backupMV.y + iDiamondSize, 6);
1773            CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,
1774                                                             backupMV.y - iDiamondSize, 7);
1775            CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,
1776                                                             backupMV.y + iDiamondSize, 8);
1777    
1778    
1779  //initial skip decision          if (iDirection) {
1780                    while (!iFound) {
1781                          if ((pMB->dquant == NO_CHANGE) && (sad00 <= MAX_SAD00_FOR_SKIP * pMB->quant)                          iFound = 1;
1782                                  && (SkipDecisionP(pCurrent, pRef, x, y, pParam->edged_width, pMB->quant)) ) {                          backupMV = *currMV;
                                 if (pMB->sad16 < pMB->quant * INITIAL_SKIP_THRESH) {  
                                                 SkipMacroblockP(pMB, sad00);  
                                                 continue;  
                                         sad00 = 256 * 4096;  
                                 }  
                         } else sad00 = 256*4096; // skip not allowed - for final skip decision  
1783    
1784                          SearchP(pRef->y, pRefH->y, pRefV->y, pRefHV->y, qimage, pCurrent, x,                          switch (iDirection) {
1785                                                  y, current->motion_flags, pMB->quant,                          case 1:
1786                                                  &Data, pParam, pMBs, reference->mbs,                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1787                                                  current->global_flags & XVID_INTER4V, pMB);                                                                                     backupMV.y, 1);
1788                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1789                                                                                     backupMV.y - iDiamondSize, 5);
1790                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1791                                                                                     backupMV.y - iDiamondSize, 7);
1792                                    break;
1793                            case 2:
1794                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
1795                                                                                     2);
1796                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1797                                                                                     backupMV.y + iDiamondSize, 6);
1798                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1799                                                                                     backupMV.y + iDiamondSize, 8);
1800                                    break;
1801    
1802  /* final skip decision, a.k.a. "the vector you found, really that good?" */                          case 3:
1803                          if (sad00 < pMB->quant * MAX_SAD00_FOR_SKIP)                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
1804                                  if ((100*pMB->sad16)/(sad00+1) > FINAL_SKIP_THRESH)                                                                                   4);
1805                                  { SkipMacroblockP(pMB, sad00); continue; }                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1806                                                                                     backupMV.y - iDiamondSize, 7);
1807                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1808                                                                                     backupMV.y + iDiamondSize, 8);
1809                                    break;
1810    
1811  /* finally, intra decision */                          case 4:
1812                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
1813                                                                                     3);
1814                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1815                                                                                     backupMV.y - iDiamondSize, 5);
1816                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1817                                                                                     backupMV.y + iDiamondSize, 6);
1818                                    break;
1819    
1820                            case 5:
1821                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,
1822                                                                                     1);
1823                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
1824                                                                                     3);
1825                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1826                                                                                     backupMV.y - iDiamondSize, 5);
1827                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1828                                                                                     backupMV.y + iDiamondSize, 6);
1829                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1830                                                                                     backupMV.y - iDiamondSize, 7);
1831                                    break;
1832    
1833                            case 6:
1834                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
1835                                                                                     2);
1836                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
1837                                                                                     3);
1838    
1839                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1840                                                                                     backupMV.y - iDiamondSize, 5);
1841                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1842                                                                                     backupMV.y + iDiamondSize, 6);
1843                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1844                                                                                     backupMV.y + iDiamondSize, 8);
1845    
1846                          InterBias = MV16_INTER_BIAS;                                  break;
                         if (pMB->quant > 8)  InterBias += 50 * (pMB->quant - 8); // to make high quants work  
                         if (y != 0)  
                                 if ((pMB - pParam->mb_width)->mode == MODE_INTER ) InterBias -= 50;  
                         if (x != 0)  
                                 if ((pMB - 1)->mode == MODE_INTER ) InterBias -= 50;  
1847    
1848                          if (InterBias < pMB->sad16)  {                          case 7:
1849                                  const int32_t deviation =                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1850                                          dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,                                                                                     backupMV.y, 1);
1851                                                    pParam->edged_width);                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
1852                                                                                     4);
1853                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1854                                                                                     backupMV.y - iDiamondSize, 5);
1855                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1856                                                                                     backupMV.y - iDiamondSize, 7);
1857                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1858                                                                                     backupMV.y + iDiamondSize, 8);
1859                                    break;
1860    
1861                                  if (deviation < (pMB->sad16 - InterBias)) {                          case 8:
1862                                          if (++iIntra >= iLimit) { free(qimage); return 1; }                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
1863                                          pMB->mode = MODE_INTRA;                                                                                   2);
1864                                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
1865                                                          pMB->mvs[3] = zeroMV;                                                                                   4);
1866                                          pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] =                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1867                                                          pMB->qmvs[3] = zeroMV;                                                                                   backupMV.y + iDiamondSize, 6);
1868                                          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1869                                                  pMB->sad8[3] = 0;                                                                                   backupMV.y - iDiamondSize, 7);
1870                                  }                                  CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1871                                                                                     backupMV.y + iDiamondSize, 8);
1872                                    break;
1873                            default:
1874                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,
1875                                                                                     1);
1876                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
1877                                                                                     2);
1878                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
1879                                                                                     3);
1880                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
1881                                                                                     4);
1882    
1883                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1884                                                                                     backupMV.y - iDiamondSize, 5);
1885                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1886                                                                                     backupMV.y + iDiamondSize, 6);
1887                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1888                                                                                     backupMV.y - iDiamondSize, 7);
1889                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1890                                                                                     backupMV.y + iDiamondSize, 8);
1891                                    break;
1892                          }                          }
1893                  }                  }
1894            } else {
1895                    currMV->x = start_x;
1896                    currMV->y = start_y;
1897          }          }
1898          free(qimage);          return iMinSAD;
         return 0;  
1899  }  }
1900    
1901    
 #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)  
   
 static __inline int  
 make_mask(const VECTOR * const pmv, const int i)  
 {  
         int mask = 255, j;  
         for (j = 0; j < i; j++) {  
                 if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already  
                 if (pmv[i].x == pmv[j].x) {  
                         if (pmv[i].y == pmv[j].y + iDiamondSize) { mask &= ~4; continue; }  
                         if (pmv[i].y == pmv[j].y - iDiamondSize) { mask &= ~8; continue; }  
                 } else  
                         if (pmv[i].y == pmv[j].y) {  
                                 if (pmv[i].x == pmv[j].x + iDiamondSize) { mask &= ~1; continue; }  
                                 if (pmv[i].x == pmv[j].x - iDiamondSize) { mask &= ~2; continue; }  
                         }  
         }  
         return mask;  
 }  
   
 static __inline void  
 PreparePredictionsP(VECTOR * const pmv, int x, int y, const int iWcount,  
                         const int iHcount, const MACROBLOCK * const prevMB)  
 {  
1902    
 //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself  
1903    
         if ( (y != 0) && (x != (iWcount-1)) ) {         // [5] top-right neighbour  
                 pmv[5].x = EVEN(pmv[3].x);  
                 pmv[5].y = EVEN(pmv[3].y);  
         } else pmv[5].x = pmv[5].y = 0;  
1904    
1905          if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }// pmv[3] is left neighbour  int32_t
1906          else pmv[3].x = pmv[3].y = 0;  Halfpel8_Refine_c(const uint8_t * const pRef,
1907                                    const uint8_t * const pRefH,
1908                                    const uint8_t * const pRefV,
1909                                    const uint8_t * const pRefHV,
1910                                    const uint8_t * const cur,
1911                                    const int x,
1912                                    const int y,
1913                                    VECTOR * const currMV,
1914                                    int32_t iMinSAD,
1915                               const int center_x,
1916                               const int center_y,
1917                                    const int32_t min_dx,
1918                                    const int32_t max_dx,
1919                                    const int32_t min_dy,
1920                                    const int32_t max_dy,
1921                                    const int32_t iFcode,
1922                                    const int32_t iQuant,
1923                                    const int32_t iEdgedWidth)
1924    {
1925    /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */
1926    
1927          if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }// [4] top neighbour          int32_t iSAD;
1928      else pmv[4].x = pmv[4].y = 0;          VECTOR backupMV = *currMV;
1929    
1930          // [1] median prediction          CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y - 1);
1931          pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);          CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y - 1);
1932            CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y - 1);
1933            CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y);
1934            CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y);
1935            CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y + 1);
1936            CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y + 1);
1937            CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y + 1);
1938    
1939          pmv[0].x = pmv[0].y = 0; // [0] is zero; not used in the loop (checked before) but needed here for make_mask          return iMinSAD;
1940    }
1941    
         pmv[2].x = EVEN(prevMB->mvs[0].x); // [2] is last frame  
         pmv[2].y = EVEN(prevMB->mvs[0].y);  
1942    
1943          if ((x != iWcount-1) && (y != iHcount-1)) {  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)
                 pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); //[6] right-down neighbour in last frame  
                 pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);  
         } else pmv[6].x = pmv[6].y = 0;  
 }  
1944    
1945  static void  int32_t
1946  SearchP(const uint8_t * const pRef,  PMVfastSearch8(const uint8_t * const pRef,
1947                  const uint8_t * const pRefH,                  const uint8_t * const pRefH,
1948                  const uint8_t * const pRefV,                  const uint8_t * const pRefV,
1949                  const uint8_t * const pRefHV,                  const uint8_t * const pRefHV,
                 const uint8_t * const pRefQ,  
1950                  const IMAGE * const pCur,                  const IMAGE * const pCur,
1951                  const int x,                  const int x,
1952                  const int y,                  const int y,
1953                               const int start_x,
1954                               const int start_y,
1955                                    const int center_x,
1956                                    const int center_y,
1957                  const uint32_t MotionFlags,                  const uint32_t MotionFlags,
1958                  const uint32_t iQuant,                  const uint32_t iQuant,
1959                  SearchData * const Data,                             const uint32_t iFcode,
1960                  const MBParam * const pParam,                  const MBParam * const pParam,
1961                  const MACROBLOCK * const pMBs,                  const MACROBLOCK * const pMBs,
1962                  const MACROBLOCK * const prevMBs,                  const MACROBLOCK * const prevMBs,
1963                  int inter4v,                             VECTOR * const currMV,
1964                  MACROBLOCK * const pMB)                             VECTOR * const currPMV)
1965  {  {
1966            const uint32_t iWcount = pParam->mb_width;
1967            const int32_t iWidth = pParam->width;
1968            const int32_t iHeight = pParam->height;
1969            const int32_t iEdgedWidth = pParam->edged_width;
1970    
1971          int i, iDirection = 255, mask, threshA;          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;
         VECTOR pmv[7];  
1972    
1973          Data->predQMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);          int32_t iDiamondSize;
1974    
1975          get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);  //has to be changed to get_pmv(2)()          int32_t min_dx;
1976          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,          int32_t max_dx;
1977                                  pParam->width, pParam->height, Data->iFcode, pParam->m_quarterpel);          int32_t min_dy;
1978            int32_t max_dy;
1979    
1980          Data->predMV = pmv[0];          VECTOR pmv[4];
1981            int32_t psad[4];
1982            VECTOR newMV;
1983            VECTOR backupMV;
1984            VECTOR startMV;
1985    
1986          Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16;  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;
1987          Data->Ref = pRef + (x + Data->iEdgedWidth*y)*16;          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;
         Data->RefH = pRefH + (x + Data->iEdgedWidth*y) * 16;  
         Data->RefV = pRefV + (x + Data->iEdgedWidth*y) * 16;  
         Data->RefHV = pRefHV + (x + Data->iEdgedWidth*y) * 16;  
         Data->RefQ = pRefQ;  
1988    
1989          Data->iQuant = iQuant;           int32_t threshA, threshB;
1990            int32_t iFound, bPredEq;
1991            int32_t iMinSAD, iSAD;
1992    
1993          if (!(MotionFlags & PMV_HALFPEL16)) {          int32_t iSubBlock = (y & 1) + (y & 1) + (x & 1);
                 Data->min_dx = EVEN(Data->min_dx);  
                 Data->max_dx = EVEN(Data->max_dx);  
                 Data->min_dy = EVEN(Data->min_dy);  
                 Data->max_dy = EVEN(Data->max_dy); }  
   
         if (pMB->dquant != NO_CHANGE) inter4v = 0;  
   
         if (inter4v) CheckCandidate = CheckCandidate16;  
         else CheckCandidate = CheckCandidate16no4v;  
   
         for(i = 0;  i < 5; i++)  
                 Data->currentMV[i].x = Data->currentMV[i].y = 0;  
   
         i = d_mv_bits(Data->predMV.x, Data->predMV.y, Data->iFcode);  
         Data->iMinSAD[0] = pMB->sad16 + lambda_vec16[iQuant] * i;  
         Data->iMinSAD[1] = pMB->sad8[0] + lambda_vec8[iQuant] * i;  
         Data->iMinSAD[2] = pMB->sad8[1];  
         Data->iMinSAD[3] = pMB->sad8[2];  
         Data->iMinSAD[4] = pMB->sad8[3];  
1994    
1995          if ((x == 0) && (y == 0)) threshA = 512;          MainSearch8FuncPtr MainSearchPtr;
         else {  
                 threshA = Data->temp[0]; // that's when we keep this SAD atm  
                 if (threshA < 512) threshA = 512;  
                 if (threshA > 1024) threshA = 1024; }  
1996    
1997          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,          /* Init variables */
1998                                          prevMBs + x + y * pParam->mb_width);          startMV.x = start_x;
1999            startMV.y = start_y;
2000    
2001          if (inter4v) CheckCandidate = CheckCandidate16;          /* Get maximum range */
2002          else CheckCandidate = CheckCandidate16no4v;          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,
2003                              iFcode);
2004    
2005            if (!(MotionFlags & PMV_HALFPELDIAMOND8)) {
2006                    min_dx = EVEN(min_dx);
2007                    max_dx = EVEN(max_dx);
2008                    min_dy = EVEN(min_dy);
2009                    max_dy = EVEN(max_dy);
2010            }
2011    
2012  /* main loop. checking all predictions */          /* because we might use IF (dx>max_dx) THEN dx=max_dx; */
2013            //bPredEq = get_pmvdata(pMBs, (x >> 1), (y >> 1), iWcount, iSubBlock, pmv, psad);
2014            bPredEq = get_pmvdata2(pMBs, iWcount, 0, (x >> 1), (y >> 1), iSubBlock, pmv, psad);
2015    
2016          for (i = 1; i < 7; i++) {          if ((x == 0) && (y == 0)) {
2017                  if (!(mask = make_mask(pmv, i)) ) continue;                  threshA = 512 / 4;
2018                  (*CheckCandidate)(pmv[i].x, pmv[i].y, mask, &iDirection, Data);                  threshB = 1024 / 4;
                 if (Data->iMinSAD[0] <= threshA) break;  
         }  
2019    
         if ((Data->iMinSAD[0] <= threshA) ||  
                         (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&  
                         (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16))) {  
                 inter4v = 0;  
2020          } else {          } else {
2021                    threshA = psad[0] / 4;  /* good estimate? */
2022                    threshB = threshA + 256 / 4;
2023                    if (threshA < 512 / 4)
2024                            threshA = 512 / 4;
2025                    if (threshA > 1024 / 4)
2026                            threshA = 1024 / 4;
2027                    if (threshB > 1792 / 4)
2028                            threshB = 1792 / 4;
2029            }
2030    
2031            iFound = 0;
2032    
2033    /* Step 4: Calculate SAD around the Median prediction.
2034       MinSAD=SAD
2035       If Motion Vector equal to Previous frame motion vector
2036       and MinSAD<PrevFrmSAD goto Step 10.
2037       If SAD<=256 goto Step 10.
2038    */
2039    
                 MainSearchFunc * MainSearchPtr;  
                 if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;  
                 else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;  
                         else MainSearchPtr = DiamondSearch;  
   
                 (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, iDirection);  
   
 /* extended search, diamond starting in 0,0 and in prediction.  
         note that this search is/might be done in halfpel positions,  
         which makes it more different than the diamond above */  
2040    
2041                  if (MotionFlags & PMV_EXTSEARCH16) {  // Prepare for main loop
                         int32_t bSAD;  
                         VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];  
                         if (!(MotionFlags & PMV_HALFPELREFINE16)) // who's gonna use extsearch and no halfpel?  
                                 startMV.x = EVEN(startMV.x); startMV.y = EVEN(startMV.y);  
                         if (!(MVequal(startMV, backupMV))) {  
                                 bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;  
   
                                 CheckCandidate16(startMV.x, startMV.y, 255, &iDirection, Data);  
                                 (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);  
                                 if (bSAD < Data->iMinSAD[0]) {  
                                         Data->currentMV[0] = backupMV;  
                                         Data->iMinSAD[0] = bSAD; }  
                         }  
2042    
2043                          backupMV = Data->currentMV[0];    if (MotionFlags & PMV_USESQUARES8)
2044                          if (MotionFlags & PMV_HALFPELREFINE16) startMV.x = startMV.y = 1;        MainSearchPtr = Square8_MainSearch;
2045                          else startMV.x = startMV.y = 0;    else
                         if (!(MVequal(startMV, backupMV))) {  
                                 bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;  
2046    
2047                                  CheckCandidate16(startMV.x, startMV.y, 255, &iDirection, Data);          if (MotionFlags & PMV_ADVANCEDDIAMOND8)
2048                                  (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);                  MainSearchPtr = AdvDiamond8_MainSearch;
2049                                  if (bSAD < Data->iMinSAD[0]) {          else
2050                                          Data->currentMV[0] = backupMV;                  MainSearchPtr = Diamond8_MainSearch;
                                         Data->iMinSAD[0] = bSAD; }  
                         }  
                 }  
         }  
2051    
         if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(Data);  
2052    
2053          for(i = 0; i < 5; i++) {          *currMV = startMV;
                 Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // initialize qpel vectors  
                 Data->currentQMV[i].y = 2 * Data->currentMV[i].y;  
         }  
2054    
2055          if((pParam->m_quarterpel) && (MotionFlags & PMV_QUARTERPELREFINE16)) {          iMinSAD =
2056                    sad8(cur,
2057                             get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,
2058                                                    iEdgedWidth), iEdgedWidth);
2059            iMinSAD +=
2060                    calc_delta_8(currMV->x - center_x, currMV->y - center_y,
2061                                             (uint8_t) iFcode, iQuant);
2062    
2063            if ((iMinSAD < 256 / 4) || ((MVequal(*currMV, prevMB->mvs[iSubBlock]))
2064                                                                    && ((int32_t) iMinSAD <
2065                                                                            prevMB->sad8[iSubBlock]))) {
2066                    if (MotionFlags & PMV_QUICKSTOP16)
2067                            goto PMVfast8_Terminate_without_Refine;
2068                    if (MotionFlags & PMV_EARLYSTOP16)
2069                            goto PMVfast8_Terminate_with_Refine;
2070            }
2071    
2072    /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion
2073       vector of the median.
2074       If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2
2075    */
2076    
2077            if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[iSubBlock])))
2078                    iFound = 2;
2079    
2080    /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.
2081       Otherwise select large Diamond Search.
2082    */
2083    
2084                  if(inter4v)          if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))
2085                          CheckCandidate = CheckCandidate16_qpel;                  iDiamondSize = 1;               // 1 halfpel!
2086                  else                  else
2087                          CheckCandidate = CheckCandidate16no4v_qpel;                  iDiamondSize = 2;               // 2 halfpel = 1 full pixel!
2088    
2089                          Data->iMinSAD[0] -= lambda_vec16[iQuant] *          if (!(MotionFlags & PMV_HALFPELDIAMOND8))
2090                                  d_mv_bits(Data->predMV.x - Data->currentMV[0].x, Data->predMV.y - Data->currentMV[0].y, Data->iFcode);                  iDiamondSize *= 2;
2091                          Data->iMinSAD[1] -= lambda_vec8[iQuant] *  
2092                                  d_mv_bits(Data->predMV.x - Data->currentMV[1].x, Data->predMV.y - Data->currentMV[1].y, Data->iFcode);  
2093    /*
2094                          Data->iMinSAD[0] += lambda_vec16[iQuant] *     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.
2095                                  d_mv_bits(Data->predQMV.x - Data->currentQMV[0].x, Data->predMV.y - Data->currentQMV[0].y, Data->iFcode);     Also calculate (0,0) but do not subtract offset.
2096                          Data->iMinSAD[1] += lambda_vec8[iQuant] *     Let MinSAD be the smallest SAD up to this point.
2097                                  d_mv_bits(Data->predQMV.x - Data->currentQMV[1].x, Data->predMV.y - Data->currentQMV[1].y, Data->iFcode);     If MV is (0,0) subtract offset.
2098    */
2099                          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,  
2100                                  pParam->width, pParam->height, Data->iFcode, 0);  // the median prediction might be even better than mv16
2101    
2102                  QuarterpelRefine(Data);          if (!MVequal(pmv[0], startMV))
2103          }                  CHECK_MV8_CANDIDATE(center_x, center_y);
2104    
2105          if (inter4v) {  // (0,0) if needed
2106                  SearchData Data8;          if (!MVzero(pmv[0]))
2107                  Data8.iFcode = Data->iFcode;                  if (!MVzero(startMV))
2108                  Data8.iQuant = Data->iQuant;                          CHECK_MV8_ZERO;
2109                  Data8.iEdgedWidth = Data->iEdgedWidth;  
2110                  Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);  // previous frame MV if needed
2111                  Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);          if (!MVzero(prevMB->mvs[iSubBlock]))
2112                  Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);                  if (!MVequal(prevMB->mvs[iSubBlock], startMV))
2113                  Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);                          if (!MVequal(prevMB->mvs[iSubBlock], pmv[0]))
2114          }                                  CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x,
2115                                                                            prevMB->mvs[iSubBlock].y);
2116          if (!(inter4v) ||  
2117                  (Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +          if ((iMinSAD <= threshA) ||
2118                          Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {                  (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&
2119  // INTER MODE                   ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {
2120                  pMB->mode = MODE_INTER;                  if (MotionFlags & PMV_QUICKSTOP16)
2121                  pMB->mvs[0] = pMB->mvs[1]                          goto PMVfast8_Terminate_without_Refine;
2122                          = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];                  if (MotionFlags & PMV_EARLYSTOP16)
2123                            goto PMVfast8_Terminate_with_Refine;
2124            }
2125    
2126    // left neighbour, if allowed and needed
2127            if (!MVzero(pmv[1]))
2128                    if (!MVequal(pmv[1], startMV))
2129                            if (!MVequal(pmv[1], prevMB->mvs[iSubBlock]))
2130                                    if (!MVequal(pmv[1], pmv[0])) {
2131                                            if (!(MotionFlags & PMV_HALFPEL8)) {
2132                                                    pmv[1].x = EVEN(pmv[1].x);
2133                                                    pmv[1].y = EVEN(pmv[1].y);
2134                                            }
2135                                            CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);
2136                                    }
2137    // top neighbour, if allowed and needed
2138            if (!MVzero(pmv[2]))
2139                    if (!MVequal(pmv[2], startMV))
2140                            if (!MVequal(pmv[2], prevMB->mvs[iSubBlock]))
2141                                    if (!MVequal(pmv[2], pmv[0]))
2142                                            if (!MVequal(pmv[2], pmv[1])) {
2143                                                    if (!(MotionFlags & PMV_HALFPEL8)) {
2144                                                            pmv[2].x = EVEN(pmv[2].x);
2145                                                            pmv[2].y = EVEN(pmv[2].y);
2146                                                    }
2147                                                    CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);
2148    
2149    // top right neighbour, if allowed and needed
2150                                                    if (!MVzero(pmv[3]))
2151                                                            if (!MVequal(pmv[3], startMV))
2152                                                                    if (!MVequal(pmv[3], prevMB->mvs[iSubBlock]))
2153                                                                            if (!MVequal(pmv[3], pmv[0]))
2154                                                                                    if (!MVequal(pmv[3], pmv[1]))
2155                                                                                            if (!MVequal(pmv[3], pmv[2])) {
2156                                                                                                    if (!
2157                                                                                                            (MotionFlags &
2158                                                                                                             PMV_HALFPEL8)) {
2159                                                                                                            pmv[3].x = EVEN(pmv[3].x);
2160                                                                                                            pmv[3].y = EVEN(pmv[3].y);
2161                                                                                                    }
2162                                                                                                    CHECK_MV8_CANDIDATE(pmv[3].x,
2163                                                                                                                                            pmv[3].y);
2164                                                                                            }
2165                                            }
2166    
2167            if ((MVzero(*currMV)) &&
2168                    (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )
2169                    iMinSAD -= MV8_00_BIAS;
2170    
2171    
2172    /* Step 6: If MinSAD <= thresa goto Step 10.
2173       If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.
2174    */
2175    
2176            if ((iMinSAD <= threshA) ||
2177                    (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&
2178                     ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {
2179                    if (MotionFlags & PMV_QUICKSTOP16)
2180                            goto PMVfast8_Terminate_without_Refine;
2181                    if (MotionFlags & PMV_EARLYSTOP16)
2182                            goto PMVfast8_Terminate_with_Refine;
2183            }
2184    
2185    /************ (Diamond Search)  **************/
2186    /*
2187       Step 7: Perform Diamond search, with either the small or large diamond.
2188       If Found=2 only examine one Diamond pattern, and afterwards goto step 10
2189       Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.
2190       If center then goto step 10.
2191       Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.
2192       Refine by using small diamond and goto step 10.
2193    */
2194    
2195            backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */
2196    
2197    /* default: use best prediction as starting point for one call of PMVfast_MainSearch */
2198            iSAD =
2199                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,
2200                                                      currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,
2201                                                      min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,
2202                                                      iQuant, iFound);
2203    
2204            if (iSAD < iMinSAD) {
2205                    *currMV = newMV;
2206                    iMinSAD = iSAD;
2207            }
2208    
2209                  pMB->qmvs[0] = pMB->qmvs[1]          if (MotionFlags & PMV_EXTSEARCH8) {
2210                          = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];  /* extended: search (up to) two more times: orignal prediction and (0,0) */
2211    
2212                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =                  if (!(MVequal(pmv[0], backupMV))) {
2213                          pMB->sad8[2] = pMB->sad8[3] =  Data->iMinSAD[0];                          iSAD =
2214                                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,
2215                                                                      pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,
2216                                                                      min_dx, max_dx, min_dy, max_dy, iEdgedWidth,
2217                                                                      iDiamondSize, iFcode, iQuant, iFound);
2218    
2219                  if(pParam->m_quarterpel) {                          if (iSAD < iMinSAD) {
2220                          pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predQMV.x;                                  *currMV = newMV;
2221                          pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predQMV.y;                                  iMinSAD = iSAD;
2222                  }                  }
                 else {  
                         pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;  
                         pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;  
2223                  }                  }
2224          } else {  
2225  // INTER4V MODE; all other things are already set in Search8                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {
2226                  pMB->mode = MODE_INTER4V;                          iSAD =
2227                  pMB->sad16 = Data->iMinSAD[1] + Data->iMinSAD[2] +                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,
2228                          Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * iQuant;                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,
2229                                                                      max_dy, iEdgedWidth, iDiamondSize, iFcode,
2230                                                                      iQuant, iFound);
2231    
2232                            if (iSAD < iMinSAD) {
2233                                    *currMV = newMV;
2234                                    iMinSAD = iSAD;
2235                            }
2236          }          }
2237  }  }
2238    
2239  static void  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.
2240  Search8(const SearchData * const OldData,     By performing an optional local half-pixel search, we can refine this result even further.
2241                  const int x, const int y,  */
2242    
2243      PMVfast8_Terminate_with_Refine:
2244            if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step
2245                    iMinSAD =
2246                            Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,
2247                                                            iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,
2248                                                            iFcode, iQuant, iEdgedWidth);
2249    
2250    
2251      PMVfast8_Terminate_without_Refine:
2252            currPMV->x = currMV->x - center_x;
2253            currPMV->y = currMV->y - center_y;
2254    
2255            return iMinSAD;
2256    }
2257    
2258    int32_t
2259    EPZSSearch16(const uint8_t * const pRef,
2260                             const uint8_t * const pRefH,
2261                             const uint8_t * const pRefV,
2262                             const uint8_t * const pRefHV,
2263                             const IMAGE * const pCur,
2264                             const int x,
2265                             const int y,
2266                            const int start_x,
2267                            const int start_y,
2268                            const int center_x,
2269                            const int center_y,
2270                  const uint32_t MotionFlags,                  const uint32_t MotionFlags,
2271                             const uint32_t iQuant,
2272                             const uint32_t iFcode,
2273                  const MBParam * const pParam,                  const MBParam * const pParam,
                 MACROBLOCK * const pMB,  
2274                  const MACROBLOCK * const pMBs,                  const MACROBLOCK * const pMBs,
2275                  const int block,                           const MACROBLOCK * const prevMBs,
2276                  SearchData * const Data)                           VECTOR * const currMV,
2277                             VECTOR * const currPMV)
2278  {  {
2279          Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2 , y/2, block);          const uint32_t iWcount = pParam->mb_width;
2280          Data->predQMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2 , y/2, block);          const uint32_t iHcount = pParam->mb_height;
         Data->iMinSAD = OldData->iMinSAD + 1 + block;  
         Data->currentMV = OldData->currentMV + 1 + block;  
         Data->currentQMV = OldData->currentQMV + 1 + block;  
   
         if(pParam->m_quarterpel) {  
                 //it is qpel. substract d_mv_bits[qpel] from 0, add d_mv_bits[hpel] everywhere  
                 if (block == 0)  
                         *(Data->iMinSAD) -= lambda_vec8[Data->iQuant] *  
                                                                         d_mv_bits(      Data->currentQMV->x - Data->predQMV.x,  
                                                                                                 Data->currentQMV->y - Data->predQMV.y,  
                                                                                                 Data->iFcode);  
   
                 *(Data->iMinSAD) += lambda_vec8[Data->iQuant] *  
                                                                         d_mv_bits(      Data->currentMV->x - Data->predMV.x,  
                                                                                                 Data->currentMV->y - Data->predMV.y,  
                                                                                                 Data->iFcode);  
         } else //it is not qpel. add d_mv_bits[hpel] everywhere but not in 0 (it's already there)  
                 if (block != 0) *(Data->iMinSAD) += lambda_vec8[Data->iQuant] *  
                                                                         d_mv_bits(      Data->currentMV->x - Data->predMV.x,  
                                                                                                 Data->currentMV->y - Data->predMV.y,  
                                                                                                 Data->iFcode);  
   
   
         if (MotionFlags & (PMV_EXTSEARCH8|PMV_HALFPELREFINE8)) {  
   
                 Data->Ref = OldData->Ref + 8 * ((block&1) + pParam->edged_width*(block>>1));  
                 Data->RefH = OldData->RefH + 8 * ((block&1) + pParam->edged_width*(block>>1));  
                 Data->RefV = OldData->RefV + 8 * ((block&1) + pParam->edged_width*(block>>1));  
                 Data->RefHV = OldData->RefHV + 8 * ((block&1) + pParam->edged_width*(block>>1));  
                 Data->RefQ = OldData->RefQ;  
2281    
2282                  Data->Cur = OldData->Cur + 8 * ((block&1) + pParam->edged_width*(block>>1));          const int32_t iWidth = pParam->width;
2283            const int32_t iHeight = pParam->height;
2284            const int32_t iEdgedWidth = pParam->edged_width;
2285    
2286                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;
                                 pParam->width, pParam->height, OldData->iFcode, pParam->m_quarterpel);  
2287    
2288                  CheckCandidate = CheckCandidate8;          int32_t min_dx;
2289            int32_t max_dx;
2290            int32_t min_dy;
2291            int32_t max_dy;
2292    
2293                  if (MotionFlags & PMV_EXTSEARCH8) {          VECTOR newMV;
2294                          int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD          VECTOR backupMV;
2295    
2296                          MainSearchFunc *MainSearchPtr;          VECTOR pmv[4];
2297                          if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;          int32_t psad[8];
                                 else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;  
                                         else MainSearchPtr = DiamondSearch;  
2298    
2299                          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);          static MACROBLOCK *oldMBs = NULL;
2300    
2301                          if(*(Data->iMinSAD) < temp_sad) {  //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;
2302                                          Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;
2303                                          Data->currentQMV->y = 2 * Data->currentMV->y;          MACROBLOCK *oldMB = NULL;
                         }  
                 }  
2304    
2305                  if (MotionFlags & PMV_HALFPELREFINE8) {           int32_t thresh2;
2306                          int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD          int32_t bPredEq;
2307            int32_t iMinSAD, iSAD = 9999;
2308    
2309                          HalfpelRefine(Data); // perform halfpel refine of current best vector          MainSearch16FuncPtr MainSearchPtr;
2310    
2311                          if(*(Data->iMinSAD) < temp_sad) { // we have found a better match          if (oldMBs == NULL) {
2312                                  Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector                  oldMBs = (MACROBLOCK *) calloc(iWcount * iHcount, sizeof(MACROBLOCK));
2313                                  Data->currentQMV->y = 2 * Data->currentMV->y;  //      fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));
                         }  
2314                  }                  }
2315            oldMB = oldMBs + x + y * iWcount;
2316    
2317                  if(pParam->m_quarterpel) {  /* Get maximum range */
2318                          if((!(Data->currentQMV->x & 1)) && (!(Data->currentQMV->y & 1)) &&          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,
2319                                  (MotionFlags & PMV_QUARTERPELREFINE8)) {                            iFcode);
2320    
2321                                  CheckCandidate = CheckCandidate8_qpel;          if (!(MotionFlags & PMV_HALFPEL16)) {
2322                          Data->iMinSAD[0] -= lambda_vec8[Data->iQuant] *                  min_dx = EVEN(min_dx);
2323                                  d_mv_bits(Data->predMV.x - Data->currentMV[0].x, Data->predMV.y - Data->currentMV[0].y, Data->iFcode);                  max_dx = EVEN(max_dx);
2324                    min_dy = EVEN(min_dy);
2325                    max_dy = EVEN(max_dy);
2326            }
2327            /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */
2328            //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);
2329            bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);
2330    
2331    /* Step 4: Calculate SAD around the Median prediction.
2332            MinSAD=SAD
2333            If Motion Vector equal to Previous frame motion vector
2334                    and MinSAD<PrevFrmSAD goto Step 10.
2335            If SAD<=256 goto Step 10.
2336    */
2337    
2338                          Data->iMinSAD[0] += lambda_vec8[Data->iQuant] *  // Prepare for main loop
                                 d_mv_bits(Data->predQMV.x - Data->currentQMV[0].x, Data->predQMV.y - Data->currentQMV[0].y, Data->iFcode);  
2339    
2340                                  QuarterpelRefine(Data);          currMV->x = start_x;
2341                          }          currMV->y = start_y;
                 }  
         }  
2342    
2343          if(pParam->m_quarterpel) {          if (!(MotionFlags & PMV_HALFPEL16)) {
2344                  pMB->pmvs[block].x = Data->currentQMV->x - Data->predQMV.x;                  currMV->x = EVEN(currMV->x);
2345                  pMB->pmvs[block].y = Data->currentQMV->y - Data->predQMV.y;                  currMV->y = EVEN(currMV->y);
         }  
         else {  
                 pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;  
                 pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;  
2346          }          }
2347    
2348          pMB->mvs[block] = *(Data->currentMV);          if (currMV->x > max_dx)
2349          pMB->qmvs[block] = *(Data->currentQMV);                  currMV->x = max_dx;
2350            if (currMV->x < min_dx)
2351                    currMV->x = min_dx;
2352            if (currMV->y > max_dy)
2353                    currMV->y = max_dy;
2354            if (currMV->y < min_dy)
2355                    currMV->y = min_dy;
2356    
2357    /***************** This is predictor SET A: only median prediction ******************/
2358    
2359            iMinSAD =
2360                    sad16(cur,
2361                              get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,
2362                                                     iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);
2363            iMinSAD +=
2364                    calc_delta_16(currMV->x - center_x, currMV->y - center_y,
2365                                              (uint8_t) iFcode, iQuant);
2366    
2367    // thresh1 is fixed to 256
2368            if ((iMinSAD < 256) ||
2369                    ((MVequal(*currMV, prevMB->mvs[0])) &&
2370                     ((int32_t) iMinSAD < prevMB->sad16))) {
2371                    if (MotionFlags & PMV_QUICKSTOP16)
2372                            goto EPZS16_Terminate_without_Refine;
2373                    if (MotionFlags & PMV_EARLYSTOP16)
2374                            goto EPZS16_Terminate_with_Refine;
2375            }
2376    
2377    /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/
2378    
2379          pMB->sad8[block] =  4 * (*Data->iMinSAD);  // previous frame MV
2380  }          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);
   
 /* B-frames code starts here */  
2381    
2382  static __inline VECTOR  // set threshhold based on Min of Prediction and SAD of collocated block
2383  ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)  // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want
 {  
 /* the stupidiest function ever */  
         if (mode == MODE_FORWARD) return pMB->mvs[0];  
         else return pMB->b_mvs[0];  
 }  
2384    
2385  static void __inline          if ((x == 0) && (y == 0)) {
2386  PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,                  thresh2 = 512;
2387                                                          const uint32_t iWcount,          } else {
2388                                                          const MACROBLOCK * const pMB,  /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */
                                                         const uint32_t mode_curr)  
 {  
2389    
2390          // [0] is prediction                  thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;
2391          pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);          }
2392    
2393          pmv[1].x = pmv[1].y = 0; // [1] is zero  // MV=(0,0) is often a good choice
2394    
2395          pmv[2] = ChoosePred(pMB, mode_curr);          CHECK_MV16_ZERO;
         pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);  
2396    
         if ((y != 0)&&(x != (int)(iWcount+1))) {                        // [3] top-right neighbour  
                 pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);  
                 pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);  
         } else pmv[3].x = pmv[3].y = 0;  
2397    
2398    // left neighbour, if allowed
2399            if (x != 0) {
2400                    if (!(MotionFlags & PMV_HALFPEL16)) {
2401                            pmv[1].x = EVEN(pmv[1].x);
2402                            pmv[1].y = EVEN(pmv[1].y);
2403                    }
2404                    CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);
2405            }
2406    // top neighbour, if allowed
2407          if (y != 0) {          if (y != 0) {
2408                  pmv[4] = ChoosePred(pMB-iWcount, mode_curr);                  if (!(MotionFlags & PMV_HALFPEL16)) {
2409                  pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);                          pmv[2].x = EVEN(pmv[2].x);
2410          } else pmv[4].x = pmv[4].y = 0;                          pmv[2].y = EVEN(pmv[2].y);
2411                    }
2412                    CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);
2413    
2414          if (x != 0) {  // top right neighbour, if allowed
2415                  pmv[5] = ChoosePred(pMB-1, mode_curr);                  if ((uint32_t) x != (iWcount - 1)) {
2416                  pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);                          if (!(MotionFlags & PMV_HALFPEL16)) {
2417          } else pmv[5].x = pmv[5].y = 0;                                  pmv[3].x = EVEN(pmv[3].x);
2418                                    pmv[3].y = EVEN(pmv[3].y);
2419                            }
2420                            CHECK_MV16_CANDIDATE(pmv[3].x, pmv[3].y);
2421                    }
2422            }
2423    
2424          if ((x != 0)&&(y != 0)) {  /* Terminate if MinSAD <= T_2
2425                  pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]
2426                  pmv[6].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);  */
         } else pmv[6].x = pmv[6].y = 0;  
2427    
2428  // more?          if ((iMinSAD <= thresh2)
2429                    || (MVequal(*currMV, prevMB->mvs[0]) &&
2430                            ((int32_t) iMinSAD <= prevMB->sad16))) {
2431                    if (MotionFlags & PMV_QUICKSTOP16)
2432                            goto EPZS16_Terminate_without_Refine;
2433                    if (MotionFlags & PMV_EARLYSTOP16)
2434                            goto EPZS16_Terminate_with_Refine;
2435  }  }
2436    
2437    /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/
2438    
2439  /* search backward or forward, for b-frames */          backupMV = prevMB->mvs[0];      // collocated MV
2440  static void          backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x);     // acceleration X
2441  SearchBF(       const uint8_t * const pRef,          backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y);     // acceleration Y
                         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 iFcode,  
                         const MBParam * const pParam,  
                         MACROBLOCK * const pMB,  
                         const VECTOR * const predMV,  
                         int32_t * const best_sad,  
                         const int32_t mode_current,  
                         SearchData * const Data)  
 {  
2442    
2443          const int32_t iEdgedWidth = pParam->edged_width;          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y);
2444    
2445          int i, iDirection, mask;  // left neighbour
2446          VECTOR pmv[7];          if (x != 0)
2447          MainSearchFunc *MainSearchPtr;                  CHECK_MV16_CANDIDATE((prevMB - 1)->mvs[0].x, (prevMB - 1)->mvs[0].y);
         *Data->iMinSAD = MV_MAX_ERROR;  
         Data->iFcode = iFcode;  
2448    
2449          Data->Ref = pRef + (x + y * iEdgedWidth) * 16;  // top neighbour
2450          Data->RefH = pRefH + (x + y * iEdgedWidth) * 16;          if (y != 0)
2451          Data->RefV = pRefV + (x + y * iEdgedWidth) * 16;                  CHECK_MV16_CANDIDATE((prevMB - iWcount)->mvs[0].x,
2452          Data->RefHV = pRefHV + (x + y * iEdgedWidth) * 16;                                                           (prevMB - iWcount)->mvs[0].y);
2453    
2454          Data->predMV = *predMV;  // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs
2455    
2456          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,          if ((uint32_t) x != iWcount - 1)
2457                                  pParam->width, pParam->height, iFcode, pParam->m_quarterpel);                  CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);
2458    
2459          pmv[0] = Data->predMV;  // bottom neighbour, dito
2460          PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);          if ((uint32_t) y != iHcount - 1)
2461                    CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,
2462                                                             (prevMB + iWcount)->mvs[0].y);
2463    
2464          Data->currentMV->x = Data->currentMV->y = 0;  /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */
2465            if (iMinSAD <= thresh2) {
2466                    if (MotionFlags & PMV_QUICKSTOP16)
2467                            goto EPZS16_Terminate_without_Refine;
2468                    if (MotionFlags & PMV_EARLYSTOP16)
2469                            goto EPZS16_Terminate_with_Refine;
2470            }
2471    
2472          CheckCandidate = CheckCandidate16no4v;  /************ (if Diamond Search)  **************/
2473    
2474  // main loop. checking all predictions          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */
         for (i = 0; i < 8; i++) {  
                 if (!(mask = make_mask(pmv, i)) ) continue;  
                 CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, Data);  
         }  
2475    
2476          if (MotionFlags & PMV_USESQUARES16)          if (MotionFlags & PMV_USESQUARES16)
2477                  MainSearchPtr = SquareSearch;                  MainSearchPtr = Square16_MainSearch;
2478          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)          else
2479                  MainSearchPtr = AdvDiamondSearch;           if (MotionFlags & PMV_ADVANCEDDIAMOND16)
2480                  else MainSearchPtr = DiamondSearch;                  MainSearchPtr = AdvDiamond16_MainSearch;
2481            else
2482                    MainSearchPtr = Diamond16_MainSearch;
2483    
2484          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */
2485    
2486          HalfpelRefine(Data);          iSAD =
2487                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,
2488                                                      currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,
2489                                                      min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);
2490    
2491            if (iSAD < iMinSAD) {
2492                    *currMV = newMV;
2493                    iMinSAD = iSAD;
2494            }
2495    
 // three bits are needed to code backward mode. four for forward  
 // we treat the bits just like they were vector's  
         if (mode_current == MODE_FORWARD) *Data->iMinSAD +=  4 * lambda_vec16[Data->iQuant];  
         else *Data->iMinSAD +=  3 * lambda_vec16[Data->iQuant];  
2496    
2497            if (MotionFlags & PMV_EXTSEARCH16) {
2498    /* extended mode: search (up to) two more times: orignal prediction and (0,0) */
2499    
2500          if (*Data->iMinSAD < *best_sad) {                  if (!(MVequal(pmv[0], backupMV))) {
2501                  *best_sad = *Data->iMinSAD;                          iSAD =
2502                  pMB->mode = mode_current;                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,
2503                  pMB->pmvs[0].x = Data->currentMV->x - predMV->x;                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,
2504                  pMB->pmvs[0].y = Data->currentMV->y - predMV->y;                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,
2505                  if (mode_current == MODE_FORWARD) pMB->mvs[0] = *Data->currentMV;                                                                    2, iFcode, iQuant, 0);
                 else pMB->b_mvs[0] = *Data->currentMV;  
2506          }          }
2507    
2508                    if (iSAD < iMinSAD) {
2509                            *currMV = newMV;
2510                            iMinSAD = iSAD;
2511  }  }
2512    
2513  static int32_t                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {
2514  SearchDirect(const IMAGE * const f_Ref,                          iSAD =
2515                                  const uint8_t * const f_RefH,                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,
2516                                  const uint8_t * const f_RefV,                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,
2517                                  const uint8_t * const f_RefHV,                                                                    max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);
2518                                  const IMAGE * const b_Ref,  
2519                                  const uint8_t * const b_RefH,                          if (iSAD < iMinSAD) {
2520                                  const uint8_t * const b_RefV,                                  *currMV = newMV;
2521                                  const uint8_t * const b_RefHV,                                  iMinSAD = iSAD;
                                 const IMAGE * const pCur,  
                                 const int x, const int y,  
                                 const uint32_t MotionFlags,  
                                 const int32_t TRB, const int32_t TRD,  
                                 const MBParam * const pParam,  
                                 MACROBLOCK * const pMB,  
                                 const MACROBLOCK * const b_mb,  
                                 int32_t * const best_sad,  
                                 SearchData * const Data)  
   
 {  
         int32_t skip_sad;  
         int k;  
   
         MainSearchFunc *MainSearchPtr;  
   
         *Data->iMinSAD = 256*4096;  
         Data->referencemv = b_mb->mvs;  
   
         Data->Ref = f_Ref->y + (x + Data->iEdgedWidth*y) * 16;  
         Data->RefH = f_RefH + (x + Data->iEdgedWidth*y) * 16;  
         Data->RefV = f_RefV + (x + Data->iEdgedWidth*y) * 16;  
         Data->RefHV = f_RefHV + (x + Data->iEdgedWidth*y) * 16;  
         Data->bRef = b_Ref->y + (x + Data->iEdgedWidth*y) * 16;  
         Data->bRefH = b_RefH + (x + Data->iEdgedWidth*y) * 16;  
         Data->bRefV = b_RefV + (x + Data->iEdgedWidth*y) * 16;  
         Data->bRefHV = b_RefHV + (x + Data->iEdgedWidth*y) * 16;  
   
         Data->max_dx = 2 * pParam->width - 2 * (x) * 16;  
         Data->max_dy = 2 * pParam->height - 2 * (y) * 16;  
         Data->min_dx = -(2 * 16 + 2 * (x) * 16);  
         Data->min_dy = -(2 * 16 + 2 * (y) * 16);  
   
         for (k = 0; k < 4; k++) {  
                 pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);  
                 pMB->b_mvs[k].x = Data->directmvB[k].x = ((TRB - TRD) * Data->referencemv[k].x) / TRD;  
                 pMB->mvs[k].y = Data->directmvF[k].y = ((TRB * Data->referencemv[k].y) / TRD);  
                 pMB->b_mvs[k].y = Data->directmvB[k].y = ((TRB - TRD) * Data->referencemv[k].y) / TRD;  
   
                 if ( ( pMB->b_mvs[k].x > Data->max_dx ) || ( pMB->b_mvs[k].x < Data->min_dx )  
                         || ( pMB->b_mvs[k].y > Data->max_dy ) || ( pMB->b_mvs[k].y < Data->min_dy )) {  
   
                         *best_sad = 256*4096; // in that case, we won't use direct mode  
                         pMB->mode = MODE_DIRECT; // just to make sure it doesn't say "MODE_DIRECT_NONE_MV"  
                         pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;  
                         return 0;  
2522                  }                  }
                 if (b_mb->mode != MODE_INTER4V) {  
                         pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mvs[0];  
                         pMB->b_mvs[1] = pMB->b_mvs[2] = pMB->b_mvs[3] = pMB->b_mvs[0];  
                         Data->directmvF[1] = Data->directmvF[2] = Data->directmvF[3] = Data->directmvF[0];  
                         Data->directmvB[1] = Data->directmvB[2] = Data->directmvB[3] = Data->directmvB[0];  
                         break;  
2523                  }                  }
2524          }          }
2525    
2526          if (b_mb->mode == MODE_INTER4V)  /***************        Choose best MV found     **************/
                 CheckCandidate = CheckCandidateDirect;  
         else CheckCandidate = CheckCandidateDirectno4v;  
2527    
2528          (*CheckCandidate)(0, 0, 255, &k, Data);    EPZS16_Terminate_with_Refine:
2529            if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step
2530                    iMinSAD =
2531                            Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,
2532                                                             iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,
2533                                                             iFcode, iQuant, iEdgedWidth);
2534    
2535  // skip decision    EPZS16_Terminate_without_Refine:
         if (*Data->iMinSAD - 2 * lambda_vec16[Data->iQuant] < (int32_t)Data->iQuant * SKIP_THRESH_B) {  
                 //possible skip - checking chroma. everything copied from MC  
                 //this is not full chroma compensation, only it's fullpel approximation. should work though  
                 int sum, dx, dy, b_dx, b_dy;  
2536    
2537                  sum = pMB->mvs[0].x + pMB->mvs[1].x + pMB->mvs[2].x + pMB->mvs[3].x;          *oldMB = *prevMB;
                 dx = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));  
2538    
2539                  sum = pMB->mvs[0].y + pMB->mvs[1].y + pMB->mvs[2].y + pMB->mvs[3].y;          currPMV->x = currMV->x - center_x;
2540                  dy = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));          currPMV->y = currMV->y - center_y;
2541            return iMinSAD;
2542                  sum = pMB->b_mvs[0].x + pMB->b_mvs[1].x + pMB->b_mvs[2].x + pMB->b_mvs[3].x;  }
                 b_dx = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));  
   
                 sum = pMB->b_mvs[0].y + pMB->b_mvs[1].y + pMB->b_mvs[2].y + pMB->b_mvs[3].y;  
                 b_dy = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));  
2543    
                 sum = sad8bi(pCur->u + 8*x + 8*y*(Data->iEdgedWidth/2),  
                                         f_Ref->u + (y*8 + dy/2) * (Data->iEdgedWidth/2) + x*8 + dx/2,  
                                         b_Ref->u + (y*8 + b_dy/2) * (Data->iEdgedWidth/2) + x*8 + b_dx/2,  
                                         Data->iEdgedWidth/2);  
                 sum += sad8bi(pCur->v + 8*x + 8*y*(Data->iEdgedWidth/2),  
                                         f_Ref->v + (y*8 + dy/2) * (Data->iEdgedWidth/2) + x*8 + dx/2,  
                                         b_Ref->v + (y*8 + b_dy/2) * (Data->iEdgedWidth/2) + x*8 + b_dx/2,  
                                         Data->iEdgedWidth/2);  
2544    
2545                  if ((uint32_t) sum < MAX_CHROMA_SAD_FOR_SKIP * Data->iQuant) {  int32_t
2546                          pMB->mode = MODE_DIRECT_NONE_MV;  EPZSSearch8(const uint8_t * const pRef,
2547                          return *Data->iMinSAD;                          const uint8_t * const pRefH,
2548                  }                          const uint8_t * const pRefV,
2549          }                          const uint8_t * const pRefHV,
2550                            const IMAGE * const pCur,
2551                            const int x,
2552                            const int y,
2553                            const int start_x,
2554                            const int start_y,
2555                            const int center_x,
2556                            const int center_y,
2557                            const uint32_t MotionFlags,
2558                            const uint32_t iQuant,
2559                            const uint32_t iFcode,
2560                            const MBParam * const pParam,
2561                            const MACROBLOCK * const pMBs,
2562                            const MACROBLOCK * const prevMBs,
2563                            VECTOR * const currMV,
2564                            VECTOR * const currPMV)
2565    {
2566    /* Please not that EPZS might not be a good choice for 8x8-block motion search ! */
2567    
2568          skip_sad = *Data->iMinSAD;          const uint32_t iWcount = pParam->mb_width;
2569            const int32_t iWidth = pParam->width;
2570            const int32_t iHeight = pParam->height;
2571            const int32_t iEdgedWidth = pParam->edged_width;
2572    
2573  //  DIRECT MODE DELTA VECTOR SEARCH.          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;
 //      This has to be made more effective, but at the moment I'm happy it's running at all  
2574    
2575          if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;          int32_t iDiamondSize = 1;
                 else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;  
                         else MainSearchPtr = DiamondSearch;  
2576    
2577          (*MainSearchPtr)(0, 0, Data, 255);          int32_t min_dx;
2578            int32_t max_dx;
2579            int32_t min_dy;
2580            int32_t max_dy;
2581    
2582          HalfpelRefine(Data);          VECTOR newMV;
2583            VECTOR backupMV;
2584    
2585          *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          VECTOR pmv[4];
2586          *best_sad = *Data->iMinSAD;          int32_t psad[8];
2587    
2588          if (b_mb->mode == MODE_INTER4V)          const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);
                 pMB->mode = MODE_DIRECT;  
         else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation  
2589    
2590          pMB->pmvs[3] = *Data->currentMV;  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;
2591            const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;
2592    
2593          for (k = 0; k < 4; k++) {          int32_t bPredEq;
2594                  pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;          int32_t iMinSAD, iSAD = 9999;
                 pMB->b_mvs[k].x = ((Data->currentMV->x == 0)  
                                                         ? Data->directmvB[k].x  
                                                         : pMB->mvs[k].x - Data->referencemv[k].x);  
                 pMB->mvs[k].y = (Data->directmvF[k].y + Data->currentMV->y);  
                 pMB->b_mvs[k].y = ((Data->currentMV->y == 0)  
                                                         ? Data->directmvB[k].y  
                                                         : pMB->mvs[k].y - Data->referencemv[k].y);  
                 if (b_mb->mode != MODE_INTER4V) {  
                         pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];  
                         pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];  
                         break;  
                 }  
         }  
         return skip_sad;  
 }  
2595    
2596            MainSearch8FuncPtr MainSearchPtr;
2597    
2598  static __inline void  /* Get maximum range */
2599  SearchInterpolate(const uint8_t * const f_Ref,          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,
2600                                  const uint8_t * const f_RefH,                            iFcode);
                                 const uint8_t * const f_RefV,  
                                 const uint8_t * const f_RefHV,  
                                 const uint8_t * const b_Ref,  
                                 const uint8_t * const b_RefH,  
                                 const uint8_t * const b_RefV,  
                                 const uint8_t * const b_RefHV,  
                                 const IMAGE * const pCur,  
                                 const int x, const int y,  
                                 const uint32_t fcode,  
                                 const uint32_t bcode,  
                                 const uint32_t MotionFlags,  
                                 const MBParam * const pParam,  
                                 const VECTOR * const f_predMV,  
                                 const VECTOR * const b_predMV,  
                                 MACROBLOCK * const pMB,  
                                 int32_t * const best_sad,  
                                 SearchData * const fData)  
2601    
2602  {  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */
2603    
2604          const int32_t iEdgedWidth = pParam->edged_width;          if (!(MotionFlags & PMV_HALFPEL8)) {
2605                    min_dx = EVEN(min_dx);
2606                    max_dx = EVEN(max_dx);
2607                    min_dy = EVEN(min_dy);
2608                    max_dy = EVEN(max_dy);
2609            }
2610            /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */
2611            //bPredEq = get_pmvdata(pMBs, x >> 1, y >> 1, iWcount, iSubBlock, pmv[0].x, pmv[0].y, psad);
2612            bPredEq = get_pmvdata2(pMBs, iWcount, 0, x >> 1, y >> 1, iSubBlock, pmv, psad);
2613    
         int iDirection, i, j;  
         SearchData bData;  
2614    
2615          bData.iMinSAD = fData->iMinSAD;  /* Step 4: Calculate SAD around the Median prediction.
2616          *bData.iMinSAD = 4096*256;          MinSAD=SAD
2617          bData.Cur = fData->Cur;          If Motion Vector equal to Previous frame motion vector
2618          fData->iEdgedWidth = bData.iEdgedWidth = iEdgedWidth;                  and MinSAD<PrevFrmSAD goto Step 10.
2619          bData.currentMV = fData->currentMV + 1;          If SAD<=256 goto Step 10.
2620          bData.iQuant = fData->iQuant;  */
         fData->iFcode = bData.bFcode = fcode; fData->bFcode = bData.iFcode = bcode;  
   
         bData.bRef = fData->Ref = f_Ref + (x + y * iEdgedWidth) * 16;  
         bData.bRefH = fData->RefH = f_RefH + (x + y * iEdgedWidth) * 16;  
         bData.bRefV = fData->RefV = f_RefV + (x + y * iEdgedWidth) * 16;  
         bData.bRefHV = fData->RefHV = f_RefHV + (x + y * iEdgedWidth) * 16;  
         bData.Ref = fData->bRef = b_Ref + (x + y * iEdgedWidth) * 16;  
         bData.RefH = fData->bRefH = b_RefH + (x + y * iEdgedWidth) * 16;  
         bData.RefV = fData->bRefV = b_RefV + (x + y * iEdgedWidth) * 16;  
         bData.RefHV = fData->bRefHV = b_RefHV + (x + y * iEdgedWidth) * 16;  
   
         bData.bpredMV = fData->predMV = *f_predMV;  
         fData->bpredMV = bData.predMV = *b_predMV;  
   
         fData->currentMV[0] = pMB->mvs[0];  
         fData->currentMV[1] = pMB->b_mvs[0];  
         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);  
         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);  
   
         if (fData->currentMV[0].x > fData->max_dx) fData->currentMV[0].x = fData->max_dx;  
         if (fData->currentMV[0].x < fData->min_dx) fData->currentMV[0].x = fData->min_dy;  
         if (fData->currentMV[0].y > fData->max_dy) fData->currentMV[0].y = fData->max_dx;  
         if (fData->currentMV[0].y > fData->min_dy) fData->currentMV[0].y = fData->min_dy;  
   
         if (fData->currentMV[1].x > bData.max_dx) fData->currentMV[1].x = bData.max_dx;  
         if (fData->currentMV[1].x < bData.min_dx) fData->currentMV[1].x = bData.min_dy;  
         if (fData->currentMV[1].y > bData.max_dy) fData->currentMV[1].y = bData.max_dx;  
         if (fData->currentMV[1].y > bData.min_dy) fData->currentMV[1].y = bData.min_dy;  
2621    
2622          CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, 255, &iDirection, fData);  // Prepare for main loop
2623    
 //diamond. I wish we could use normal mainsearch functions (square, advdiamond)  
2624    
2625          do {          if (!(MotionFlags & PMV_HALFPEL8)) {
2626                  iDirection = 255;                  currMV->x = EVEN(currMV->x);
2627                  // forward MV moves                  currMV->y = EVEN(currMV->y);
                 i = fData->currentMV[0].x; j = fData->currentMV[0].y;  
   
                 CheckCandidateInt(i + 1, j, 0, &iDirection, fData);  
                 CheckCandidateInt(i, j + 1, 0, &iDirection, fData);  
                 CheckCandidateInt(i - 1, j, 0, &iDirection, fData);  
                 CheckCandidateInt(i, j - 1, 0, &iDirection, fData);  
   
                 // backward MV moves  
                 i = fData->currentMV[1].x; j = fData->currentMV[1].y;  
                 fData->currentMV[2] = fData->currentMV[0];  
   
                 CheckCandidateInt(i + 1, j, 0, &iDirection, &bData);  
                 CheckCandidateInt(i, j + 1, 0, &iDirection, &bData);  
                 CheckCandidateInt(i - 1, j, 0, &iDirection, &bData);  
                 CheckCandidateInt(i, j - 1, 0, &iDirection, &bData);  
   
         } while (!(iDirection));  
   
 // two bits are needed to code interpolate mode. we treat the bits just like they were vector's  
         *fData->iMinSAD +=  2 * lambda_vec16[fData->iQuant];  
         if (*fData->iMinSAD < *best_sad) {  
                 *best_sad = *fData->iMinSAD;  
                 pMB->mvs[0] = fData->currentMV[0];  
                 pMB->b_mvs[0] = fData->currentMV[1];  
                 pMB->mode = MODE_INTERPOLATE;  
   
                 pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;  
                 pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;  
                 pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;  
                 pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;  
         }  
2628  }  }
2629    
2630            if (currMV->x > max_dx)
2631                    currMV->x = max_dx;
2632            if (currMV->x < min_dx)
2633                    currMV->x = min_dx;
2634            if (currMV->y > max_dy)
2635                    currMV->y = max_dy;
2636            if (currMV->y < min_dy)
2637                    currMV->y = min_dy;
2638    
2639  void  /***************** This is predictor SET A: only median prediction ******************/
 MotionEstimationBVOP(MBParam * const pParam,  
                                          FRAMEINFO * const frame,  
                                          const int32_t time_bp,  
                                          const int32_t time_pp,  
                                          // forward (past) reference  
                                          const MACROBLOCK * const f_mbs,  
                                          const IMAGE * const f_ref,  
                                          const IMAGE * const f_refH,  
                                          const IMAGE * const f_refV,  
                                          const IMAGE * const f_refHV,  
                                          // backward (future) reference  
                                          const MACROBLOCK * const b_mbs,  
                                          const IMAGE * const b_ref,  
                                          const IMAGE * const b_refH,  
                                          const IMAGE * const b_refV,  
                                          const IMAGE * const b_refHV)  
 {  
         uint32_t i, j;  
         int32_t best_sad, skip_sad;  
         int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;  
         static const VECTOR zeroMV={0,0};  
2640    
         VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/  
2641    
2642          const int32_t TRB = time_pp - time_bp;          iMinSAD =
2643          const int32_t TRD = time_pp;                  sad8(cur,
2644                             get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,
2645                                                    iEdgedWidth), iEdgedWidth);
2646            iMinSAD +=
2647                    calc_delta_8(currMV->x - center_x, currMV->y - center_y,
2648                                             (uint8_t) iFcode, iQuant);
2649    
 // some pre-inintialized data for the rest of the search  
2650    
2651          SearchData Data;  // thresh1 is fixed to 256
2652          int32_t iMinSAD;          if (iMinSAD < 256 / 4) {
2653          VECTOR currentMV[3];                  if (MotionFlags & PMV_QUICKSTOP8)
2654          Data.iEdgedWidth = pParam->edged_width;                          goto EPZS8_Terminate_without_Refine;
2655          Data.currentMV = currentMV;                  if (MotionFlags & PMV_EARLYSTOP8)
2656          Data.iMinSAD = &iMinSAD;                          goto EPZS8_Terminate_with_Refine;
2657          Data.iQuant = frame->quant;          }
2658    
2659          // note: i==horizontal, j==vertical  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/
2660    
         for (j = 0; j < pParam->mb_height; j++) {  
2661    
2662                  f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */  // MV=(0,0) is often a good choice
2663            CHECK_MV8_ZERO;
2664    
2665                  for (i = 0; i < pParam->mb_width; i++) {  // previous frame MV
2666                          MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;          CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x, prevMB->mvs[iSubBlock].y);
                         const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;  
2667    
2668  /* special case, if collocated block is SKIPed: encoding is forward (0,0), cpb=0 without further ado */  // left neighbour, if allowed
2669                          if (b_mb->mode == MODE_NOT_CODED) {          if (psad[1] != MV_MAX_ERROR) {
2670                                  pMB->mode = MODE_NOT_CODED;                  if (!(MotionFlags & PMV_HALFPEL8)) {
2671                                  continue;                          pmv[1].x = EVEN(pmv[1].x);
2672                            pmv[1].y = EVEN(pmv[1].y);
2673                    }
2674                    CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);
2675                          }                          }
2676    // top neighbour, if allowed
2677            if (psad[2] != MV_MAX_ERROR) {
2678                    if (!(MotionFlags & PMV_HALFPEL8)) {
2679                            pmv[2].x = EVEN(pmv[2].x);
2680                            pmv[2].y = EVEN(pmv[2].y);
2681                    }
2682                    CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);
2683    
2684                          Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;  // top right neighbour, if allowed
2685  /* direct search comes first, because it (1) checks for SKIP-mode                  if (psad[3] != MV_MAX_ERROR) {
2686          and (2) sets very good predictions for forward and backward search */                          if (!(MotionFlags & PMV_HALFPEL8)) {
2687                                    pmv[3].x = EVEN(pmv[3].x);
2688                          skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,                                  pmv[3].y = EVEN(pmv[3].y);
                                                                         b_ref, b_refH->y, b_refV->y, b_refHV->y,  
                                                                         &frame->image,  
                                                                         i, j,  
                                                                         frame->motion_flags,  
                                                                         TRB, TRD,  
                                                                         pParam,  
                                                                         pMB, b_mb,  
                                                                         &best_sad,  
                                                                         &Data);  
   
                         if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }  
   
 //                      best_sad = 256*4096; //uncomment to disable Directsearch.  
 //      To disable any other mode, just comment the function call  
   
                         // forward search  
                         SearchBF(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 &frame->image, i, j,  
                                                 frame->motion_flags,  
                                                 frame->fcode, pParam,  
                                                 pMB, &f_predMV, &best_sad,  
                                                 MODE_FORWARD, &Data);  
   
                         // backward search  
                         SearchBF(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 &frame->image, i, j,  
                                                 frame->motion_flags,  
                                                 frame->bcode, pParam,  
                                                 pMB, &b_predMV, &best_sad,  
                                                 MODE_BACKWARD, &Data);  
   
                         // interpolate search comes last, because it uses data from forward and backward as prediction  
   
                         SearchInterpolate(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 &frame->image,  
                                                 i, j,  
                                                 frame->fcode, frame->bcode,  
                                                 frame->motion_flags,  
                                                 pParam,  
                                                 &f_predMV, &b_predMV,  
                                                 pMB, &best_sad,  
                                                 &Data);  
   
                         switch (pMB->mode) {  
                                 case MODE_FORWARD:  
                                         f_count++;  
                                         f_predMV = pMB->mvs[0];  
                                         break;  
                                 case MODE_BACKWARD:  
                                         b_count++;  
                                         b_predMV = pMB->b_mvs[0];  
                                         break;  
                                 case MODE_INTERPOLATE:  
                                         i_count++;  
                                         f_predMV = pMB->mvs[0];  
                                         b_predMV = pMB->b_mvs[0];  
                                         break;  
                                 case MODE_DIRECT:  
                                 case MODE_DIRECT_NO4V:  
                                         d_count++;  
                                         break;  
                                 default:  
                                         break;  
2689                          }                          }
2690                            CHECK_MV8_CANDIDATE(pmv[3].x, pmv[3].y);
2691                  }                  }
2692          }          }
2693    
2694  //      fprintf(debug,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d, N: %04d\n",  /*  // this bias is zero anyway, at the moment!
 //                              f_count,b_count,i_count,d_count,n_count);  
2695    
2696  }          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)
2697                    iMinSAD -= MV8_00_BIAS;
2698    
2699  /* Hinted ME starts here */  */
2700    
2701  static void  /* Terminate if MinSAD <= T_2
2702  Search8hinted(const SearchData * const OldData,     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]
2703                  const int x, const int y,  */
2704                  const uint32_t MotionFlags,  
2705                  const MBParam * const pParam,          if (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */
2706                  MACROBLOCK * const pMB,                  if (MotionFlags & PMV_QUICKSTOP8)
2707                  const MACROBLOCK * const pMBs,                          goto EPZS8_Terminate_without_Refine;
2708                  const int block,                  if (MotionFlags & PMV_EARLYSTOP8)
2709                  SearchData * const Data)                          goto EPZS8_Terminate_with_Refine;
 {  
         int32_t temp_sad;  
         MainSearchFunc *MainSearchPtr;  
         Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2 , y/2, block);  
         Data->predQMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2 , y/2, block);  
         Data->iMinSAD = OldData->iMinSAD + 1 + block;  
         Data->currentMV = OldData->currentMV + 1 + block;  
         Data->currentQMV = OldData->currentQMV + 1 + block;  
   
         if (block != 0) {  
                 if(pParam->m_quarterpel) {  
                         *(Data->iMinSAD) += lambda_vec8[Data->iQuant] *  
                                                                         d_mv_bits(      Data->currentQMV->x - Data->predQMV.x,  
                                                                                                 Data->currentQMV->y - Data->predQMV.y,  
                                                                                                 Data->iFcode);  
                 }  
                 else {  
                         *(Data->iMinSAD) += lambda_vec8[Data->iQuant] *  
                                                                         d_mv_bits(      Data->currentMV->x - Data->predMV.x,  
                                                                                                 Data->currentMV->y - Data->predMV.y,  
                                                                                                 Data->iFcode);  
                 }  
2710          }          }
2711    
2712    /************ (Diamond Search)  **************/
2713    
2714          Data->Ref = OldData->Ref + 8 * ((block&1) + pParam->edged_width*(block>>1));          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */
         Data->RefH = OldData->RefH + 8 * ((block&1) + pParam->edged_width*(block>>1));  
         Data->RefV = OldData->RefV + 8 * ((block&1) + pParam->edged_width*(block>>1));  
         Data->RefHV = OldData->RefHV + 8 * ((block&1) + pParam->edged_width*(block>>1));  
         Data->RefQ = OldData->RefQ;  
2715    
2716          Data->Cur = OldData->Cur + 8 * ((block&1) + pParam->edged_width*(block>>1));          if (!(MotionFlags & PMV_HALFPELDIAMOND8))
2717                    iDiamondSize *= 2;
2718    
2719          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,  /* default: use best prediction as starting point for one call of EPZS_MainSearch */
                                 pParam->width, pParam->height, OldData->iFcode, pParam->m_quarterpel);  
2720    
2721          CheckCandidate = CheckCandidate8;  // there is no EPZS^2 for inter4v at the moment
2722    
2723      if (MotionFlags & PMV_USESQUARES8)
2724          MainSearchPtr = Square8_MainSearch;
2725      else
2726    
2727          temp_sad = *(Data->iMinSAD); // store current MinSAD          if (MotionFlags & PMV_ADVANCEDDIAMOND8)
2728                    MainSearchPtr = AdvDiamond8_MainSearch;
2729            else
2730                    MainSearchPtr = Diamond8_MainSearch;
2731    
2732          if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;          iSAD =
2733                  else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,
2734                          else MainSearchPtr = DiamondSearch;                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,
2735                                                      min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,
2736                                                      iQuant, 0);
2737    
         (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);  
2738    
2739          if(*(Data->iMinSAD) < temp_sad) {          if (iSAD < iMinSAD) {
2740                  Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector                  *currMV = newMV;
2741                  Data->currentQMV->y = 2 * Data->currentMV->y;                  iMinSAD = iSAD;
2742          }          }
2743    
2744          if (MotionFlags & PMV_HALFPELREFINE8) {          if (MotionFlags & PMV_EXTSEARCH8) {
2745                  temp_sad = *(Data->iMinSAD); // store current MinSAD  /* extended mode: search (up to) two more times: orignal prediction and (0,0) */
2746    
2747                  HalfpelRefine(Data); // perform halfpel refine of current best vector                  if (!(MVequal(pmv[0], backupMV))) {
2748                            iSAD =
2749                                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,
2750                                                                      pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,
2751                                                                      min_dx, max_dx, min_dy, max_dy, iEdgedWidth,
2752                                                                      iDiamondSize, iFcode, iQuant, 0);
2753    
2754                  if(*(Data->iMinSAD) < temp_sad) { // we have found a better match                          if (iSAD < iMinSAD) {
2755                          Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector                                  *currMV = newMV;
2756                          Data->currentQMV->y = 2 * Data->currentMV->y;                                  iMinSAD = iSAD;
2757                  }                  }
2758          }          }
2759    
2760          if(pParam->m_quarterpel) {                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {
2761                  if((!(Data->currentQMV->x & 1)) && (!(Data->currentQMV->y & 1)) &&                          iSAD =
2762                          (MotionFlags & PMV_QUARTERPELREFINE8)) {                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,
2763                                  CheckCandidate = CheckCandidate8_qpel;                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,
2764                                  QuarterpelRefine(Data);                                                                    max_dy, iEdgedWidth, iDiamondSize, iFcode,
2765                  }                                                                    iQuant, 0);
         }  
2766    
2767          if(pParam->m_quarterpel) {                          if (iSAD < iMinSAD) {
2768                  pMB->pmvs[block].x = Data->currentQMV->x - Data->predQMV.x;                                  *currMV = newMV;
2769                  pMB->pmvs[block].y = Data->currentQMV->y - Data->predQMV.y;                                  iMinSAD = iSAD;
2770                            }
2771          }          }
         else {  
                 pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;  
                 pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;  
2772          }          }
2773    
2774          pMB->mvs[block] = *(Data->currentMV);  /***************        Choose best MV found     **************/
2775          pMB->qmvs[block] = *(Data->currentQMV);  
2776      EPZS8_Terminate_with_Refine:
2777            if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step
2778                    iMinSAD =
2779                            Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,
2780                                                            iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,
2781                                                            iFcode, iQuant, iEdgedWidth);
2782    
2783      EPZS8_Terminate_without_Refine:
2784    
2785          pMB->sad8[block] =  4 * (*Data->iMinSAD);          currPMV->x = currMV->x - center_x;
2786            currPMV->y = currMV->y - center_y;
2787            return iMinSAD;
2788  }  }
2789    
2790    
2791  static void  
2792  SearchPhinted ( const uint8_t * const pRef,  int32_t
2793    PMVfastIntSearch16(const uint8_t * const pRef,
2794                                  const uint8_t * const pRefH,                                  const uint8_t * const pRefH,
2795                                  const uint8_t * const pRefV,                                  const uint8_t * const pRefV,
2796                                  const uint8_t * const pRefHV,                                  const uint8_t * const pRefHV,
2797                                  const IMAGE * const pCur,                                  const IMAGE * const pCur,
2798                                  const int x,                                  const int x,
2799                                  const int y,                                  const int y,
2800                                    const int start_x,              /* start should be most likely vector */
2801                                    const int start_y,
2802                                    const int center_x,             /* center is from where length of MVs is measured */
2803                                    const int center_y,
2804                                  const uint32_t MotionFlags,                                  const uint32_t MotionFlags,
2805                                  const uint32_t iQuant,                                  const uint32_t iQuant,
2806                                    const uint32_t iFcode,
2807                                  const MBParam * const pParam,                                  const MBParam * const pParam,
2808                                  const MACROBLOCK * const pMBs,                                  const MACROBLOCK * const pMBs,
2809                                  int inter4v,                                  const MACROBLOCK * const prevMBs,
2810                                  MACROBLOCK * const pMB,                                  VECTOR * const currMV,
2811                                  SearchData * const Data)                                  VECTOR * const currPMV)
2812  {  {
2813            const uint32_t iWcount = pParam->mb_width;
2814            const int32_t iWidth = pParam->width;
2815            const int32_t iHeight = pParam->height;
2816          const int32_t iEdgedWidth = pParam->edged_width;          const int32_t iEdgedWidth = pParam->edged_width;
2817    
2818          int i, t;          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;
2819          MainSearchFunc * MainSearchPtr;          const VECTOR zeroMV = { 0, 0 };
   
         Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);  
         get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,  
                                 pParam->width, pParam->height, Data->iFcode, pParam->m_quarterpel);  
   
         Data->Cur = pCur->y + (x + y * iEdgedWidth) * 16;  
         Data->Ref = pRef + (x + iEdgedWidth*y)*16;  
         Data->RefH = pRefH + (x + iEdgedWidth*y) * 16;  
         Data->RefV = pRefV + (x + iEdgedWidth*y) * 16;  
         Data->RefHV = pRefHV + (x + iEdgedWidth*y) * 16;  
         Data->iQuant = iQuant;  
2820    
2821          if (!(MotionFlags & PMV_HALFPEL16)) {          int32_t iDiamondSize;
                 Data->min_dx = EVEN(Data->min_dx);  
                 Data->max_dx = EVEN(Data->max_dx);  
                 Data->min_dy = EVEN(Data->min_dy);  
                 Data->max_dy = EVEN(Data->max_dy);  
         }  
2822    
2823          for(i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;          int32_t min_dx;
2824            int32_t max_dx;
2825            int32_t min_dy;
2826            int32_t max_dy;
2827    
2828          if (pMB->dquant != NO_CHANGE) inter4v = 0;          int32_t iFound;
2829    
2830          if (inter4v)          VECTOR newMV;
2831                  CheckCandidate = CheckCandidate16;          VECTOR backupMV;
         else CheckCandidate = CheckCandidate16no4v;  
2832    
2833            VECTOR pmv[4];
2834            int32_t psad[4];
2835    
2836          pMB->mvs[0].x = EVEN(pMB->mvs[0].x);          MainSearch16FuncPtr MainSearchPtr;
         pMB->mvs[0].y = EVEN(pMB->mvs[0].y);  
         if (pMB->mvs[0].x > Data->max_dx) pMB->mvs[0].x = Data->max_dx; // this is in case iFcode changed  
         if (pMB->mvs[0].x < Data->min_dx) pMB->mvs[0].x = Data->min_dx;  
         if (pMB->mvs[0].y > Data->max_dy) pMB->mvs[0].y = Data->max_dy;  
         if (pMB->mvs[0].y < Data->min_dy) pMB->mvs[0].y = Data->min_dy;  
2837    
2838          (*CheckCandidate)(pMB->mvs[0].x, pMB->mvs[0].y, 0, &t, Data);          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;
2839            MACROBLOCK *const pMB = pMBs + x + y * iWcount;
2840    
2841          if (pMB->mode == MODE_INTER4V)          int32_t threshA, threshB;
2842                  for (i = 1; i < 4; i++) { // all four vectors will be used as four predictions for 16x16 search          int32_t bPredEq;
2843                          pMB->mvs[i].x = EVEN(pMB->mvs[i].x);          int32_t iMinSAD, iSAD;
                         pMB->mvs[i].y = EVEN(pMB->mvs[i].y);  
                         if (!(make_mask(pMB->mvs, i)))  
                                 (*CheckCandidate)(pMB->mvs[i].x, pMB->mvs[i].y, 0, &t, Data);  
                 }  
2844    
         if (MotionFlags & PMV_USESQUARES16)  
                 MainSearchPtr = SquareSearch;  
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamondSearch;  
                 else MainSearchPtr = DiamondSearch;  
2845    
2846          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);  /* Get maximum range */
2847            get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,
2848                              iFcode);
2849    
2850          if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(Data);  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */
2851    
2852          for(i = 0; i < 5; i++) {          if ((x == 0) && (y == 0)) {
2853                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // initialize qpel vectors                  threshA = 512;
2854                  Data->currentQMV[i].y = 2 * Data->currentMV[i].y;                  threshB = 1024;
         }  
2855    
2856          if((pParam->m_quarterpel) && (MotionFlags & PMV_QUARTERPELREFINE16)) {                  bPredEq = 0;
2857                    psad[0] = psad[1] = psad[2] = psad[3] = 0;
2858                    *currMV = pmv[0] = pmv[1] = pmv[2] = pmv[3] = zeroMV;
2859    
2860                  if(inter4v)          } else {
                         CheckCandidate = CheckCandidate16_qpel;  
                 else  
                         CheckCandidate = CheckCandidate16no4v_qpel;  
2861    
2862                  QuarterpelRefine(Data);                  bPredEq = get_ipmvdata(pMBs, iWcount, 0, x, y, 0, pmv, psad);
         }  
2863    
2864                    threshA = psad[0];
2865                    threshB = threshA + 256;
2866                    if (threshA < 512)
2867                            threshA = 512;
2868                    if (threshA > 1024)
2869                            threshA = 1024;
2870                    if (threshB > 1792)
2871                            threshB = 1792;
2872    
2873          if (inter4v) {                  *currMV = pmv[0];                       /* current best := prediction */
                 SearchData Data8;  
                 Data8.iFcode = Data->iFcode;  
                 Data8.iQuant = Data->iQuant;  
                 Data8.iEdgedWidth = Data->iEdgedWidth;  
                 Search8hinted(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);  
                 Search8hinted(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);  
                 Search8hinted(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);  
                 Search8hinted(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);  
2874          }          }
2875    
2876          if (!(inter4v) ||          iFound = 0;
                 (Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] + Data->iMinSAD[3] +  
                                                         Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {  
 // INTER MODE  
   
                 pMB->mode = MODE_INTER;  
                 pMB->mvs[0] = pMB->mvs[1]  
                         = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];  
2877    
2878                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =  /* Step 4: Calculate SAD around the Median prediction.
2879                          pMB->sad8[2] = pMB->sad8[3] =  Data->iMinSAD[0];     MinSAD=SAD
2880       If Motion Vector equal to Previous frame motion vector
2881       and MinSAD<PrevFrmSAD goto Step 10.
2882       If SAD<=256 goto Step 10.
2883    */
2884    
2885                  pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;          if (currMV->x > max_dx) {
2886                  pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;                  currMV->x = EVEN(max_dx);
         } else {  
 // INTER4V MODE; all other things are already set in Search8hinted  
                 pMB->mode = MODE_INTER4V;  
                 pMB->sad16 = Data->iMinSAD[1] + Data->iMinSAD[2] + Data->iMinSAD[3]  
                                                 + Data->iMinSAD[4] + IMV16X16 * iQuant;  
2887          }          }
2888            if (currMV->x < min_dx) {
2889                    currMV->x = EVEN(min_dx);
2890  }  }
2891            if (currMV->y > max_dy) {
2892  void                  currMV->y = EVEN(max_dy);
2893  MotionEstimationHinted( MBParam * const pParam,          }
2894                                                  FRAMEINFO * const current,          if (currMV->y < min_dy) {
2895                                                  FRAMEINFO * const reference,                  currMV->y = EVEN(min_dy);
                                                 const IMAGE * const pRefH,  
                                                 const IMAGE * const pRefV,  
                                                 const IMAGE * const pRefHV)  
 {  
         MACROBLOCK *const pMBs = current->mbs;  
         const IMAGE *const pCurrent = &current->image;  
         const IMAGE *const pRef = &reference->image;  
   
         uint32_t x, y;  
         int8_t * qimage;  
         int32_t temp[5], quant = current->quant;  
         int32_t iMinSAD[5];  
         VECTOR currentMV[5];  
         SearchData Data;  
         Data.iEdgedWidth = pParam->edged_width;  
         Data.currentMV = currentMV;  
         Data.iMinSAD = iMinSAD;  
         Data.temp = temp;  
         Data.iFcode = current->fcode;  
         Data.rounding = pParam->m_rounding_type;  
   
         if((qimage = (uint8_t *) malloc(32 * pParam->edged_width)) == NULL)  
                 return; // allocate some mem for qpel interpolated blocks  
                                   // somehow this is dirty since I think we shouldn't use malloc outside  
                                   // encoder_create() - so please fix me!  
   
         Data.RefQ = qimage;  
   
         if (sadInit) (*sadInit) ();  
   
         for (y = 0; y < pParam->mb_height; y++) {  
                 for (x = 0; x < pParam->mb_width; x++)  {  
   
                         MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];  
   
 //intra mode is copied from the first pass. At least for the time being  
                         if  ((pMB->mode == MODE_INTRA) || (pMB->mode == MODE_NOT_CODED) ) continue;  
   
   
                         if (!(current->global_flags & XVID_LUMIMASKING)) {  
                                 pMB->dquant = NO_CHANGE;  
                                 pMB->quant = current->quant; }  
                         else  
                                 if (pMB->dquant != NO_CHANGE) {  
                                         quant += DQtab[pMB->dquant];  
                                         if (quant > 31) quant = 31;  
                                         else if (quant < 1) quant = 1;  
                                         pMB->quant = quant;  
2896                                  }                                  }
2897    
2898                          SearchPhinted(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,          iMinSAD =
2899                                                          y, current->motion_flags, pMB->quant,                  sad16(cur,
2900                                                          pParam, pMBs, current->global_flags & XVID_INTER4V, pMB,                            get_iref_mv(pRef, x, y, 16, currMV,
2901                                                          &Data);                                                   iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);
2902            iMinSAD +=
2903                    calc_delta_16(currMV->x - center_x, currMV->y - center_y,
2904                                              (uint8_t) iFcode, iQuant);
2905    
2906            if ((iMinSAD < 256) ||
2907                    ((MVequal(*currMV, prevMB->i_mvs[0])) &&
2908                     ((int32_t) iMinSAD < prevMB->i_sad16))) {
2909                    if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode
2910                    {
2911                            if (!MVzero(*currMV)) {
2912                                    iMinSAD += MV16_00_BIAS;
2913                                    CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures
2914                                    iMinSAD -= MV16_00_BIAS;
2915                  }                  }
2916          }          }
2917          free(qimage);  
2918                    if (MotionFlags & PMV_EARLYSTOP16)
2919                            goto PMVfastInt16_Terminate_with_Refine;
2920  }  }
2921    
 static __inline int  
 MEanalyzeMB (   const uint8_t * const pRef,  
                                 const uint8_t * const pCur,  
                                 const int x,  
                                 const int y,  
                                 const MBParam * const pParam,  
                                 const MACROBLOCK * const pMBs,  
                                 MACROBLOCK * const pMB,  
                                 SearchData * const Data)  
 {  
2922    
2923          int i, mask;  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion
2924          VECTOR pmv[3];     vector of the median.
2925       If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2
2926    */
2927    
2928            if ((bPredEq) && (MVequal(pmv[0], prevMB->i_mvs[0])))
2929                    iFound = 2;
2930    
2931          *(Data->iMinSAD) = MV_MAX_ERROR;  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.
2932          Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);     Otherwise select large Diamond Search.
2933          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,  */
                                 pParam->width, pParam->height, Data->iFcode, pParam->m_quarterpel);  
2934    
2935          Data->Cur = pCur + (x + y * pParam->edged_width) * 16;          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))
2936          Data->Ref = pRef + (x + y * pParam->edged_width) * 16;                  iDiamondSize = 2;               // halfpel units!
2937            else
2938                    iDiamondSize = 4;               // halfpel units!
2939    
2940          CheckCandidate = CheckCandidate16no4vI;  /*
2941       Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.
2942       Also calculate (0,0) but do not subtract offset.
2943       Let MinSAD be the smallest SAD up to this point.
2944       If MV is (0,0) subtract offset.
2945    */
2946    
2947    // (0,0) is often a good choice
2948    
2949            if (!MVzero(pmv[0]))
2950                    CHECK_MV16_ZERO;
2951    
2952    // previous frame MV is always possible
2953    
2954            if (!MVzero(prevMB->i_mvs[0]))
2955                    if (!MVequal(prevMB->i_mvs[0], pmv[0]))
2956                            CHECK_MV16_CANDIDATE(prevMB->i_mvs[0].x, prevMB->i_mvs[0].y);
2957    
2958    // left neighbour, if allowed
2959    
2960            if (!MVzero(pmv[1]))
2961                    if (!MVequal(pmv[1], prevMB->i_mvs[0]))
2962                            if (!MVequal(pmv[1], pmv[0]))
2963                                    CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);
2964    
2965    // top neighbour, if allowed
2966            if (!MVzero(pmv[2]))
2967                    if (!MVequal(pmv[2], prevMB->i_mvs[0]))
2968                            if (!MVequal(pmv[2], pmv[0]))
2969                                    if (!MVequal(pmv[2], pmv[1]))
2970                                            CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);
2971    
2972    // top right neighbour, if allowed
2973                                            if (!MVzero(pmv[3]))
2974                                                    if (!MVequal(pmv[3], prevMB->i_mvs[0]))
2975                                                            if (!MVequal(pmv[3], pmv[0]))
2976                                                                    if (!MVequal(pmv[3], pmv[1]))
2977                                                                            if (!MVequal(pmv[3], pmv[2]))
2978                                                                                    CHECK_MV16_CANDIDATE(pmv[3].x,
2979                                                                                                                             pmv[3].y);
2980    
2981            if ((MVzero(*currMV)) &&
2982                    (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )
2983                    iMinSAD -= MV16_00_BIAS;
2984    
2985    
2986    /* Step 6: If MinSAD <= thresa goto Step 10.
2987       If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.
2988    */
2989    
2990            if ((iMinSAD <= threshA) ||
2991                    (MVequal(*currMV, prevMB->i_mvs[0]) &&
2992                     ((int32_t) iMinSAD < prevMB->i_sad16))) {
2993    
2994                    if (MotionFlags & PMV_EARLYSTOP16)
2995                            goto PMVfastInt16_Terminate_with_Refine;
2996            }
2997    
2998    
2999    /************ (Diamond Search)  **************/
3000    /*
3001       Step 7: Perform Diamond search, with either the small or large diamond.
3002       If Found=2 only examine one Diamond pattern, and afterwards goto step 10
3003       Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.
3004       If center then goto step 10.
3005       Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.
3006       Refine by using small diamond and goto step 10.
3007    */
3008    
3009          pmv[1].x = EVEN(pMB->mvs[0].x);          if (MotionFlags & PMV_USESQUARES16)
3010          pmv[1].y = EVEN(pMB->mvs[0].y);                  MainSearchPtr = Square16_MainSearch;
3011          pmv[0].x = EVEN(Data->predMV.x);          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
3012          pmv[0].y = EVEN(Data->predMV.y);                  MainSearchPtr = AdvDiamond16_MainSearch;
3013          pmv[2].x = pmv[2].y = 0;          else
3014                    MainSearchPtr = Diamond16_MainSearch;
3015    
3016          CheckCandidate16no4vI(pmv[0].x, pmv[0].y, 255, &i, Data);          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */
         if (!(mask = make_mask(pmv, 1)))  
                 CheckCandidate16no4vI(pmv[1].x, pmv[1].y, mask, &i, Data);  
         if (!(mask = make_mask(pmv, 2)))  
                 CheckCandidate16no4vI(0, 0, mask, &i, Data);  
3017    
         DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, i);  
3018    
3019          pMB->mvs[0] = pMB->mvs[1]  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */
3020                          = pMB->mvs[2] = pMB->mvs[3] = *Data->currentMV; // all, for future get_pmv()          iSAD =
3021                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,
3022                                                      currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,
3023                                                      min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,
3024                                                      iQuant, iFound);
3025    
3026          return *(Data->iMinSAD);          if (iSAD < iMinSAD) {
3027                    *currMV = newMV;
3028                    iMinSAD = iSAD;
3029  }  }
3030    
3031  #define INTRA_THRESH    1350          if (MotionFlags & PMV_EXTSEARCH16) {
3032  #define INTER_THRESH    900  /* extended: search (up to) two more times: orignal prediction and (0,0) */
3033    
3034  int                  if (!(MVequal(pmv[0], backupMV))) {
3035  MEanalysis(     const IMAGE * const pRef,                          iSAD =
3036                          const IMAGE * const pCurrent,                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,
3037                          MBParam * const pParam,                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,
3038                          MACROBLOCK * const pMBs,                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,
3039                          const uint32_t iFcode)                                                                    iDiamondSize, iFcode, iQuant, iFound);
 {  
         uint32_t x, y, intra = 0;  
         int sSAD = 0;  
3040    
3041          VECTOR currentMV;                          if (iSAD < iMinSAD) {
3042          int32_t iMinSAD;                                  *currMV = newMV;
3043          SearchData Data;                                  iMinSAD = iSAD;
         Data.iEdgedWidth = pParam->edged_width;  
         Data.currentMV = &currentMV;  
         Data.iMinSAD = &iMinSAD;  
         Data.iFcode = iFcode;  
         Data.iQuant = 2;  
   
         if (sadInit) (*sadInit) ();  
   
         for (y = 0; y < pParam->mb_height-1; y++) {  
                 for (x = 0; x < pParam->mb_width; x++) {  
                         int sad, dev;  
                         MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];  
   
                         sad = MEanalyzeMB(pRef->y, pCurrent->y, x, y,  
                                                                 pParam, pMBs, pMB, &Data);  
   
                         if ( x != 0 && y != 0 && x != pParam->mb_width-1 ) { //no edge macroblocks, they just don't work  
                                 if (sad > INTRA_THRESH) {  
                                         dev = dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,  
                                                                   pParam->edged_width);  
                                         if (dev + INTRA_THRESH < sad) intra++;  
                                         if (intra > (pParam->mb_height-2)*(pParam->mb_width-2)/2) return 2;  // I frame  
3044                                  }                                  }
                                 sSAD += sad;  
3045                          }                          }
3046    
3047                    if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {
3048                            iSAD =
3049                                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,
3050                                                                      iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,
3051                                                                      max_dy, iEdgedWidth, iDiamondSize, iFcode,
3052                                                                      iQuant, iFound);
3053    
3054                            if (iSAD < iMinSAD) {
3055                                    *currMV = newMV;
3056                                    iMinSAD = iSAD;
3057                  }                  }
3058          }          }
         sSAD /= (pParam->mb_height-2)*(pParam->mb_width-2);  
         if (sSAD > INTER_THRESH ) return 1; //P frame  
         emms();  
         return 0; // B frame  
   
3059  }  }
3060    
3061  int  /*
3062  FindFcode(      const MBParam * const pParam,     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.
3063                          const FRAMEINFO * const current)  */
 {  
         uint32_t x, y;  
         int max = 0, min = 0, i;  
3064    
3065          for (y = 0; y < pParam->mb_height; y++) {  PMVfastInt16_Terminate_with_Refine:
                 for (x = 0; x < pParam->mb_width; x++) {  
3066    
3067                          MACROBLOCK *pMB = &current->mbs[x + y * pParam->mb_width];          pMB->i_mvs[0] = pMB->i_mvs[1] = pMB->i_mvs[2] = pMB->i_mvs[3] = pMB->i_mv16 = *currMV;
3068                          for(i = 0; i < (pMB->mode == MODE_INTER4V ? 4:1); i++) {          pMB->i_sad8[0] = pMB->i_sad8[1] = pMB->i_sad8[2] = pMB->i_sad8[3] = pMB->i_sad16 = iMinSAD;
                                 if (pMB->mvs[i].x > max) max = pMB->mvs[i].x;  
                                 if (pMB->mvs[i].y > max) max = pMB->mvs[i].y;  
3069    
3070                                  if (pMB->mvs[i].x < min) min = pMB->mvs[i].x;          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step
3071                                  if (pMB->mvs[i].y < min) min = pMB->mvs[i].y;                  iMinSAD =
3072                          }                          Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,
3073                  }                                                           iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,
3074          }                                                           iFcode, iQuant, iEdgedWidth);
3075    
3076          min = -min;          pmv[0] = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          // get _REAL_ prediction (halfpel possible)
         max += 1;  
         if (min > max) max = min;  
3077    
3078          for (i = 1; (max > 32 << (i - 1)); i++);  PMVfastInt16_Terminate_without_Refine:
3079          return i;          currPMV->x = currMV->x - center_x;
3080            currPMV->y = currMV->y - center_y;
3081            return iMinSAD;
3082  }  }
3083    

Legend:
Removed from v.1.44.2.8  
changed lines
  Added in v.1.46

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