[svn] / branches / dev-api-3 / xvidcore / src / motion / motion_est.c Repository:
ViewVC logotype

Diff of /branches/dev-api-3/xvidcore/src/motion/motion_est.c

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

trunk/xvidcore/src/motion/motion_est.c revision 3, Fri Mar 8 02:46:11 2002 UTC branches/dev-api-3/xvidcore/src/motion/motion_est.c revision 539, Wed Sep 25 21:28:48 2002 UTC
# Line 1  Line 1 
1  /**************************************************************************  /**************************************************************************
2   *   *
3   *  Modifications:   *      XVID MPEG-4 VIDEO CODEC
4     *      motion estimation
5   *   *
6   *  08.02.2002 split up PMVfast into three routines: PMVFast, PMVFast_MainLoop   *      This program is an implementation of a part of one or more MPEG-4
7   *             PMVFast_Refine to support multiple searches with different start points   *      Video tools as specified in ISO/IEC 14496-2 standard.  Those intending
8   *      07.01.2002 uv-block-based interpolation   *      to use this software module in hardware or software products are
9   *  06.01.2002 INTER/INTRA-decision is now done before any SEARCH8 (speedup)   *      advised that its use may infringe existing patents or copyrights, and
10   *                         changed INTER_BIAS to 150 (as suggested by suxen_drol)   *      any such use would be at such party's own risk.  The original
11   *                         removed halfpel refinement step in PMVfastSearch8 + quality=5   *      developer of this software module and his/her company, and subsequent
12   *                         added new quality mode = 6 which performs halfpel refinement   *      editors and their companies, will have no liability for use of this
13   *                         filesize difference between quality 5 and 6 is smaller than 1%   *      software or modifications or derivatives thereof.
  *             (Isibaar)  
  *  31.12.2001 PMVfastSearch16 and PMVfastSearch8 (gruel)  
  *      30.12.2001 get_range/MotionSearchX simplified; blue/green bug fix  
  *      22.12.2001 commented best_point==99 check  
  *      19.12.2001 modified get_range (purple bug fix)  
  *  15.12.2001 moved pmv displacement from mbprediction  
  *  02.12.2001 motion estimation/compensation split (Isibaar)  
  *      16.11.2001 rewrote/tweaked search algorithms; pross@cs.rmit.edu.au  
  *  10.11.2001 support for sad16/sad8 functions  
  *  28.08.2001 reactivated MODE_INTER4V for EXT_MODE  
  *  24.08.2001 removed MODE_INTER4V_Q, disabled MODE_INTER4V for EXT_MODE  
  *      22.08.2001 added MODE_INTER4V_Q  
  *  20.08.2001 added pragma to get rid of internal compiler error with VC6  
  *             idea by Cyril. Thanks.  
14   *   *
15   *  Michael Militzer <isibaar@videocoding.de>   *      This program is free software; you can redistribute it and/or modify
16     *      it under the terms of the GNU General Public License as published by
17     *      the Free Software Foundation; either version 2 of the License, or
18     *      (at your option) any later version.
19   *   *
20   **************************************************************************/   *      This program is distributed in the hope that it will be useful,
21     *      but WITHOUT ANY WARRANTY; without even the implied warranty of
22     *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     *      GNU General Public License for more details.
24     *
25     *      You should have received a copy of the GNU General Public License
26     *      along with this program; if not, write to the Free Software
27     *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28     *
29     *************************************************************************/
30    
31  #include <assert.h>  #include <assert.h>
32  #include <stdio.h>  #include <stdio.h>
33    #include <stdlib.h>
34    
35  #include "../encoder.h"  #include "../encoder.h"
36  #include "../utils/mbfunctions.h"  #include "../utils/mbfunctions.h"
37  #include "../prediction/mbprediction.h"  #include "../prediction/mbprediction.h"
38  #include "../global.h"  #include "../global.h"
39  #include "../utils/timer.h"  #include "../utils/timer.h"
40    #include "motion_est.h"
41    #include "motion.h"
42  #include "sad.h"  #include "sad.h"
43    #include "../utils/emms.h"
44    
45  // very large value  #define INITIAL_SKIP_THRESH     (10)
46  #define MV_MAX_ERROR    (4096 * 256)  #define FINAL_SKIP_THRESH       (50)
47    #define MAX_SAD00_FOR_SKIP      (20)
48    #define MAX_CHROMA_SAD_FOR_SKIP (22)
49    #define SKIP_THRESH_B (25)
50    
51  // stop search if sdelta < THRESHOLD  #define CHECK_CANDIDATE(X,Y,D) { \
52  #define MV16_THRESHOLD  192  (*CheckCandidate)((const int)(X),(const int)(Y), (D), &iDirection, data ); }
 #define MV8_THRESHOLD   56  
53    
54  /* sad16(0,0) bias; mpeg4 spec suggests nb/2+1 */  #define iDiamondSize 2
 /* nb  = vop pixels * 2^(bpp-8) */  
 #define MV16_00_BIAS    (128+1)  
55    
56  /* INTER bias for INTER/INTRA decision; mpeg4 spec suggests 2*nb */  static __inline int
57  #define INTER_BIAS      512  d_mv_bits(int x, int y, const uint32_t iFcode)
58    {
59            int xb, yb;
60    
61  /* Parameters which control inter/inter4v decision */          if (x == 0) xb = 1;
62  #define IMV16X16                        5          else {
63                    if (x < 0) x = -x;
64                    x += (1 << (iFcode - 1)) - 1;
65                    x >>= (iFcode - 1);
66                    if (x > 32) x = 32;
67                    xb = mvtab[x] + iFcode;
68            }
69    
70  /* vector map (vlc delta size) smoother parameters */          if (y == 0) yb = 1;
71  #define NEIGH_TEND_16X16        2          else {
72  #define NEIGH_TEND_8X8          2                  if (y < 0) y = -y;
73                    y += (1 << (iFcode - 1)) - 1;
74                    y >>= (iFcode - 1);
75                    if (y > 32) y = 32;
76                    yb = mvtab[y] + iFcode;
77            }
78            return xb + yb;
79    }
80    
81    
82  // fast ((A)/2)*2  /* CHECK_CANDIATE FUNCTIONS START */
 #define EVEN(A)         (((A)<0?(A)+1:(A)) & ~1)  
83    
84    static void
85    CheckCandidate16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
86    {
87            int32_t * const sad = data->temp;
88            int t;
89            const uint8_t * Reference;
90    
91  #define MIN(X, Y) ((X)<(Y)?(X):(Y))          if (( x > data->max_dx) || ( x < data->min_dx)
92  #define MAX(X, Y) ((X)>(Y)?(X):(Y))                  || ( y > data->max_dy) || (y < data->min_dy)) return;
 #define ABS(X) (((X)>0)?(X):-(X))  
 #define SIGN(X) (((X)>0)?1:-1)  
93    
94            switch ( ((x&1)<<1) + (y&1) ) {
95                    case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
96                    case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;
97                    case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;
98                    default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
99            }
100    
101  int32_t PMVfastSearch8(          data->temp[0] = sad16v(data->Cur, Reference, data->iEdgedWidth, sad+1);
                                         const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const IMAGE * const pCur,  
                                         const int x, const int y,  
                                         const int start_x, int start_y,  
                                         const uint32_t iQuality,  
                                         MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV);  
102    
103  int32_t PMVfastSearch16(          t = d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
104                                          const uint8_t * const pRef,          data->temp[0] += lambda_vec16[data->iQuant] * t;
105                                          const uint8_t * const pRefH,          data->temp[1] += lambda_vec8[data->iQuant] * t;
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const IMAGE * const pCur,  
                                         const int x, const int y,  
                                         const uint32_t iQuality,  
                                         MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV);  
106    
107            if (data->temp[0] < data->iMinSAD[0]) {
108                    data->iMinSAD[0] = data->temp[0];
109                    data->currentMV[0].x = x; data->currentMV[0].y = y;
110                    *dir = Direction; }
111    
112            if (data->temp[1] < data->iMinSAD[1]) {
113                    data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
114            if (data->temp[2] < data->iMinSAD[2]) {
115                    data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
116            if (data->temp[3] < data->iMinSAD[3]) {
117                    data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
118            if (data->temp[4] < data->iMinSAD[4]) {
119                    data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
120    
121  /* diamond search stuff  }
    keep the the sequence in circular order (so optimization works)  
 */  
122    
123  typedef struct  static void
124    CheckCandidate16no4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
125  {  {
126          int32_t dx;          int32_t sad;
127          int32_t dy;          const uint8_t * Reference;
 }  
 DPOINT;  
128    
129            if (( x > data->max_dx) || ( x < data->min_dx)
130                    || ( y > data->max_dy) || (y < data->min_dy)) return;
131    
132  static const DPOINT diamond_small[4] =          switch ( ((x&1)<<1) + (y&1) )
133  {  {
134          {0, 1}, {1, 0}, {0, -1}, {-1, 0}                  case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
135  };                  case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;
136                    case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;
137                    default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
138            }
139    
140            sad = lambda_vec16[data->iQuant] *
141                            d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
142            sad += sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
143    
144            if (sad < *(data->iMinSAD)) {
145                    *(data->iMinSAD) = sad;
146                    data->currentMV[0].x = x; data->currentMV[0].y = y;
147                    *dir = Direction; }
148    }
149    
150  static const DPOINT diamond_large[8] =  static void
151    CheckCandidate16no4vI(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
152  {  {
153          {0, 2}, {1, 1}, {2, 0}, {1, -1}, {0, -2}, {-1, -1}, {-2, 0}, {-1, 1}          int32_t sad;
 };  
154    
155            if (( x > data->max_dx) || ( x < data->min_dx)
156                    || ( y > data->max_dy) || (y < data->min_dy)) return;
157    
158  // mv.length table          sad = lambda_vec16[data->iQuant] *
159  static const uint32_t mvtab[33] = {                          d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
     1,  2,  3,  4,  6,  7,  7,  7,  
     9,  9,  9,  10, 10, 10, 10, 10,  
     10, 10, 10, 10, 10, 10, 10, 10,  
     10, 11, 11, 11, 11, 11, 11, 12, 12  
 };  
160    
161            sad += sad16(data->Cur, data->Ref + x/2 + (y/2)*(data->iEdgedWidth),
162                                            data->iEdgedWidth, 256*4096);
163    
164  static __inline uint32_t mv_bits(int32_t component, const uint32_t iFcode)          if (sad < *(data->iMinSAD)) {
165  {                  *(data->iMinSAD) = sad;
166      if (component == 0)                  data->currentMV[0].x = x; data->currentMV[0].y = y;
167                  return 1;                  *dir = Direction; }
168    }
169    
     if (component < 0)  
                 component = -component;  
170    
171      if (iFcode == 1)  static void
172    CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)
173      {      {
174                  if (component > 32)          int32_t sad;
175                      component = 32;          const int xb = data->currentMV[1].x;
176            const int yb = data->currentMV[1].y;
177            const uint8_t *ReferenceF, *ReferenceB;
178    
179            if (( xf > data->max_dx) || ( xf < data->min_dx)
180                    || ( yf > data->max_dy) || (yf < data->min_dy)) return;
181    
182                  return mvtab[component] + 1;          switch ( ((xf&1)<<1) + (yf&1) ) {
183                    case 0 : ReferenceF = data->Ref + xf/2 + (yf/2)*(data->iEdgedWidth); break;
184                    case 1 : ReferenceF = data->RefV + xf/2 + ((yf-1)/2)*(data->iEdgedWidth); break;
185                    case 2 : ReferenceF = data->RefH + (xf-1)/2 + (yf/2)*(data->iEdgedWidth); break;
186                    default : ReferenceF = data->RefHV + (xf-1)/2 + ((yf-1)/2)*(data->iEdgedWidth); break;
187      }      }
188    
189      component += (1 << (iFcode - 1)) - 1;          switch ( ((xb&1)<<1) + (yb&1) ) {
190      component >>= (iFcode - 1);                  case 0 : ReferenceB = data->bRef + xb/2 + (yb/2)*(data->iEdgedWidth); break;
191                    case 1 : ReferenceB = data->bRefV + xb/2 + ((yb-1)/2)*(data->iEdgedWidth); break;
192                    case 2 : ReferenceB = data->bRefH + (xb-1)/2 + (yb/2)*(data->iEdgedWidth); break;
193                    default : ReferenceB = data->bRefHV + (xb-1)/2 + ((yb-1)/2)*(data->iEdgedWidth); break;
194            }
195    
196      if (component > 32)          sad = lambda_vec16[data->iQuant] *
197                  component = 32;                          ( d_mv_bits(xf - data->predMV.x, yf - data->predMV.y, data->iFcode) +
198                              d_mv_bits(xb - data->bpredMV.x, yb - data->bpredMV.y, data->iFcode) );
199    
200      return mvtab[component] + 1 + iFcode - 1;          sad += sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
 }  
201    
202            if (sad < *(data->iMinSAD)) {
203                    *(data->iMinSAD) = sad;
204                    data->currentMV->x = xf; data->currentMV->y = yf;
205                    *dir = Direction; }
206    }
207    
208  static __inline uint32_t calc_delta_16(const int32_t dx, const int32_t dy, const uint32_t iFcode)  static void
209    CheckCandidateDirect(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
210  {  {
211          return NEIGH_TEND_16X16 * (mv_bits(dx, iFcode) + mv_bits(dy, iFcode));          int32_t sad;
212            int k;
213            const uint8_t *ReferenceF;
214            const uint8_t *ReferenceB;
215            VECTOR mvs, b_mvs;
216    
217            if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
218    
219            sad = lambda_vec16[data->iQuant] * d_mv_bits(x, y, 1);
220    
221            for (k = 0; k < 4; k++) {
222                    mvs.x = data->directmvF[k].x + x;
223                    b_mvs.x = ((x == 0) ?
224                            data->directmvB[k].x
225                            : mvs.x - data->referencemv[k].x);
226    
227                    mvs.y = data->directmvF[k].y + y;
228                    b_mvs.y = ((y == 0) ?
229                            data->directmvB[k].y
230                            : mvs.y - data->referencemv[k].y);
231    
232                    if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
233                            || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
234                            || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
235                            || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
236    
237                    switch ( ((mvs.x&1)<<1) + (mvs.y&1) ) {
238                            case 0 : ReferenceF = data->Ref + mvs.x/2 + (mvs.y/2)*(data->iEdgedWidth); break;
239                            case 1 : ReferenceF = data->RefV + mvs.x/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
240                            case 2 : ReferenceF = data->RefH + (mvs.x-1)/2 + (mvs.y/2)*(data->iEdgedWidth); break;
241                            default : ReferenceF = data->RefHV + (mvs.x-1)/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
242  }  }
243    
244  static __inline uint32_t calc_delta_8(const int32_t dx, const int32_t dy, const uint32_t iFcode)                  switch ( ((b_mvs.x&1)<<1) + (b_mvs.y&1) ) {
245                            case 0 : ReferenceB = data->bRef + b_mvs.x/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
246                            case 1 : ReferenceB = data->bRefV + b_mvs.x/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
247                            case 2 : ReferenceB = data->bRefH + (b_mvs.x-1)/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
248                            default : ReferenceB = data->bRefHV + (b_mvs.x-1)/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
249                    }
250    
251  {                  sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
252      return NEIGH_TEND_8X8 * (mv_bits(dx, iFcode) + mv_bits(dy, iFcode));                                                  ReferenceF + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
253                                                    ReferenceB + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
254                                                    data->iEdgedWidth);
255                    if (sad > *(data->iMinSAD)) return;
256  }  }
257    
258            if (sad < *(data->iMinSAD)) {
259                    *(data->iMinSAD) = sad;
260                    data->currentMV->x = x; data->currentMV->y = y;
261                    *dir = Direction; }
262    }
263    
264    static void
265    CheckCandidateDirectno4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
266    {
267            int32_t sad;
268            const uint8_t *ReferenceF;
269            const uint8_t *ReferenceB;
270            VECTOR mvs, b_mvs;
271    
272            if (( x > 31) || ( x < -31) || ( y > 31) || (y < -31)) return;
273    
274  /* calculate the min/max range (in halfpixels)                  sad = lambda_vec16[data->iQuant] * d_mv_bits(x, y, 1);
         relative to the _MACROBLOCK_ position  
 */  
275    
276  static void __inline get_range(          mvs.x = data->directmvF[0].x + x;
277                          int32_t * const min_dx, int32_t * const max_dx,          b_mvs.x = ((x == 0) ?
278                          int32_t * const min_dy, int32_t * const max_dy,                  data->directmvB[0].x
279                          const uint32_t x, const uint32_t y,                  : mvs.x - data->referencemv[0].x);
                         const uint32_t block_sz,                                        // block dimension, 8 or 16  
                         const uint32_t width, const uint32_t height,  
                         const uint32_t fcode)  
 {  
         const int search_range = 32 << (fcode - 1);  
     const int high = search_range - 1;  
     const int low = -search_range;  
   
         // convert full-pixel measurements to half pixel  
         const int hp_width = 2 * width;  
         const int hp_height = 2 * height;  
         const int hp_edge = 2 * block_sz;  
         const int hp_x = 2 * (x) * block_sz;            // we need _right end_ of block, not x-coordinate  
         const int hp_y = 2 * (y) * block_sz;            // same for _bottom end_  
   
     *max_dx = MIN(high, hp_width - hp_x);  
     *max_dy = MIN(high, hp_height - hp_y);  
     *min_dx = MAX(low,  -(hp_edge + hp_x));  
     *min_dy = MAX(low,  -(hp_edge + hp_y));  
 }  
280    
281            mvs.y = data->directmvF[0].y + y;
282            b_mvs.y = ((y == 0) ?
283                    data->directmvB[0].y
284                    : mvs.y - data->referencemv[0].y);
285    
286  /* getref: calculate reference image pointer          if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
287  the decision to use interpolation h/v/hv or the normal image is                  || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
288  based on dx & dy.                  || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
289  */                  || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
290    
291  static __inline const uint8_t * get_ref(          switch ( ((mvs.x&1)<<1) + (mvs.y&1) ) {
292                                  const uint8_t * const refn,                  case 0 : ReferenceF = data->Ref + mvs.x/2 + (mvs.y/2)*(data->iEdgedWidth); break;
293                                  const uint8_t * const refh,                  case 1 : ReferenceF = data->RefV + mvs.x/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
294                                  const uint8_t * const refv,                  case 2 : ReferenceF = data->RefH + (mvs.x-1)/2 + (mvs.y/2)*(data->iEdgedWidth); break;
295                                  const uint8_t * const refhv,                  default : ReferenceF = data->RefHV + (mvs.x-1)/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
                                 const uint32_t x, const uint32_t y,  
                                 const uint32_t block,                                   // block dimension, 8 or 16  
                                 const int32_t dx, const int32_t dy,  
                                 const uint32_t stride)  
 {  
         switch ( ((dx&1)<<1) + (dy&1) )         // ((dx%2)?2:0)+((dy%2)?1:0)  
     {  
         case 0 : return refn + (x*block+dx/2) + (y*block+dy/2)*stride;  
     case 1 : return refv + (x*block+dx/2) + (y*block+(dy-1)/2)*stride;  
         case 2 : return refh + (x*block+(dx-1)/2) + (y*block+dy/2)*stride;  
         default :  
         case 3 : return refhv + (x*block+(dx-1)/2) + (y*block+(dy-1)/2)*stride;  
296          }          }
297    
298            switch ( ((b_mvs.x&1)<<1) + (b_mvs.y&1) ) {
299                    case 0 : ReferenceB = data->bRef + b_mvs.x/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
300                    case 1 : ReferenceB = data->bRefV + b_mvs.x/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
301                    case 2 : ReferenceB = data->bRefH + (b_mvs.x-1)/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
302                    default : ReferenceB = data->bRefHV + (b_mvs.x-1)/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
303  }  }
304    
305            sad += sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
306    
307  /* This is somehow a copy of get_ref, but with MV instead of X,Y */          if (sad < *(data->iMinSAD)) {
308                    *(data->iMinSAD) = sad;
309                    data->currentMV->x = x; data->currentMV->y = y;
310                    *dir = Direction; }
311    }
312    
313  static __inline const uint8_t * get_ref_mv(  static void
314                                  const uint8_t * const refn,  CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                                 const uint8_t * const refh,  
                                 const uint8_t * const refv,  
                                 const uint8_t * const refhv,  
                                 const uint32_t x, const uint32_t y,  
                                 const uint32_t block,                   // block dimension, 8 or 16  
                                 const VECTOR* mv,       // measured in half-pel!  
                                 const uint32_t stride)  
315  {  {
316          switch ( (((mv->x)&1)<<1) + ((mv->y)&1) )          int32_t sad;
317            const uint8_t * Reference;
318    
319            if (( x > data->max_dx) || ( x < data->min_dx)
320                    || ( y > data->max_dy) || (y < data->min_dy)) return;
321    
322            switch ( ((x&1)<<1) + (y&1) )
323      {      {
324          case 0 : return refn + (x*block+(mv->x)/2) + (y*block+(mv->y)/2)*stride;                  case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
325          case 1 : return refv + (x*block+(mv->x)/2) + (y*block+((mv->y)-1)/2)*stride;                  case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;
326          case 2 : return refh + (x*block+((mv->x)-1)/2) + (y*block+(mv->y)/2)*stride;                  case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;
327          default :                  default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
         case 3 : return refhv + (x*block+((mv->x)-1)/2) + (y*block+((mv->y)-1)/2)*stride;  
328          }          }
 }  
   
 #ifndef SEARCH16  
 #define SEARCH16        PMVfastSearch16  
 #endif  
329    
330  #ifndef SEARCH8          sad = sad8(data->Cur, Reference, data->iEdgedWidth);
331  #define SEARCH8         PMVfastSearch8          sad += lambda_vec8[data->iQuant] * d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
 #endif  
332    
333  bool MotionEstimation(          if (sad < *(data->iMinSAD)) {
334                          MACROBLOCK * const pMBs,                  *(data->iMinSAD) = sad;
335                          MBParam * const pParam,                  data->currentMV->x = x; data->currentMV->y = y;
336                      const IMAGE * const pRef,                  *dir = Direction; }
337                          const IMAGE * const pRefH,  }
                     const IMAGE * const pRefV,  
                         const IMAGE * const pRefHV,  
                     IMAGE * const pCurrent,  
                         const uint32_t iLimit)  
338    
339  {  /* CHECK_CANDIATE FUNCTIONS END */
     const uint32_t iWcount = pParam->mb_width;  
     const uint32_t iHcount = pParam->mb_height;  
340    
341          uint32_t i, j, iIntra = 0;  /* MAINSEARCH FUNCTIONS START */
342    
343      VECTOR mv16;  static void
344      VECTOR pmv16;  AdvDiamondSearch(int x, int y, const SearchData * const data, int bDirection)
345    {
346    
347      int32_t sad8 = 0;  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
     int32_t sad16;  
     int32_t deviation;  
348    
349          // note: i==horizontal, j==vertical                  int iDirection;
     for (i = 0; i < iHcount; i++)  
                 for (j = 0; j < iWcount; j++)  
                 {  
                         MACROBLOCK *pMB = &pMBs[j + i * iWcount];  
350    
351                          sad16 = SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,                  do {
352                                            j, i, pParam->motion_flags,                          iDirection = 0;
353                                            pParam, pMBs, &mv16, &pmv16);                          if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
354                          pMB->sad16=sad16;                          if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
355                            if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
356                            if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
357    
358                            /* now we're doing diagonal checks near our candidate */
359    
360                  /* decide: MODE_INTER or MODE_INTRA                          if (iDirection) {               //checking if anything found
361                          if (dev_intra < sad_inter - 2 * nb) use_intra                                  bDirection = iDirection;
362                  */                                  iDirection = 0;
363                                    x = data->currentMV->x; y = data->currentMV->y;
364                                    if (bDirection & 3) {   //our candidate is left or right
365                                            CHECK_CANDIDATE(x, y + iDiamondSize, 8);
366                                            CHECK_CANDIDATE(x, y - iDiamondSize, 4);
367                                    } else {                        // what remains here is up or down
368                                            CHECK_CANDIDATE(x + iDiamondSize, y, 2);
369                                            CHECK_CANDIDATE(x - iDiamondSize, y, 1); }
370    
371                  deviation = dev16(pCurrent->y + j*16 + i*16*pParam->edged_width, pParam->edged_width);                                  if (iDirection) {
372                                            bDirection += iDirection;
373                                            x = data->currentMV->x; y = data->currentMV->y; }
374                            } else {                                //about to quit, eh? not so fast....
375                                    switch (bDirection) {
376                                    case 2:
377                                            CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
378                                            CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
379                                            break;
380                                    case 1:
381                                            CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
382                                            CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
383                                            break;
384                                    case 2 + 4:
385                                            CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
386                                            CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
387                                            CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
388                                            break;
389                                    case 4:
390                                            CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
391                                            CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
392                                            break;
393                                    case 8:
394                                            CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
395                                            CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
396                                            break;
397                                    case 1 + 4:
398                                            CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
399                                            CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
400                                            CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
401                                            break;
402                                    case 2 + 8:
403                                            CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
404                                            CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
405                                            CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
406                                            break;
407                                    case 1 + 8:
408                                            CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
409                                            CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
410                                            CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
411                                            break;
412                                    default:                //1+2+4+8 == we didn't find anything at all
413                                            CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
414                                            CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
415                                            CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
416                                            CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
417                                            break;
418                                    }
419                                    if (!iDirection) break;         //ok, the end. really
420                                    bDirection = iDirection;
421                                    x = data->currentMV->x; y = data->currentMV->y;
422                            }
423                    }
424                    while (1);                              //forever
425    }
426    
427                  if (deviation < (sad16 - INTER_BIAS))  static void
428    SquareSearch(int x, int y, const SearchData * const data, int bDirection)
429                  {                  {
430                          pMB->mode = MODE_INTRA;          int iDirection;
                         pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = 0;  
                         pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = 0;  
431    
432                          iIntra++;          do {
433                          if(iIntra >= iLimit)                  iDirection = 0;
434                                  return 1;                  if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);
435                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);
436                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);
437                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128);
438                    if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64);
439                    if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128);
440                    if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128);
441                    if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128);
442    
443                          continue;                  bDirection = iDirection;
444                    x = data->currentMV->x; y = data->currentMV->y;
445            } while (iDirection);
446                  }                  }
447    
448                  if (pParam->global_flags & XVID_INTER4V)  static void
449    DiamondSearch(int x, int y, const SearchData * const data, int bDirection)
450                  {                  {
                         pMB->sad8[0] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,  
                                         2 * j, 2 * i, mv16.x, mv16.y, pParam->motion_flags,  
                                         pParam, pMBs, &pMB->mvs[0], &pMB->pmvs[0]);  
451    
452                          pMB->sad8[1] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
                                         2 * j + 1, 2 * i, mv16.x, mv16.y, pParam->motion_flags,  
                                         pParam, pMBs, &pMB->mvs[1], &pMB->pmvs[1]);  
453    
454                          pMB->sad8[2] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,                  int iDirection;
                                         2 * j, 2 * i + 1, mv16.x, mv16.y, pParam->motion_flags,  
                                         pParam, pMBs, &pMB->mvs[2], &pMB->pmvs[2]);  
455    
456                          pMB->sad8[3] = SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,                  do {
457                                          2 * j + 1, 2 * i + 1, mv16.x, mv16.y, pParam->motion_flags,                          iDirection = 0;
458                                          pParam, pMBs, &pMB->mvs[3], &pMB->pmvs[3]);                          if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
459                            if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
460                            if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
461                            if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
462    
463                          sad8 = pMB->sad8[0] + pMB->sad8[1] + pMB->sad8[2] + pMB->sad8[3];                          /* now we're doing diagonal checks near our candidate */
                 }  
464    
465                            if (iDirection) {               //checking if anything found
466                                    bDirection = iDirection;
467                                    iDirection = 0;
468                                    x = data->currentMV->x; y = data->currentMV->y;
469                                    if (bDirection & 3) {   //our candidate is left or right
470                                            CHECK_CANDIDATE(x, y + iDiamondSize, 8);
471                                            CHECK_CANDIDATE(x, y - iDiamondSize, 4);
472                                    } else {                        // what remains here is up or down
473                                            CHECK_CANDIDATE(x + iDiamondSize, y, 2);
474                                            CHECK_CANDIDATE(x - iDiamondSize, y, 1); }
475    
476                  /* decide: MODE_INTER or MODE_INTER4V                                  bDirection += iDirection;
477                          mpeg4:   if (sad8 < sad16 - nb/2+1) use_inter4v                                  x = data->currentMV->x; y = data->currentMV->y;
                 */  
   
                 if (pMB->dquant == NO_CHANGE) {  
                         if (((pParam->global_flags & XVID_INTER4V)==0) ||  
                                 (sad16 < (sad8 + (int32_t)(IMV16X16 * pParam->quant)))) {  
   
                                 sad8 = sad16;  
                                 pMB->mode = MODE_INTER;  
                                 pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = mv16.x;  
                                 pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = mv16.y;  
                                 pMB->pmvs[0].x = pmv16.x;  
                                 pMB->pmvs[0].y = pmv16.y;  
                         }  
                         else  
                                 pMB->mode = MODE_INTER4V;  
478                  }                  }
                 else  
                 {  
                         sad8 = sad16;  
                         pMB->mode = MODE_INTER;  
                         pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = mv16.x;  
                         pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = mv16.y;  
                         pMB->pmvs[0].x = pmv16.x;  
                         pMB->pmvs[0].y = pmv16.y;  
479                  }                  }
480                    while (iDirection);
481          }          }
482    
483          return 0;  /* MAINSEARCH FUNCTIONS END */
 }  
484    
485  #define MVzero(A) ( ((A).x)==(0) && ((A).y)==(0) )  /* HALFPELREFINE COULD BE A MAINSEARCH FUNCTION, BUT THERE IS NO NEED FOR IT */
486    
487  #define MVequal(A,B) ( ((A).x)==((B).x) && ((A).y)==((B).y) )  static void
488    HalfpelRefine(const SearchData * const data)
489    {
490    /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */
491    
492            VECTOR backupMV = *(data->currentMV);
493            int iDirection; //not needed
494    
495            CHECK_CANDIDATE(backupMV.x - 1, backupMV.y - 1, 0);
496            CHECK_CANDIDATE(backupMV.x + 1, backupMV.y - 1, 0);
497            CHECK_CANDIDATE(backupMV.x - 1, backupMV.y + 1, 0);
498            CHECK_CANDIDATE(backupMV.x + 1, backupMV.y + 1, 0);
499    
500  #define CHECK_MV16_ZERO {\          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y, 0);
501    if ( (0 <= max_dx) && (0 >= min_dx) \          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y, 0);
502      && (0 <= max_dy) && (0 >= min_dy) ) \  
503    { \          CHECK_CANDIDATE(backupMV.x, backupMV.y + 1, 0);
504      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \          CHECK_CANDIDATE(backupMV.x, backupMV.y - 1, 0);
     iSAD += calc_delta_16(-pmv[0].x, -pmv[0].y, (uint8_t)iFcode) * iQuant;\  
     if (iSAD <= iQuant * 96)    \  
         iSAD -= MV16_00_BIAS; \  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=0; currMV->y=0; }  }     \  
 }  
   
   
 #define CHECK_MV16_CANDIDATE(X,Y) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode) * iQuant;\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_CANDIDATE_DIR(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode) * iQuant;\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \  
 }  
   
 #define CHECK_MV16_CANDIDATE_FOUND(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - pmv[0].x, (Y) - pmv[0].y, (uint8_t)iFcode) * iQuant;\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
 }  
   
   
 #define CHECK_MV8_ZERO {\  
   iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, 0, 0 , iEdgedWidth), iEdgedWidth); \  
   iSAD += calc_delta_8(-pmv[0].x, -pmv[0].y, (uint8_t)iFcode) * iQuant;\  
   if (iSAD < iMinSAD) \  
   { iMinSAD=iSAD; currMV->x=0; currMV->y=0; } \  
 }  
   
   
 #define CHECK_MV8_CANDIDATE(X,Y) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode) * iQuant;\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV8_CANDIDATE_DIR(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode) * iQuant;\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \  
 }  
   
 #define CHECK_MV8_CANDIDATE_FOUND(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-pmv[0].x, (Y)-pmv[0].y, (uint8_t)iFcode) * iQuant;\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
505  }  }
506    
507  /* too slow and not fully functional at the moment */  static __inline int
508  /*  SkipDecisionP(const IMAGE * current, const IMAGE * reference,
 int32_t ZeroSearch16(  
                                         const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const IMAGE * const pCur,  
509                                          const int x, const int y,                                          const int x, const int y,
510                                          const uint32_t MotionFlags,                                                          const uint32_t iEdgedWidth, const uint32_t iQuant)
                                         MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
 {  
         const int32_t iEdgedWidth = pParam->edged_width;  
         const int32_t iQuant = pParam->quant;  
         const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;  
         int32_t iSAD;  
         int32_t pred_x,pred_y;  
   
         get_pmv(pMBs, x, y, pParam->mb_width, 0, &pred_x, &pred_y);  
   
         iSAD = sad16( cur,  
                 get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth),  
                 iEdgedWidth, MV_MAX_ERROR);  
         if (iSAD <= iQuant * 96)  
                 iSAD -= MV16_00_BIAS;  
   
         currMV->x = 0;  
         currMV->y = 0;  
         currPMV->x = -pred_x;  
         currPMV->y = -pred_y;  
511    
512          return iSAD;  {
513    /*      keep repeating checks for all b-frames before this P frame,
514            to make sure that SKIP is possible (todo)
515            how: if skip is not possible set sad00 to a very high value */
516    
517            uint32_t sadC = sad8(current->u + x*8 + y*(iEdgedWidth/2)*8,
518                                            reference->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2);
519            if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
520            sadC += sad8(current->v + x*8 + y*(iEdgedWidth/2)*8,
521                                            reference->v + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2);
522            if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
523    
524            return 1;
525  }  }
 */  
526    
527  int32_t PMVfastSearch16_MainSearch(  static __inline void
528                                          const uint8_t * const pRef,  SkipMacroblockP(MACROBLOCK *pMB, const int32_t sad)
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x, const int y,  
                                         int32_t startx, int32_t starty,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                         const VECTOR * const pmv,  
                                         const int32_t min_dx, const int32_t max_dx,  
                                         const int32_t min_dy, const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iDirection=0;  
         int32_t iSAD;  
         VECTOR backupMV;  
         backupMV.x = startx;  
         backupMV.y = starty;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         CHECK_MV16_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y,1);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);  
   
         if (iDirection)  
                 while (!iFound)  
                 {  
                         iFound = 1;  
                         backupMV=*currMV;  
   
                         if ( iDirection != 2)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x-iDiamondSize,backupMV.y,1);  
                         if ( iDirection != 1)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x+iDiamondSize,backupMV.y,2);  
                         if ( iDirection != 4)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,backupMV.y-iDiamondSize,3);  
                         if ( iDirection != 3)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,backupMV.y+iDiamondSize,4);  
                 }  
         else  
529                  {                  {
530                          currMV->x = startx;          pMB->mode = MODE_NOT_CODED;
531                          currMV->y = starty;          pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = 0;
532                  }          pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = 0;
533          return iMinSAD;          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
534  }  }
535    
536  int32_t PMVfastSearch16_Refine(  bool
537                                          const uint8_t * const pRef,  MotionEstimation(MBParam * const pParam,
538                                          const uint8_t * const pRefH,                                   FRAMEINFO * const current,
539                                          const uint8_t * const pRefV,                                   FRAMEINFO * const reference,
540                                          const uint8_t * const pRefHV,                                   const IMAGE * const pRefH,
541                                          const uint8_t * const cur,                                   const IMAGE * const pRefV,
542                                          const int x, const int y,                                   const IMAGE * const pRefHV,
543                                          VECTOR * const currMV,                                   const uint32_t iLimit)
                                         int32_t iMinSAD,  
                                         const VECTOR * const pmv,  
                                         const int32_t min_dx, const int32_t max_dx,  
                                         const int32_t min_dy, const int32_t max_dy,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         const int32_t iEdgedWidth)  
544  {  {
545  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */          MACROBLOCK *const pMBs = current->mbs;
546            const IMAGE *const pCurrent = &current->image;
547          int32_t iSAD;          const IMAGE *const pRef = &reference->image;
548          VECTOR backupMV = *currMV;  
549            const VECTOR zeroMV = { 0, 0 };
550          CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y-1);  
551          CHECK_MV16_CANDIDATE(backupMV.x  ,backupMV.y-1);          uint32_t x, y;
552          CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y-1);          uint32_t iIntra = 0;
553          CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y);          int32_t InterBias;
554          CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y);  
555          CHECK_MV16_CANDIDATE(backupMV.x-1,backupMV.y+1);          // some pre-initialized thingies for SearchP
556          CHECK_MV16_CANDIDATE(backupMV.x  ,backupMV.y+1);          int32_t temp[5];
557          CHECK_MV16_CANDIDATE(backupMV.x+1,backupMV.y+1);          VECTOR currentMV[5];
558            int32_t iMinSAD[5];
559          return iMinSAD;          SearchData Data;
560            Data.iEdgedWidth = pParam->edged_width;
561            Data.currentMV = currentMV;
562            Data.iMinSAD = iMinSAD;
563            Data.temp = temp;
564            Data.iFcode = current->fcode;
565    
566            if (sadInit) (*sadInit) ();
567    
568            for (y = 0; y < pParam->mb_height; y++) {
569                    for (x = 0; x < pParam->mb_width; x++)  {
570    
571                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
572                            int32_t sad00 =  pMB->sad16
573                                    = sad16v(pCurrent->y + (x + y * pParam->edged_width) * 16,
574                                                            pRef->y + (x + y * pParam->edged_width) * 16,
575                                                            pParam->edged_width, pMB->sad8 );
576    
577                            if (!(current->global_flags & XVID_LUMIMASKING)) {
578                                    pMB->dquant = NO_CHANGE;
579                                    pMB->quant = current->quant; }
580    
581    //initial skip decision
582    
583                            if ((pMB->dquant == NO_CHANGE) && (sad00 <= MAX_SAD00_FOR_SKIP * pMB->quant)
584                                    && (SkipDecisionP(pCurrent, pRef, x, y, pParam->edged_width, pMB->quant)) ) {
585                                    if (pMB->sad16 < pMB->quant * INITIAL_SKIP_THRESH) {
586                                                    SkipMacroblockP(pMB, sad00);
587                                                    continue;
588  }  }
589                            } else sad00 = 256*4096; // skip not allowed - for final skip decision
590    
591  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)                          SearchP(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
592                                                    y, current->motion_flags, pMB->quant,
593                                                    &Data, pParam, pMBs, reference->mbs,
594                                                    current->global_flags & XVID_INTER4V, pMB);
595    
596    /* final skip decision, a.k.a. "the vector you found, really that good?" */
597                            if (sad00 < pMB->quant * MAX_SAD00_FOR_SKIP)
598                                    if ((100*pMB->sad16)/(sad00+1) > FINAL_SKIP_THRESH)
599                                    { SkipMacroblockP(pMB, sad00); continue; }
600    
601  int32_t PMVfastSearch16(  /* finally, intra decision */
                                         const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const IMAGE * const pCur,  
                                         const int x, const int y,  
                                         const uint32_t MotionFlags,  
                                         MBParam * const pParam,  
                                         MACROBLOCK * const pMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
 {  
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iFcode = pParam->fixed_code;  
         const int32_t iQuant = pParam->quant;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
602    
603          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;                          InterBias = MV16_INTER_BIAS;
604                            if (pMB->quant > 8)  InterBias += 50 * (pMB->quant - 8); // to make high quants work
605                            if (y != 0)
606                                    if ((pMB - pParam->mb_width)->mode == MODE_INTER ) InterBias -= 50;
607                            if (x != 0)
608                                    if ((pMB - 1)->mode == MODE_INTER ) InterBias -= 50;
609    
610          int32_t iDiamondSize;                          if (InterBias < pMB->sad16)  {
611                                    const int32_t deviation =
612                                            dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,
613                                                      pParam->edged_width);
614    
615          int32_t min_dx;                                  if (deviation < (pMB->sad16 - InterBias)) {
616          int32_t max_dx;                                          if (++iIntra >= iLimit) return 1;
617          int32_t min_dy;                                          pMB->mode = MODE_INTRA;
618          int32_t max_dy;                                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =
619                                                            pMB->mvs[3] = zeroMV;
620                                            pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =
621                                                    pMB->sad8[3] = 0;
622                                    }
623                            }
624                    }
625            }
626            return 0;
627    }
628    
         int32_t iFound;  
629    
630          VECTOR newMV;  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)
         VECTOR backupMV;        /* just for PMVFAST */  
631    
632          VECTOR pmv[4];  static __inline int
633          int32_t psad[4];  make_mask(const VECTOR * const pmv, const int i)
634    {
635            int mask = 255, j;
636            for (j = 0; j < i; j++) {
637                    if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already
638                    if (pmv[i].x == pmv[j].x) {
639                            if (pmv[i].y == pmv[j].y + iDiamondSize) { mask &= ~4; continue; }
640                            if (pmv[i].y == pmv[j].y - iDiamondSize) { mask &= ~8; continue; }
641                    } else
642                            if (pmv[i].y == pmv[j].y) {
643                                    if (pmv[i].x == pmv[j].x + iDiamondSize) { mask &= ~1; continue; }
644                                    if (pmv[i].x == pmv[j].x - iDiamondSize) { mask &= ~2; continue; }
645                            }
646            }
647            return mask;
648    }
649    
650          MACROBLOCK * const pMB = pMBs + x + y * iWcount;  static __inline void
651    PreparePredictionsP(VECTOR * const pmv, int x, int y, const int iWcount,
652                            const int iHcount, const MACROBLOCK * const prevMB)
653    {
654    
655          static int32_t threshA,threshB;  //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself
         int32_t bPredEq;  
         int32_t iMinSAD,iSAD;  
656    
657  /* Get maximum range */          if ( (y != 0) && (x != (iWcount-1)) ) {         // [5] top-right neighbour
658          get_range(&min_dx, &max_dx, &min_dy, &max_dy,                  pmv[5].x = EVEN(pmv[3].x);
659                          x, y, 16, iWidth, iHeight, iFcode);                  pmv[5].y = EVEN(pmv[3].y);
660            } else pmv[5].x = pmv[5].y = 0;
661    
662  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }// pmv[3] is left neighbour
663            else pmv[3].x = pmv[3].y = 0;
664    
665          if (!(MotionFlags & PMV_HALFPEL16 ))          if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }// [4] top neighbour
666          { min_dx = EVEN(min_dx);      else pmv[4].x = pmv[4].y = 0;
           max_dx = EVEN(max_dx);  
           min_dy = EVEN(min_dy);  
           max_dy = EVEN(max_dy);  
         }               /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
667    
668            // [1] median prediction
669            pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
670    
671          bPredEq  = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);          pmv[0].x = pmv[0].y = 0; // [0] is zero; not used in the loop (checked before) but needed here for make_mask
672    
673          if ((x==0) && (y==0) )          pmv[2].x = EVEN(prevMB->mvs[0].x); // [2] is last frame
674          {          pmv[2].y = EVEN(prevMB->mvs[0].y);
                 threshA =  512;  
                 threshB = 1024;  
675    
676            if ((x != iWcount-1) && (y != iHcount-1)) {
677                    pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); //[6] right-down neighbour in last frame
678                    pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
679            } else pmv[6].x = pmv[6].y = 0;
680          }          }
681          else  
682          {  static void
683                  threshA = psad[0];  SearchP(const uint8_t * const pRef,
684                  threshB = threshA+256;                  const uint8_t * const pRefH,
685                    const uint8_t * const pRefV,
686                    const uint8_t * const pRefHV,
687                    const IMAGE * const pCur,
688                    const int x,
689                    const int y,
690                    const uint32_t MotionFlags,
691                    const uint32_t iQuant,
692                    SearchData * const Data,
693                    const MBParam * const pParam,
694                    const MACROBLOCK * const pMBs,
695                    const MACROBLOCK * const prevMBs,
696                    int inter4v,
697                    MACROBLOCK * const pMB)
698    {
699    
700            int i, iDirection = 255, mask, threshA;
701            VECTOR pmv[7];
702    
703            get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);  //has to be changed to get_pmv(2)()
704            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
705                                    pParam->width, pParam->height, Data->iFcode);
706    
707            Data->predMV = pmv[0];
708            Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16;
709            Data->Ref = pRef + (x + Data->iEdgedWidth*y)*16;
710            Data->RefH = pRefH + (x + Data->iEdgedWidth*y) * 16;
711            Data->RefV = pRefV + (x + Data->iEdgedWidth*y) * 16;
712            Data->RefHV = pRefHV + (x + Data->iEdgedWidth*y) * 16;
713    
714            Data->iQuant = iQuant;
715    
716            if (!(MotionFlags & PMV_HALFPEL16)) {
717                    Data->min_dx = EVEN(Data->min_dx);
718                    Data->max_dx = EVEN(Data->max_dx);
719                    Data->min_dy = EVEN(Data->min_dy);
720                    Data->max_dy = EVEN(Data->max_dy); }
721    
722            for(i = 0;  i < 5; i++) Data->iMinSAD[i] = 256*4096;
723    
724            if (inter4v) CheckCandidate = CheckCandidate16;
725            else CheckCandidate = CheckCandidate16no4v;
726    
727            (*CheckCandidate)(Data->predMV.x, Data->predMV.y, 0, &iDirection, Data);
728    
729            for(i = 0;  i < 5; i++) Data->currentMV[i].x = Data->currentMV[i].y = 0;
730    
731            i = d_mv_bits(Data->predMV.x, Data->predMV.y, Data->iFcode);
732            Data->iMinSAD[0] = pMB->sad16 + lambda_vec16[iQuant] * i;
733            Data->iMinSAD[1] = pMB->sad8[0] + lambda_vec8[iQuant] * i;
734            Data->iMinSAD[2] = pMB->sad8[1];
735            Data->iMinSAD[3] = pMB->sad8[2];
736            Data->iMinSAD[4] = pMB->sad8[3];
737    
738            if (pMB->dquant != NO_CHANGE) inter4v = 0;
739    
740            if ((x == 0) && (y == 0)) threshA = 512;
741            else {
742                    threshA = Data->temp[0] + 20;
743                  if (threshA< 512) threshA =  512;                  if (threshA< 512) threshA =  512;
744                  if (threshA>1024) threshA = 1024;                  if (threshA > 1024) threshA = 1024; }
                 if (threshB>1792) threshB = 1792;  
         }  
745    
746          iFound=0;          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
747                                            prevMBs + x + y * pParam->mb_width);
748    
749  /* Step 2: Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  /* main loop. checking all predictions */
750          vector of the median.  
751          If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2          for (i = 1; i < 7; i++) {
752  */                  if (!(mask = make_mask(pmv, i)) ) continue;
753                    CheckCandidate16(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
754                    if (Data->iMinSAD[0] <= threshA) break;
755            }
756    
757          if ((bPredEq) && (MVequal(pmv[0],pMB->mvs[0]) ) )          if ((Data->iMinSAD[0] <= threshA) ||
758                  iFound=2;                          (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
759                            (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16))) {
760                    inter4v = 0;
761            } else {
762    
763  /* Step 3: If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.                  MainSearchFunc * MainSearchPtr;
764          Otherwise select large Diamond Search.                  if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
765  */                  else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
766                            else MainSearchPtr = DiamondSearch;
767    
768          if ( (pmv[0].x != 0) || (pmv[0].y != 0) || (threshB<1536) || (bPredEq) )                  (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
                 iDiamondSize=1; // halfpel!  
         else  
                 iDiamondSize=2; // halfpel!  
   
         if (!(MotionFlags & PMV_HALFPELDIAMOND16) )  
                 iDiamondSize*=2;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
         MinSAD=SAD  
         If Motion Vector equal to Previous frame motion vector  
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
 */  
769    
770    /* extended search, diamond starting in 0,0 and in prediction.
771            note that this search is/might be done in halfpel positions,
772            which makes it more different than the diamond above */
773    
774  // Prepare for main loop                  if (MotionFlags & PMV_EXTSEARCH16) {
775                            int32_t bSAD;
776                            VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
777                            if (!(MotionFlags & PMV_HALFPELREFINE16)) // who's gonna use extsearch and no halfpel?
778                                    startMV.x = EVEN(startMV.x); startMV.y = EVEN(startMV.y);
779                            if (!(MVequal(startMV, backupMV))) {
780                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
781    
782          *currMV=pmv[0];         /* current best := prediction */                                  CheckCandidate16(startMV.x, startMV.y, 255, &iDirection, Data);
783          if (!(MotionFlags & PMV_HALFPEL16 ))                                  (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
784          {       /* This should NOT be necessary! */                                  if (bSAD < Data->iMinSAD[0]) {
785                  currMV->x = EVEN(currMV->x);                                          Data->currentMV[0] = backupMV;
786                  currMV->y = EVEN(currMV->y);                                          Data->iMinSAD[0] = bSAD; }
787          }          }
788    
789          if (currMV->x > max_dx)                          backupMV = Data->currentMV[0];
790                  {                          if (MotionFlags & PMV_HALFPELREFINE16) startMV.x = startMV.y = 1;
791                          currMV->x=max_dx;                          else startMV.x = startMV.y = 0;
792                  }                          if (!(MVequal(startMV, backupMV))) {
793          if (currMV->x < min_dx)                                  bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
794                  {  
795                          currMV->x=min_dx;                                  CheckCandidate16(startMV.x, startMV.y, 255, &iDirection, Data);
796                                    (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
797                                    if (bSAD < Data->iMinSAD[0]) {
798                                            Data->currentMV[0] = backupMV;
799                                            Data->iMinSAD[0] = bSAD; }
800                  }                  }
         if (currMV->y > max_dy)  
                 {  
                         currMV->y=max_dy;  
801                  }                  }
         if (currMV->y < min_dy)  
                 {  
                         currMV->y=min_dy;  
802                  }                  }
803    
804          iMinSAD = sad16( cur,          if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(Data);
                 get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV, iEdgedWidth),  
                 iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD += calc_delta_16(currMV->x-pmv[0].x, currMV->y-pmv[0].y, (uint8_t)iFcode) * iQuant;  
805    
806          if ( (iMinSAD < 256 ) || ( (MVequal(*currMV,pMB->mvs[0])) && (iMinSAD < pMB->sad16) ) )          if (inter4v) {
807                  {                  SearchData Data8;
808                    Data8.iFcode = Data->iFcode;
809                          if (MotionFlags & PMV_QUICKSTOP16)                  Data8.iQuant = Data->iQuant;
810                                  goto step10b;                  Data8.iEdgedWidth = Data->iEdgedWidth;
811                          if (MotionFlags & PMV_EARLYSTOP16)                  Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
812                                  goto step10;                  Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
813                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
814                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
815                  }                  }
816    
817  /*          if (!(inter4v) ||
818  Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.                  (Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
819          Also calculate (0,0) but do not subtract offset.                          Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {
820          Let MinSAD be the smallest SAD up to this point.  // INTER MODE
821          If MV is (0,0) subtract offset. ******** WHAT'S THIS 'OFFSET' ??? ***********                  pMB->mode = MODE_INTER;
822  */                  pMB->mvs[0] = pMB->mvs[1]
823                            = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
 // (0,0) is always possible  
   
         CHECK_MV16_ZERO;  
824    
825  // previous frame MV is always possible                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
826          CHECK_MV16_CANDIDATE(pMB->mvs[0].x,pMB->mvs[0].y);                          pMB->sad8[2] = pMB->sad8[3] =  Data->iMinSAD[0];
827    
828  // left neighbour, if allowed                  pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
829          if (x != 0)                  pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
830          {          } else {
831                  if (!(MotionFlags & PMV_HALFPEL16 ))  // INTER4V MODE; all other things are already set in Search8
832                  {       pmv[1].x = EVEN(pmv[1].x);                  pMB->mode = MODE_INTER4V;
833                          pmv[1].y = EVEN(pmv[1].y);                  pMB->sad16 = Data->iMinSAD[1] + Data->iMinSAD[2] +
834                  }                          Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * iQuant;
                 CHECK_MV16_CANDIDATE(pmv[1].x,pmv[1].y);  
835          }          }
836    
 // top neighbour, if allowed  
         if (y != 0)  
         {  
                 if (!(MotionFlags & PMV_HALFPEL16 ))  
                 {       pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
837                  }                  }
                 CHECK_MV16_CANDIDATE(pmv[2].x,pmv[2].y);  
838    
839  // top right neighbour, if allowed  static void
840                  if (x != (iWcount-1))  Search8(const SearchData * const OldData,
841                    const int x, const int y,
842                    const uint32_t MotionFlags,
843                    const MBParam * const pParam,
844                    MACROBLOCK * const pMB,
845                    const MACROBLOCK * const pMBs,
846                    const int block,
847                    SearchData * const Data)
848                  {                  {
849                          if (!(MotionFlags & PMV_HALFPEL16 ))          Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2 , y/2, block);
850                          {       pmv[3].x = EVEN(pmv[3].x);          Data->iMinSAD = OldData->iMinSAD + 1 + block;
851                                  pmv[3].y = EVEN(pmv[3].y);          Data->currentMV = OldData->currentMV + 1 + block;
                         }  
                         CHECK_MV16_CANDIDATE(pmv[3].x,pmv[3].y);  
                 }  
         }  
852    
853  /* Step 6: If MinSAD <= thresa goto Step 10.          if (block != 0)
854     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.                  *(Data->iMinSAD) += lambda_vec8[Data->iQuant] *
855  */                                                                  d_mv_bits(      Data->currentMV->x - Data->predMV.x,
856                                                                                            Data->currentMV->y - Data->predMV.y,
857                                                                                            Data->iFcode);
858    
859          if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[0]) && (iMinSAD < pMB->sad16) ) )          if (MotionFlags & (PMV_EXTSEARCH8|PMV_HALFPELREFINE8)) {
                 {  
                         if (MotionFlags & PMV_QUICKSTOP16)  
                                 goto step10b;  
                         if (MotionFlags & PMV_EARLYSTOP16)  
                                 goto step10;  
                 }  
860    
861                    Data->Ref = OldData->Ref + 8 * ((block&1) + pParam->edged_width*(block>>1));
862                    Data->RefH = OldData->RefH + 8 * ((block&1) + pParam->edged_width*(block>>1));
863                    Data->RefV = OldData->RefV + 8 * ((block&1) + pParam->edged_width*(block>>1));
864                    Data->RefHV = OldData->RefHV + 8 * ((block&1) + pParam->edged_width*(block>>1));
865    
866  /************ (Diamond Search)  **************/                  Data->Cur = OldData->Cur + 8 * ((block&1) + pParam->edged_width*(block>>1));
 /*  
 Step 7: Perform Diamond search, with either the small or large diamond.  
         If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
 Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
         If center then goto step 10.  
 Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
         Refine by using small diamond and goto step 10.  
 */  
867    
868          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
869                                    pParam->width, pParam->height, OldData->iFcode);
870    
871  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                  CheckCandidate = CheckCandidate8;
         iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,  
                 x, y,  
                 currMV->x, currMV->y, iMinSAD, &newMV,  
                 pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);  
872    
873          if (iSAD < iMinSAD)                  if (MotionFlags & PMV_EXTSEARCH8) {
         {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
874    
875          if (MotionFlags & PMV_EXTSEARCH16)                          MainSearchFunc *MainSearchPtr;
876          {                          if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
877  /* extended: search (up to) two more times: orignal prediction and (0,0) */                                  else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
878                                            else MainSearchPtr = DiamondSearch;
879    
880                  if (!(MVequal(pmv[0],backupMV)) )                          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);    }
                 {       iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,  
                                 x, y,  
                         pmv[0].x, pmv[0].y, iMinSAD, &newMV,  
                         pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);  
881    
882                          if (iSAD < iMinSAD)                  if (MotionFlags & PMV_HALFPELREFINE8) HalfpelRefine(Data);
                         {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
883                          }                          }
884    
885            pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
886            pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
887            pMB->mvs[block] = *(Data->currentMV);
888            pMB->sad8[block] =  4 * (*Data->iMinSAD);
889    
890                  }                  }
891    
892                  if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )  /* B-frames code starts here */
                 {       iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,  
                                 x, y,  
                         0, 0, iMinSAD, &newMV,  
                         pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);  
893    
894                          if (iSAD < iMinSAD)  static __inline VECTOR
895    ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
896                          {                          {
897                                  *currMV = newMV;  /* the stupidiest function ever */
898                                  iMinSAD = iSAD;          if (mode == MODE_FORWARD) return pMB->mvs[0];
899                          }          else return pMB->b_mvs[0];
                 }  
900          }          }
901    
902  /*  static void __inline
903          Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
904  */                                                          const uint32_t iWcount,
905                                                            const MACROBLOCK * const pMB,
906                                                            const uint32_t mode_curr)
907    {
908    
909  step10:          // [0] is prediction
910          if (MotionFlags & PMV_HALFPELREFINE16)          // perform final half-pel step          pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
                 iMinSAD = PMVfastSearch16_Refine( pRef, pRefH, pRefV, pRefHV, cur,  
                                 x, y,  
                                 currMV, iMinSAD,  
                                 pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);  
   
 step10b:  
         currPMV->x = currMV->x - pmv[0].x;  
         currPMV->y = currMV->y - pmv[0].y;  
         return iMinSAD;  
 }  
911    
912            pmv[1].x = pmv[1].y = 0; // [1] is zero
913    
914            pmv[2] = ChoosePred(pMB, mode_curr);
915            pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
916    
917            if ((y != 0)&&(x != (int)(iWcount+1))) {                        // [3] top-right neighbour
918                    pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
919                    pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
920            } else pmv[3].x = pmv[3].y = 0;
921    
922            if (y != 0) {
923                    pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
924                    pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
925            } else pmv[4].x = pmv[4].y = 0;
926    
927            if (x != 0) {
928                    pmv[5] = ChoosePred(pMB-1, mode_curr);
929                    pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
930            } else pmv[5].x = pmv[5].y = 0;
931    
932  int32_t PMVfastSearch8_MainSearch(          if ((x != 0)&&(y != 0)) {
933                                          const uint8_t * const pRef,                  pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
934                                          const uint8_t * const pRefH,                  pmv[6].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
935                                          const uint8_t * const pRefV,          } else pmv[6].x = pmv[6].y = 0;
936                                          const uint8_t * const pRefHV,  
937                                          const uint8_t * const cur,  // more?
                                         const int x, const int y,  
                                         int32_t startx, int32_t starty,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                         const VECTOR * const pmv,  
                                         const int32_t min_dx, const int32_t max_dx,  
                                         const int32_t min_dy, const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iDirection=0;  
         int32_t iSAD;  
         VECTOR backupMV;  
         backupMV.x = startx;  
         backupMV.y = starty;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         CHECK_MV8_CANDIDATE_DIR(backupMV.x-iDiamondSize,backupMV.y,1);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x+iDiamondSize,backupMV.y,2);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x,backupMV.y-iDiamondSize,3);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x,backupMV.y+iDiamondSize,4);  
   
         if (iDirection)  
                 while (!iFound)  
                 {  
                         iFound = 1;  
                         backupMV=*currMV;       // since iDirection!=0, this is well defined!  
   
                         if ( iDirection != 2)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x-iDiamondSize,backupMV.y,1);  
                         if ( iDirection != 1)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x+iDiamondSize,backupMV.y,2);  
                         if ( iDirection != 4)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,backupMV.y-iDiamondSize,3);  
                         if ( iDirection != 3)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,backupMV.y+iDiamondSize,4);  
                 }  
         else  
                 {  
                         currMV->x = startx;  
                         currMV->y = starty;  
                 }  
         return iMinSAD;  
938  }  }
939    
940  int32_t PMVfastSearch8_Refine(  
941                                          const uint8_t * const pRef,  /* search backward or forward, for b-frames */
942    static void
943    SearchBF(       const uint8_t * const pRef,
944                                          const uint8_t * const pRefH,                                          const uint8_t * const pRefH,
945                                          const uint8_t * const pRefV,                                          const uint8_t * const pRefV,
946                                          const uint8_t * const pRefHV,                                          const uint8_t * const pRefHV,
947                                          const uint8_t * const cur,                          const IMAGE * const pCur,
948                                          const int x, const int y,                                          const int x, const int y,
949                                          VECTOR * const currMV,                          const uint32_t MotionFlags,
950                                          int32_t iMinSAD,                          const uint32_t iQuant,
951                                          const VECTOR * const pmv,                          const uint32_t iFcode,
952                                          const int32_t min_dx, const int32_t max_dx,                          const MBParam * const pParam,
953                                          const int32_t min_dy, const int32_t max_dy,                          MACROBLOCK * const pMB,
954                                          const int32_t iFcode,                          const VECTOR * const predMV,
955                                          const int32_t iQuant,                          int32_t * const best_sad,
956                                          const int32_t iEdgedWidth)                          const int32_t mode_current)
957  {  {
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
958    
959          int32_t iSAD;          const int32_t iEdgedWidth = pParam->edged_width;
         VECTOR backupMV = *currMV;  
960    
961          CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y-1);          int i, iDirection, mask;
962          CHECK_MV8_CANDIDATE(backupMV.x  ,backupMV.y-1);          VECTOR currentMV, pmv[7];
963          CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y-1);          MainSearchFunc *MainSearchPtr;
964          CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y);          int32_t iMinSAD = MV_MAX_ERROR;
965          CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y);          SearchData Data;
966          CHECK_MV8_CANDIDATE(backupMV.x-1,backupMV.y+1);  
967          CHECK_MV8_CANDIDATE(backupMV.x  ,backupMV.y+1);          Data.iMinSAD = &iMinSAD;
968          CHECK_MV8_CANDIDATE(backupMV.x+1,backupMV.y+1);          Data.Cur = pCur->y + (x + y * iEdgedWidth) * 16;
969            Data.iEdgedWidth = iEdgedWidth;
970            Data.currentMV = &currentMV;
971            Data.iMinSAD = &iMinSAD;
972            Data.Ref = pRef + (x + y * iEdgedWidth) * 16;
973            Data.RefH = pRefH + (x + y * iEdgedWidth) * 16;
974            Data.RefV = pRefV + (x + y * iEdgedWidth) * 16;
975            Data.RefHV = pRefHV + (x + y * iEdgedWidth) * 16;
976    
977            Data.iQuant = iQuant;
978            Data.iFcode = iFcode;
979            Data.predMV = *predMV;
980    
981            get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 16,
982                                    pParam->width, pParam->height, iFcode);
983    
984            if (!(MotionFlags & PMV_HALFPEL16)) {
985                    Data.min_dx = EVEN(Data.min_dx);
986                    Data.max_dx = EVEN(Data.max_dx);
987                    Data.min_dy = EVEN(Data.min_dy);
988                    Data.max_dy = EVEN(Data.max_dy); } // no-halpel and b-frames. do we need it?
989    
990    
991            pmv[0] = Data.predMV;
992            PreparePredictionsBF(pmv, x, y, pParam->mb_width,
993                                            pMB, mode_current);
994    
995            currentMV.x = currentMV.y = 0;
996    
997            CheckCandidate = CheckCandidate16no4v;
998    
999    // main loop. checking all predictions
1000            for (i = 0; i < 8; i++) {
1001                    if (!(mask = make_mask(pmv, i)) ) continue;
1002                    CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, &Data);
1003            }
1004    
1005            if (MotionFlags & PMV_USESQUARES16)
1006                    MainSearchPtr = SquareSearch;
1007            else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
1008                    MainSearchPtr = AdvDiamondSearch;
1009                    else MainSearchPtr = DiamondSearch;
1010    
1011            (*MainSearchPtr)(currentMV.x, currentMV.y, &Data, 255);
1012    
1013            if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(&Data);
1014    
1015    // three bits are needed to code backward mode. four for forward
1016    // we treat the bits just like they were vector's
1017            if (mode_current == MODE_FORWARD) iMinSAD +=  4 * lambda_vec16[iQuant];
1018            else iMinSAD +=  3 * lambda_vec16[iQuant];
1019    
1020    
1021            if (iMinSAD < *best_sad) {
1022                    *best_sad = iMinSAD;
1023                    pMB->mode = mode_current;
1024                    pMB->pmvs[0].x = currentMV.x - predMV->x;
1025                    pMB->pmvs[0].y = currentMV.y - predMV->y;
1026                    if (mode_current == MODE_FORWARD) pMB->mvs[0] = currentMV;
1027                    else pMB->b_mvs[0] = currentMV;
1028            }
1029    
1030    }
1031    
1032    static int32_t
1033    SearchDirect(const IMAGE * const f_Ref,
1034                                    const uint8_t * const f_RefH,
1035                                    const uint8_t * const f_RefV,
1036                                    const uint8_t * const f_RefHV,
1037                                    const IMAGE * const b_Ref,
1038                                    const uint8_t * const b_RefH,
1039                                    const uint8_t * const b_RefV,
1040                                    const uint8_t * const b_RefHV,
1041                                    const IMAGE * const pCur,
1042                                    const int x, const int y,
1043                                    const uint32_t MotionFlags,
1044                                    const uint32_t iQuant,
1045                                    const int32_t TRB, const int32_t TRD,
1046                                    const MBParam * const pParam,
1047                                    MACROBLOCK * const pMB,
1048                                    const MACROBLOCK * const b_mb,
1049                                    int32_t * const best_sad)
1050    
1051    {
1052            const uint32_t iEdgedWidth = pParam->edged_width;
1053            int32_t iMinSAD = 266*4096, skip_sad;
1054            int k;
1055            VECTOR currentMV;
1056            MainSearchFunc *MainSearchPtr;
1057            SearchData Data;
1058    
1059            Data.iMinSAD = &iMinSAD;
1060            Data.Cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;
1061            Data.iEdgedWidth = iEdgedWidth;
1062            Data.currentMV = &currentMV;
1063            Data.iQuant = iQuant;
1064            Data.referencemv = b_mb->mvs;
1065    
1066            Data.Ref= f_Ref->y + (x + iEdgedWidth*y) * 16;
1067            Data.RefH = f_RefH + (x + iEdgedWidth*y) * 16;
1068            Data.RefV = f_RefV + (x + iEdgedWidth*y) * 16;
1069            Data.RefHV = f_RefHV + (x + iEdgedWidth*y) * 16;
1070            Data.bRef = b_Ref->y + (x + iEdgedWidth*y) * 16;
1071            Data.bRefH = b_RefH + (x + iEdgedWidth*y) * 16;
1072            Data.bRefV = b_RefV + (x + iEdgedWidth*y) * 16;
1073            Data.bRefHV = b_RefHV + (x + iEdgedWidth*y) * 16;
1074    /*
1075    //What we do here is a complicated version of CheckCandidateDirect(0,0);
1076    get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 16, pParam->width, pParam->height, 19);
1077    
1078    */
1079            Data.max_dx = 2 * pParam->width - 2 * (x) * 16;
1080            Data.max_dy = 2 * pParam->height - 2 * (y) * 16;
1081            Data.min_dx = -(2 * 16 + 2 * (x) * 16);
1082            Data.min_dy = -(2 * 16 + 2 * (y) * 16);
1083    
1084            for (k = 0; k < 4; k++) {
1085                    pMB->mvs[k].x = Data.directmvF[k].x = ((TRB * Data.referencemv[k].x) / TRD);
1086                    pMB->b_mvs[k].x = Data.directmvB[k].x = ((TRB - TRD) * Data.referencemv[k].x) / TRD;
1087                    pMB->mvs[k].y = Data.directmvF[k].y = ((TRB * Data.referencemv[k].y) / TRD);
1088                    pMB->b_mvs[k].y = Data.directmvB[k].y = ((TRB - TRD) * Data.referencemv[k].y) / TRD;
1089    
1090                    if (( pMB->mvs[k].x > Data.max_dx ) || ( pMB->mvs[k].x < Data.min_dx )
1091                            || ( pMB->mvs[k].y > Data.max_dy ) || ( pMB->mvs[k].y < Data.min_dy )
1092                            || ( pMB->b_mvs[k].x > Data.max_dx ) || ( pMB->b_mvs[k].x < Data.min_dx )
1093                            || ( pMB->b_mvs[k].y > Data.max_dy ) || ( pMB->b_mvs[k].y < Data.min_dy )) {
1094    
1095                            *best_sad = 256*4096; // in that case, we won't use direct mode
1096                            pMB->mode = MODE_DIRECT; // just to make sure it doesn't say "MODE_DIRECT_NONE_MV"
1097                            pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;
1098                            return 0;
1099                    }
1100                    if (b_mb->mode != MODE_INTER4V) {
1101                            pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mvs[0];
1102                            pMB->b_mvs[1] = pMB->b_mvs[2] = pMB->b_mvs[3] = pMB->b_mvs[0];
1103                            Data.directmvF[1] = Data.directmvF[2] = Data.directmvF[3] = Data.directmvF[0];
1104                            Data.directmvB[1] = Data.directmvB[2] = Data.directmvB[3] = Data.directmvB[0];
1105                            break;
1106                    }
1107            }
1108    
1109            if (b_mb->mode == MODE_INTER4V)
1110                    CheckCandidate = CheckCandidateDirect;
1111            else CheckCandidate = CheckCandidateDirectno4v;
1112    
1113            (*CheckCandidate)(0, 0, 255, &k, &Data);
1114    
1115    // skip decision
1116            if (iMinSAD - 2 * lambda_vec16[iQuant] < (int32_t)iQuant * SKIP_THRESH_B) {
1117                    //checking chroma. everything copied from MC
1118                    //this is not full chroma compensation, only it's fullpel approximation. should work though
1119                    int sum, dx, dy, b_dx, b_dy;
1120    
1121                    sum = pMB->mvs[0].x + pMB->mvs[1].x + pMB->mvs[2].x + pMB->mvs[3].x;
1122                    dx = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1123    
1124                    sum = pMB->mvs[0].y + pMB->mvs[1].y + pMB->mvs[2].y + pMB->mvs[3].y;
1125                    dy = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1126    
1127                    sum = pMB->b_mvs[0].x + pMB->b_mvs[1].x + pMB->b_mvs[2].x + pMB->b_mvs[3].x;
1128                    b_dx = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1129    
1130                    sum = pMB->b_mvs[0].y + pMB->b_mvs[1].y + pMB->b_mvs[2].y + pMB->b_mvs[3].y;
1131                    b_dy = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1132    
1133                    sum = sad8bi(pCur->u + 8*x + 8*y*(iEdgedWidth/2),
1134                                            f_Ref->u + (y*8 + dy/2) * (iEdgedWidth/2) + x*8 + dx/2,
1135                                            b_Ref->u + (y*8 + b_dy/2) * (iEdgedWidth/2) + x*8 + b_dx/2,
1136                                            iEdgedWidth/2);
1137                    sum += sad8bi(pCur->v + 8*x + 8*y*(iEdgedWidth/2),
1138                                            f_Ref->v + (y*8 + dy/2) * (iEdgedWidth/2) + x*8 + dx/2,
1139                                            b_Ref->v + (y*8 + b_dy/2) * (iEdgedWidth/2) + x*8 + b_dx/2,
1140                                            iEdgedWidth/2);
1141    
1142                    if ((uint32_t) sum < MAX_CHROMA_SAD_FOR_SKIP * Data.iQuant) {
1143                            pMB->mode = MODE_DIRECT_NONE_MV;
1144          return iMinSAD;          return iMinSAD;
1145  }  }
1146            }
1147    
1148            skip_sad = iMinSAD;
1149    
1150  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)  //  DIRECT MODE DELTA VECTOR SEARCH.
1151    //      This has to be made more effective, but at the moment I'm happy it's running at all
1152    
1153  int32_t PMVfastSearch8(          if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1154                                          const uint8_t * const pRef,                  else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1155                                          const uint8_t * const pRefH,                          else MainSearchPtr = DiamondSearch;
1156                                          const uint8_t * const pRefV,  
1157                                          const uint8_t * const pRefHV,          (*MainSearchPtr)(0, 0, &Data, 255);
1158    
1159            HalfpelRefine(&Data);
1160    
1161            iMinSAD +=  1 * lambda_vec16[iQuant]; // one bit is needed to code direct mode. we treat this bit just like it was vector's
1162            *best_sad = iMinSAD;
1163    
1164            if (b_mb->mode == MODE_INTER4V)
1165                    pMB->mode = MODE_DIRECT;
1166            else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation
1167    
1168            pMB->pmvs[3] = currentMV;
1169    
1170            for (k = 0; k < 4; k++) {
1171                    pMB->mvs[k].x = Data.directmvF[k].x + currentMV.x;
1172                    pMB->b_mvs[k].x = ((currentMV.x == 0)
1173                                                            ? Data.directmvB[k].x
1174                                                            : pMB->mvs[k].x - Data.referencemv[k].x);
1175                    pMB->mvs[k].y = (Data.directmvF[k].y + currentMV.y);
1176                    pMB->b_mvs[k].y = ((currentMV.y == 0)
1177                                                            ? Data.directmvB[k].y
1178                                                            : pMB->mvs[k].y - Data.referencemv[k].y);
1179                    if (b_mb->mode != MODE_INTER4V) {
1180                            pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1181                            pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1182                            break;
1183                    }
1184            }
1185            return 0;//skip_sad;
1186    }
1187    
1188    static __inline void
1189    SearchInterpolate(const uint8_t * const f_Ref,
1190                                    const uint8_t * const f_RefH,
1191                                    const uint8_t * const f_RefV,
1192                                    const uint8_t * const f_RefHV,
1193                                    const uint8_t * const b_Ref,
1194                                    const uint8_t * const b_RefH,
1195                                    const uint8_t * const b_RefV,
1196                                    const uint8_t * const b_RefHV,
1197                                          const IMAGE * const pCur,                                          const IMAGE * const pCur,
1198                                          const int x, const int y,                                          const int x, const int y,
1199                                          const int start_x, int start_y,                                  const uint32_t fcode,
1200                                    const uint32_t bcode,
1201                                          const uint32_t MotionFlags,                                          const uint32_t MotionFlags,
1202                                          MBParam * const pParam,                                  const uint32_t iQuant,
1203                                          MACROBLOCK * const pMBs,                                  const MBParam * const pParam,
1204                                          VECTOR * const currMV,                                  const VECTOR * const f_predMV,
1205                                          VECTOR * const currPMV)                                  const VECTOR * const b_predMV,
1206                                    MACROBLOCK * const pMB,
1207                                    int32_t * const best_sad)
1208    
1209  {  {
1210          const uint32_t iWcount = pParam->mb_width;  /* Interpolated MC motion vector search, this is tedious and more complicated because there are
1211       two values for everything, always one for backward and one for forward ME. Still, we don't gain
1212       much from this search, maybe it should simply be skipped and simply current i_sad16 value used
1213       as "optimal". */
1214    
         const int32_t iFcode = pParam->fixed_code;  
         const int32_t iQuant = pParam->quant;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
1215          const int32_t iEdgedWidth = pParam->edged_width;          const int32_t iEdgedWidth = pParam->edged_width;
1216    
1217          const uint8_t * cur = pCur->y + x*8 + y*8*iEdgedWidth;          int iDirection, i, j;
1218            int32_t iMinSAD = 256*4096;
1219            VECTOR currentMV[3];
1220            SearchData fData, bData;
1221    
1222            fData.iMinSAD = bData.iMinSAD = &iMinSAD;
1223    
1224            fData.Cur = bData.Cur = pCur->y + (x + y * iEdgedWidth) * 16;
1225            fData.iEdgedWidth = bData.iEdgedWidth = iEdgedWidth;
1226            fData.currentMV = currentMV; bData.currentMV = currentMV + 1;
1227            fData.iQuant = bData.iQuant = iQuant;
1228            fData.iFcode = bData.bFcode = fcode; fData.bFcode = bData.iFcode = bcode;
1229    
1230            bData.bRef = fData.Ref = f_Ref + (x + y * iEdgedWidth) * 16;
1231            bData.bRefH = fData.RefH = f_RefH + (x + y * iEdgedWidth) * 16;
1232            bData.bRefV = fData.RefV = f_RefV + (x + y * iEdgedWidth) * 16;
1233            bData.bRefHV = fData.RefHV = f_RefHV + (x + y * iEdgedWidth) * 16;
1234            bData.Ref = fData.bRef = b_Ref + (x + y * iEdgedWidth) * 16;
1235            bData.RefH = fData.bRefH = b_RefH + (x + y * iEdgedWidth) * 16;
1236            bData.RefV = fData.bRefV = b_RefV + (x + y * iEdgedWidth) * 16;
1237            bData.RefHV = fData.bRefHV = b_RefHV + (x + y * iEdgedWidth) * 16;
1238    
1239            bData.bpredMV = fData.predMV = *f_predMV;
1240            fData.bpredMV = bData.predMV = *b_predMV;
1241    
1242            currentMV[0] = pMB->mvs[0];
1243            currentMV[1] = pMB->b_mvs[0];
1244            get_range(&fData.min_dx, &fData.max_dx, &fData.min_dy, &fData.max_dy, x, y, 16, pParam->width, pParam->height, fcode);
1245            get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode);
1246    
1247            if (currentMV[0].x > fData.max_dx) currentMV[0].x = fData.max_dx;
1248            if (currentMV[0].x < fData.min_dx) currentMV[0].x = fData.min_dy;
1249            if (currentMV[0].y > fData.max_dy) currentMV[0].y = fData.max_dx;
1250            if (currentMV[0].y > fData.min_dy) currentMV[0].y = fData.min_dy;
1251    
1252            if (currentMV[1].x > bData.max_dx) currentMV[1].x = bData.max_dx;
1253            if (currentMV[1].x < bData.min_dx) currentMV[1].x = bData.min_dy;
1254            if (currentMV[1].y > bData.max_dy) currentMV[1].y = bData.max_dx;
1255            if (currentMV[1].y > bData.min_dy) currentMV[1].y = bData.min_dy;
1256    
1257            CheckCandidateInt(currentMV[0].x, currentMV[0].y, 255, &iDirection, &fData);
1258    
1259    //diamond. I wish we could use normal mainsearch functions (square, advdiamond)
1260    
1261            do {
1262                    iDirection = 255;
1263                    // forward MV moves
1264                    i = currentMV[0].x; j = currentMV[0].y;
1265    
1266                    CheckCandidateInt(i + 1, j, 0, &iDirection, &fData);
1267                    CheckCandidateInt(i, j + 1, 0, &iDirection, &fData);
1268                    CheckCandidateInt(i - 1, j, 0, &iDirection, &fData);
1269                    CheckCandidateInt(i, j - 1, 0, &iDirection, &fData);
1270    
1271                    // backward MV moves
1272                    i = currentMV[1].x; j = currentMV[1].y;
1273                    currentMV[2] = currentMV[0];
1274    
1275                    CheckCandidateInt(i + 1, j, 0, &iDirection, &bData);
1276                    CheckCandidateInt(i, j + 1, 0, &iDirection, &bData);
1277                    CheckCandidateInt(i - 1, j, 0, &iDirection, &bData);
1278                    CheckCandidateInt(i, j - 1, 0, &iDirection, &bData);
1279    
1280            } while (!(iDirection));
1281    
1282    // two bits are needed to code interpolate mode. we treat the bits just like they were vector's
1283            iMinSAD +=  2 * lambda_vec16[iQuant];
1284            if (iMinSAD < *best_sad) {
1285                    *best_sad = iMinSAD;
1286                    pMB->mvs[0] = currentMV[0];
1287                    pMB->b_mvs[0] = currentMV[1];
1288                    pMB->mode = MODE_INTERPOLATE;
1289    
1290                    pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;
1291                    pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;
1292                    pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;
1293                    pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;
1294            }
1295    }
1296    
1297    void
1298    MotionEstimationBVOP(MBParam * const pParam,
1299                                             FRAMEINFO * const frame,
1300                                             const int32_t time_bp,
1301                                             const int32_t time_pp,
1302                                             // forward (past) reference
1303                                             const MACROBLOCK * const f_mbs,
1304                                             const IMAGE * const f_ref,
1305                                             const IMAGE * const f_refH,
1306                                             const IMAGE * const f_refV,
1307                                             const IMAGE * const f_refHV,
1308                                             // backward (future) reference
1309                                             const MACROBLOCK * const b_mbs,
1310                                             const IMAGE * const b_ref,
1311                                             const IMAGE * const b_refH,
1312                                             const IMAGE * const b_refV,
1313                                             const IMAGE * const b_refHV)
1314    {
1315            uint32_t i, j;
1316            int32_t best_sad, skip_sad;
1317            int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;
1318            static const VECTOR zeroMV={0,0};
1319    
1320          int32_t iDiamondSize;          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
1321    
1322          int32_t min_dx;          const int32_t TRB = time_pp - time_bp;
1323          int32_t max_dx;          const int32_t TRD = time_pp;
         int32_t min_dy;  
         int32_t max_dy;  
1324    
1325          VECTOR pmv[4];          // note: i==horizontal, j==vertical
         int32_t psad[4];  
         VECTOR newMV;  
         VECTOR backupMV;  
1326    
1327          MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          for (j = 0; j < pParam->mb_height; j++) {
1328    
1329          static int32_t threshA,threshB;                  f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
         int32_t iFound,bPredEq;  
         int32_t iMinSAD,iSAD;  
1330    
1331          int32_t iSubBlock = ((y&1)<<1) + (x&1);                  for (i = 0; i < pParam->mb_width; i++) {
1332                            MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
1333                            const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
1334    
1335  /* Get maximum range */  /* special case, if collocated block is SKIPed: encoding is forward (0,0), cpb=0 without further ado */
1336      get_range(&min_dx, &max_dx, &min_dy, &max_dy,                          if (b_mb->mode == MODE_NOT_CODED) {
1337                          x, y, 8, iWidth, iHeight, iFcode);                                  pMB->mode = MODE_NOT_CODED;
1338                                    continue;
1339                            }
1340    
1341  /* we work with abs. MVs, not relative to prediction, so range is relative to 0,0 */  /* direct search comes first, because it (1) checks for SKIP-mode
1342            and (2) sets very good predictions for forward and backward search */
1343    
1344          if (!(MotionFlags & PMV_HALFPELDIAMOND8 ))                          skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
1345          { min_dx = EVEN(min_dx);                                                                          b_ref, b_refH->y, b_refV->y, b_refHV->y,
1346            max_dx = EVEN(max_dx);                                                                          &frame->image,
1347            min_dy = EVEN(min_dy);                                                                          i, j,
1348            max_dy = EVEN(max_dy);                                                                          frame->motion_flags,
1349          }               /* because we might use IF (dx>max_dx) THEN dx=max_dx; */                                                                          frame->quant,
1350                                                                            TRB, TRD,
1351                                                                            pParam,
1352                                                                            pMB, b_mb,
1353                                                                            &best_sad);
1354    
1355                            if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
1356    
1357    //                      best_sad = 256*4096; //uncomment to disable Directsearch.
1358    //      To disable any other mode, just comment the function call
1359    
1360                            // forward search
1361                            SearchBF(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
1362                                                    &frame->image, i, j,
1363                                                    frame->motion_flags,
1364                                                    frame->quant, frame->fcode, pParam,
1365                                                    pMB, &f_predMV, &best_sad,
1366                                                    MODE_FORWARD);
1367    
1368                            // backward search
1369                            SearchBF(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
1370                                                    &frame->image, i, j,
1371                                                    frame->motion_flags,
1372                                                    frame->quant, frame->bcode, pParam,
1373                                                    pMB, &b_predMV, &best_sad,
1374                                                    MODE_BACKWARD);
1375    
1376                            // interpolate search comes last, because it uses data from forward and backward as prediction
1377    
1378                            SearchInterpolate(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
1379                                                    b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
1380                                                    &frame->image,
1381                                                    i, j,
1382                                                    frame->fcode, frame->bcode,
1383                                                    frame->motion_flags,
1384                                                    frame->quant, pParam,
1385                                                    &f_predMV, &b_predMV,
1386                                                    pMB, &best_sad);
1387    
1388                            switch (pMB->mode) {
1389                                    case MODE_FORWARD:
1390                                            f_count++;
1391                                            f_predMV = pMB->mvs[0];
1392                                            break;
1393                                    case MODE_BACKWARD:
1394                                            b_count++;
1395                                            b_predMV = pMB->b_mvs[0];
1396                                            break;
1397                                    case MODE_INTERPOLATE:
1398                                            i_count++;
1399                                            f_predMV = pMB->mvs[0];
1400                                            b_predMV = pMB->b_mvs[0];
1401                                            break;
1402                                    case MODE_DIRECT:
1403                                    case MODE_DIRECT_NO4V:
1404                                            d_count++;
1405                                            break;
1406                                    default:
1407                                            break;
1408                            }
1409                    }
1410            }
1411    
1412    //      fprintf(debug,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d, N: %04d\n",
1413    //                              f_count,b_count,i_count,d_count,n_count);
1414    
1415          bPredEq  = get_pmvdata(pMBs, (x>>1), (y>>1), iWcount, iSubBlock, pmv, psad);  }
1416    
1417          if ((x==0) && (y==0) )  /* Hinted ME starts here */
         {  
                 threshA =  512/4;  
                 threshB = 1024/4;  
1418    
1419          }  static __inline void
1420          else  Search8hinted(  const SearchData * const OldData,
1421                                    const int x, const int y,
1422                                    const uint32_t MotionFlags,
1423                                    const MBParam * const pParam,
1424                                    MACROBLOCK * const pMB,
1425                                    const MACROBLOCK * const pMBs,
1426                                    const int block)
1427          {          {
1428                  threshA = psad[0]/4;                    /* good estimate */          SearchData Data;
1429                  threshB = threshA+256/4;          MainSearchFunc *MainSearchPtr;
                 if (threshA< 512/4) threshA =  512/4;  
                 if (threshA>1024/4) threshA = 1024/4;  
                 if (threshB>1792/4) threshB = 1792/4;  
         }  
1430    
1431          iFound=0;          Data.predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2 , y/2, block);
1432            Data.iMinSAD = OldData->iMinSAD + 1 + block;
1433            Data.currentMV = OldData->currentMV+1+block;
1434            Data.iFcode = OldData->iFcode;
1435            Data.iQuant = OldData->iQuant;
1436    
1437  /* Step 2: Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion          Data.Ref = OldData->Ref + 8 * ((block&1) + pParam->edged_width*(block>>1));
1438          vector of the median.          Data.RefH = OldData->RefH + 8 * ((block&1) + pParam->edged_width*(block>>1));
1439          If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2          Data.RefV = OldData->RefV + 8 * ((block&1) + pParam->edged_width*(block>>1));
1440  */          Data.RefHV = OldData->RefHV + 8 * ((block&1) + pParam->edged_width*(block>>1));
1441            Data.iEdgedWidth = pParam->edged_width;
1442            Data.Cur = OldData->Cur + 8 * ((block&1) + pParam->edged_width*(block>>1));
1443    
1444          if ((bPredEq) && (MVequal(pmv[0],pMB->mvs[iSubBlock]) ) )          CheckCandidate = CheckCandidate8;
                 iFound=2;  
1445    
1446  /* Step 3: If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          if (block != 0)
1447          Otherwise select large Diamond Search.                  *(Data.iMinSAD) += lambda_vec8[Data.iQuant] *
1448  */                                                                  d_mv_bits(      Data.currentMV->x - Data.predMV.x,
1449                                                                                            Data.currentMV->y - Data.predMV.y,
1450                                                                                            Data.iFcode);
1451    
         if ( (pmv[0].x != 0) || (pmv[0].y != 0) || (threshB<1536/4) || (bPredEq) )  
                 iDiamondSize=1; // 1 halfpel!  
         else  
                 iDiamondSize=2; // 2 halfpel = 1 full pixel!  
   
         if (!(MotionFlags & PMV_HALFPELDIAMOND8) )  
                 iDiamondSize*=2;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
         MinSAD=SAD  
         If Motion Vector equal to Previous frame motion vector  
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
 */  
1452    
1453            get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 8,
1454                                    pParam->width, pParam->height, OldData->iFcode);
1455    
1456  // Prepare for main loop          if (pMB->mode == MODE_INTER4V) {
1457                    int dummy;
1458                    CheckCandidate8(pMB->mvs[block].x, pMB->mvs[block].y, 0, &dummy, &Data); }
1459    
1460          currMV->x=start_x;              /* start with mv16 */          if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
1461          currMV->y=start_y;                  else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1462                            else MainSearchPtr = DiamondSearch;
1463    
1464          iMinSAD = sad8( cur,          (*MainSearchPtr)(Data.currentMV->x, Data.currentMV->y, &Data, 255);
1465                  get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV, iEdgedWidth),  
1466                  iEdgedWidth);          if (MotionFlags & PMV_HALFPELREFINE8) HalfpelRefine(&Data);
1467          iMinSAD += calc_delta_8(currMV->x - pmv[0].x, currMV->y - pmv[0].y, (uint8_t)iFcode) * iQuant;  
1468            pMB->pmvs[block].x = Data.currentMV->x - Data.predMV.x;
1469          if ( (iMinSAD < 256/4 ) || ( (MVequal(*currMV,pMB->mvs[iSubBlock])) && (iMinSAD < pMB->sad8[iSubBlock]) ) )          pMB->pmvs[block].y = Data.currentMV->y - Data.predMV.y;
1470                  {          pMB->mvs[block] = *(Data.currentMV);
1471                          if (MotionFlags & PMV_QUICKSTOP8)          pMB->sad8[block] =  4 * (*(Data.iMinSAD));
                                 goto step10_8b;  
                         if (MotionFlags & PMV_EARLYSTOP8)  
                                 goto step10_8;  
1472                  }                  }
1473    
 /*  
 Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  
         Also calculate (0,0) but do not subtract offset.  
         Let MinSAD be the smallest SAD up to this point.  
         If MV is (0,0) subtract offset. ******** WHAT'S THIS 'OFFSET' ??? ***********  
 */  
1474    
1475  // the prediction might be even better than mv16  static void
1476          CHECK_MV8_CANDIDATE(pmv[0].x,pmv[0].y);  SearchPhinted ( const uint8_t * const pRef,
1477                                    const uint8_t * const pRefH,
1478                                    const uint8_t * const pRefV,
1479                                    const uint8_t * const pRefHV,
1480                                    const IMAGE * const pCur,
1481                                    const int x,
1482                                    const int y,
1483                                    const uint32_t MotionFlags,
1484                                    const uint32_t iQuant,
1485                                    const uint32_t iFcode,
1486                                    const MBParam * const pParam,
1487                                    const MACROBLOCK * const pMBs,
1488                                    int inter4v,
1489                                    MACROBLOCK * const pMB)
1490    {
1491    
1492  // (0,0) is always possible          const int32_t iEdgedWidth = pParam->edged_width;
         CHECK_MV8_ZERO;  
1493    
1494  // previous frame MV is always possible          int i;
1495          CHECK_MV8_CANDIDATE(pMB->mvs[iSubBlock].x,pMB->mvs[iSubBlock].y);          VECTOR currentMV[5];
1496            int32_t iMinSAD[5];
1497            int32_t temp[5];
1498            MainSearchFunc * MainSearchPtr;
1499            SearchData Data;
1500    
1501            Data.predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1502            get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 16,
1503                                    pParam->width, pParam->height, iFcode);
1504    
1505            Data.Cur = pCur->y + (x + y * iEdgedWidth) * 16;
1506            Data.iEdgedWidth = iEdgedWidth;
1507            Data.currentMV = currentMV;
1508            Data.iMinSAD = iMinSAD;
1509            Data.Ref = pRef + (x + iEdgedWidth*y)*16;
1510            Data.RefH = pRefH + (x + iEdgedWidth*y) * 16;
1511            Data.RefV = pRefV + (x + iEdgedWidth*y) * 16;
1512            Data.RefHV = pRefHV + (x + iEdgedWidth*y) * 16;
1513            Data.temp = temp;
1514            Data.iQuant = iQuant;
1515            Data.iFcode = iFcode;
1516    
1517            if (!(MotionFlags & PMV_HALFPEL16)) {
1518                    Data.min_dx = EVEN(Data.min_dx);
1519                    Data.max_dx = EVEN(Data.max_dx);
1520                    Data.min_dy = EVEN(Data.min_dy);
1521                    Data.max_dy = EVEN(Data.max_dy);
1522            }
1523    
1524            for(i = 0; i < 5; i++) iMinSAD[i] = MV_MAX_ERROR;
1525    
1526            if (pMB->dquant != NO_CHANGE) inter4v = 0;
1527    
1528            if (inter4v)
1529                    CheckCandidate = CheckCandidate16;
1530            else CheckCandidate = CheckCandidate16no4v;
1531    
1532    
1533            pMB->mvs[0].x = EVEN(pMB->mvs[0].x);
1534            pMB->mvs[0].y = EVEN(pMB->mvs[0].y);
1535            if (pMB->mvs[0].x > Data.max_dx) pMB->mvs[0].x = Data.max_dx; // this is in case iFcode changed
1536            if (pMB->mvs[0].x < Data.min_dx) pMB->mvs[0].x = Data.min_dx;
1537            if (pMB->mvs[0].y > Data.max_dy) pMB->mvs[0].y = Data.max_dy;
1538            if (pMB->mvs[0].y < Data.min_dy) pMB->mvs[0].y = Data.min_dy;
1539    
1540            CheckCandidate16(pMB->mvs[0].x, pMB->mvs[0].y, 0, &i, &Data);
1541    
1542            if (pMB->mode == MODE_INTER4V)
1543                    for (i = 1; i < 4; i++) { // all four vectors will be used as four predictions for 16x16 search
1544                            pMB->mvs[i].x = EVEN(pMB->mvs[i].x);
1545                            pMB->mvs[i].y = EVEN(pMB->mvs[i].y);
1546                            if (!(make_mask(pMB->mvs, i)))
1547                                    CheckCandidate16(pMB->mvs[i].x, pMB->mvs[i].y, 0, &i, &Data);
1548                    }
1549    
1550            if (MotionFlags & PMV_USESQUARES16)
1551                    MainSearchPtr = SquareSearch;
1552            else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
1553                    MainSearchPtr = AdvDiamondSearch;
1554                    else MainSearchPtr = DiamondSearch;
1555    
1556            (*MainSearchPtr)(currentMV->x, currentMV->y, &Data, 255);
1557    
1558            if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(&Data);
1559    
1560            if (inter4v)
1561                    for(i = 0; i < 4; i++)
1562                            Search8hinted(&Data, 2*x+(i&1), 2*y+(i>>1), MotionFlags, pParam, pMB, pMBs, i);
1563    
1564            if (!(inter4v) ||
1565                    (iMinSAD[0] < iMinSAD[1] + iMinSAD[2] + iMinSAD[3] + iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {
1566    // INTER MODE
1567    
1568  // left neighbour, if allowed                  pMB->mode = MODE_INTER;
1569          if (psad[1] != MV_MAX_ERROR)                  pMB->mvs[0] = pMB->mvs[1]
1570          {                          = pMB->mvs[2] = pMB->mvs[3] = currentMV[0];
1571                  if (!(MotionFlags & PMV_HALFPEL8 ))  
1572                  {       pmv[1].x = EVEN(pmv[1].x);                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
1573                          pmv[1].y = EVEN(pmv[1].y);                          pMB->sad8[2] = pMB->sad8[3] =  iMinSAD[0];
1574                  }  
1575                  CHECK_MV8_CANDIDATE(pmv[1].x,pmv[1].y);                  pMB->pmvs[0].x = currentMV[0].x - Data.predMV.x;
1576                    pMB->pmvs[0].y = currentMV[0].y - Data.predMV.y;
1577            } else {
1578    // INTER4V MODE; all other things are already set in Search8hinted
1579                    pMB->mode = MODE_INTER4V;
1580                    pMB->sad16 = iMinSAD[1] + iMinSAD[2] + iMinSAD[3] + iMinSAD[4] + IMV16X16 * iQuant;
1581          }          }
1582    
 // top neighbour, if allowed  
         if (psad[2] != MV_MAX_ERROR)  
         {  
                 if (!(MotionFlags & PMV_HALFPEL8 ))  
                 {       pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
1583                  }                  }
                 CHECK_MV8_CANDIDATE(pmv[2].x,pmv[2].y);  
1584    
1585  // top right neighbour, if allowed  void
1586                  if (psad[3] != MV_MAX_ERROR)  MotionEstimationHinted( MBParam * const pParam,
1587                                                    FRAMEINFO * const current,
1588                                                    FRAMEINFO * const reference,
1589                                                    const IMAGE * const pRefH,
1590                                                    const IMAGE * const pRefV,
1591                                                    const IMAGE * const pRefHV)
1592                  {                  {
1593                  if (!(MotionFlags & PMV_HALFPEL8 ))          MACROBLOCK *const pMBs = current->mbs;
1594                  {       pmv[3].x = EVEN(pmv[3].x);          const IMAGE *const pCurrent = &current->image;
1595                          pmv[3].y = EVEN(pmv[3].y);          const IMAGE *const pRef = &reference->image;
                 }  
                         CHECK_MV8_CANDIDATE(pmv[3].x,pmv[3].y);  
                 }  
         }  
1596    
1597  /* Step 6: If MinSAD <= thresa goto Step 10.          uint32_t x, y;
    If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
 */  
1598    
1599          if ( (iMinSAD <= threshA) || ( MVequal(*currMV,pMB->mvs[iSubBlock]) && (iMinSAD < pMB->sad8[iSubBlock]) ) )          if (sadInit) (*sadInit) ();
                 {  
                         if (MotionFlags & PMV_QUICKSTOP8)  
                                 goto step10_8b;  
                         if (MotionFlags & PMV_EARLYSTOP8)  
                                 goto step10_8;  
                 }  
1600    
1601  /************ (Diamond Search)  **************/          for (y = 0; y < pParam->mb_height; y++) {
1602  /*                  for (x = 0; x < pParam->mb_width; x++)  {
 Step 7: Perform Diamond search, with either the small or large diamond.  
         If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
 Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
         If center then goto step 10.  
 Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
         Refine by using small diamond and goto step 10.  
 */  
1603    
1604          backupMV = *currMV; /* save best prediction, actually only for EXTSEARCH */                          MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1605    
1606  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  //intra mode is copied from the first pass. At least for the time being
1607          iSAD = PMVfastSearch8_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,                          if  ((pMB->mode == MODE_INTRA) || (pMB->mode == MODE_NOT_CODED) ) continue;
                 x, y,  
                 currMV->x, currMV->y, iMinSAD, &newMV,  
                 pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);  
1608    
1609          if (iSAD < iMinSAD)                          if (!(current->global_flags & XVID_LUMIMASKING)) {
1610          {                                  pMB->dquant = NO_CHANGE;
1611                  *currMV = newMV;                                  pMB->quant = current->quant; }
1612                  iMinSAD = iSAD;  
1613                            SearchPhinted(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1614                                                            y, current->motion_flags, pMB->quant,
1615                                                            current->fcode, pParam, pMBs,
1616                                                            current->global_flags & XVID_INTER4V, pMB);
1617    
1618                    }
1619            }
1620          }          }
1621    
1622          if (MotionFlags & PMV_EXTSEARCH8)  static __inline int
1623    MEanalyzeMB (   const uint8_t * const pRef,
1624                                    const uint8_t * const pCur,
1625                                    const int x,
1626                                    const int y,
1627                                    const uint32_t iFcode,
1628                                    const MBParam * const pParam,
1629                                    const MACROBLOCK * const pMBs,
1630                                    MACROBLOCK * const pMB)
1631          {          {
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
1632    
1633                  if (!(MVequal(pmv[0],backupMV)) )          const int32_t iEdgedWidth = pParam->edged_width;
1634                  {       iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,          int i, mask;
1635                                  x, y,          VECTOR currentMV, pmv[3];
1636                          pmv[0].x, pmv[0].y, iMinSAD, &newMV,          int32_t iMinSAD = MV_MAX_ERROR;
1637                          pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);          SearchData Data;
1638    
1639            Data.predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1640            get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 16,
1641                                    pParam->width, pParam->height, iFcode);
1642    
1643            Data.Cur = pCur + (x + y * iEdgedWidth) * 16;
1644            Data.iEdgedWidth = iEdgedWidth;
1645            Data.currentMV = &currentMV;
1646            Data.iMinSAD = &iMinSAD;
1647            Data.Ref = pRef + (x + iEdgedWidth*y)*16;
1648            Data.iQuant = 2;
1649            Data.iFcode = iFcode;
1650    
1651            CheckCandidate = CheckCandidate16no4vI;
1652    
1653            pmv[1].x = EVEN(pMB->mvs[0].x);
1654            pmv[1].y = EVEN(pMB->mvs[0].y);
1655            pmv[0].x = EVEN(Data.predMV.x);
1656            pmv[0].y = EVEN(Data.predMV.y);
1657            pmv[2].x = pmv[2].y = 0;
1658    
1659            CheckCandidate16no4vI(pmv[0].x, pmv[0].y, 255, &i, &Data);
1660            if (!(mask = make_mask(pmv, 1)))
1661                    CheckCandidate16no4vI(pmv[1].x, pmv[1].y, mask, &i, &Data);
1662            if (!(mask = make_mask(pmv, 2)))
1663                    CheckCandidate16no4vI(0, 0, mask, &i, &Data);
1664    
1665                          if (iSAD < iMinSAD)          DiamondSearch(currentMV.x, currentMV.y, &Data, i);
1666                          {  
1667                                  *currMV = newMV;          pMB->mvs[0] = pMB->mvs[1]
1668                                  iMinSAD = iSAD;                          = pMB->mvs[2] = pMB->mvs[3] = currentMV; // all, for future get_pmv()
1669                          }  
1670            return iMinSAD;
1671                  }                  }
1672    
1673                  if ( (!(MVzero(pmv[0]))) && (!(MVzero(backupMV))) )  #define INTRA_THRESH    1350
1674                  {       iSAD = PMVfastSearch16_MainSearch(pRef, pRefH, pRefV, pRefHV, cur,  #define INTER_THRESH    900
                                 x, y,  
                         0, 0, iMinSAD, &newMV,  
                         pmv, min_dx, max_dx, min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode, iQuant, iFound);  
1675    
1676                          if (iSAD < iMinSAD)  int
1677    MEanalysis(     const IMAGE * const pRef,
1678                            const IMAGE * const pCurrent,
1679                            MBParam * const pParam,
1680                            MACROBLOCK * const pMBs,
1681                            const uint32_t iFcode)
1682                          {                          {
1683                                  *currMV = newMV;          uint32_t x, y, intra = 0;
1684                                  iMinSAD = iSAD;          int sSAD = 0;
                         }  
                 }  
         }  
1685    
1686  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.          if (sadInit) (*sadInit) ();
          By performing an optional local half-pixel search, we can refine this result even further.  
 */  
1687    
1688  step10_8:          for (y = 0; y < pParam->mb_height-1; y++) {
1689          if (MotionFlags & PMV_HALFPELREFINE8)           // perform final half-pel step                  for (x = 0; x < pParam->mb_width; x++) {
1690                  iMinSAD = PMVfastSearch8_Refine( pRef, pRefH, pRefV, pRefHV, cur,                          int sad, dev;
                                 x, y,  
                                 currMV, iMinSAD,  
                                 pmv, min_dx, max_dx, min_dy, max_dy, iFcode, iQuant, iEdgedWidth);  
1691    
1692  step10_8b:                          MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1693    
1694          currPMV->x = currMV->x - pmv[0].x;                          sad = MEanalyzeMB(pRef->y, pCurrent->y, x, y,
1695          currPMV->y = currMV->y - pmv[0].y;                                                                  iFcode, pParam, pMBs, pMB);
1696    
1697                            if ( x != 0 && y != 0 && x != pParam->mb_width-1 ) { //no edge macroblocks, they just don't work
1698                                    if (sad > INTRA_THRESH) {
1699                                            dev = dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,
1700                                                                      pParam->edged_width);
1701                                            if (dev + INTRA_THRESH < sad) intra++;
1702                                            if (intra > (pParam->mb_height-2)*(pParam->mb_width-2)/2) return 2;  // I frame
1703                                    }
1704                                    sSAD += sad;
1705                            }
1706    
1707                    }
1708            }
1709            sSAD /= (pParam->mb_height-2)*(pParam->mb_width-2);
1710            if (sSAD > INTER_THRESH ) return 1; //P frame
1711            emms();
1712            return 0; // B frame
1713    
         return iMinSAD;  
1714  }  }

Legend:
Removed from v.3  
changed lines
  Added in v.539

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