[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 252, Sun Jun 30 10:46:29 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   *      01.05.2002      updated MotionEstimationBVOP   *      This program is an implementation of a part of one or more MPEG-4
7   *      25.04.2002 partial prevMB conversion   *      Video tools as specified in ISO/IEC 14496-2 standard.  Those intending
8   *  22.04.2002 remove some compile warning by chenm001 <chenm001@163.com>   *      to use this software module in hardware or software products are
9   *  14.04.2002 added MotionEstimationBVOP()   *      advised that its use may infringe existing patents or copyrights, and
10   *  02.04.2002 add EPZS(^2) as ME algorithm, use PMV_USESQUARES to choose between   *      any such use would be at such party's own risk.  The original
11   *             EPZS and EPZS^2   *      developer of this software module and his/her company, and subsequent
12   *  08.02.2002 split up PMVfast into three routines: PMVFast, PMVFast_MainLoop   *      editors and their companies, will have no liability for use of this
13   *             PMVFast_Refine to support multiple searches with different start points   *      software or modifications or derivatives thereof.
  *  07.01.2002 uv-block-based interpolation  
  *  06.01.2002 INTER/INTRA-decision is now done before any SEARCH8 (speedup)  
  *             changed INTER_BIAS to 150 (as suggested by suxen_drol)  
  *             removed halfpel refinement step in PMVfastSearch8 + quality=5  
  *             added new quality mode = 6 which performs halfpel refinement  
  *             filesize difference between quality 5 and 6 is smaller than 1%  
  *             (Isibaar)  
  *  31.12.2001 PMVfastSearch16 and PMVfastSearch8 (gruel)  
  *  30.12.2001 get_range/MotionSearchX simplified; blue/green bug fix  
  *  22.12.2001 commented best_point==99 check  
  *  19.12.2001 modified get_range (purple bug fix)  
  *  15.12.2001 moved pmv displacement from mbprediction  
  *  02.12.2001 motion estimation/compensation split (Isibaar)  
  *  16.11.2001 rewrote/tweaked search algorithms; pross@cs.rmit.edu.au  
  *  10.11.2001 support for sad16/sad8 functions  
  *  28.08.2001 reactivated MODE_INTER4V for EXT_MODE  
  *  24.08.2001 removed MODE_INTER4V_Q, disabled MODE_INTER4V for EXT_MODE  
  *  22.08.2001 added MODE_INTER4V_Q  
  *  20.08.2001 added pragma to get rid of internal compiler error with VC6  
  *             idea by Cyril. Thanks.  
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>
# Line 44  Line 37 
37  #include "../prediction/mbprediction.h"  #include "../prediction/mbprediction.h"
38  #include "../global.h"  #include "../global.h"
39  #include "../utils/timer.h"  #include "../utils/timer.h"
40    #include "motion_est.h"
41  #include "motion.h"  #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  // stop search if sdelta < THRESHOLD  #define MAX_CHROMA_SAD_FOR_SKIP (22)
49  #define MV16_THRESHOLD  192  #define SKIP_THRESH_B (25)
 #define MV8_THRESHOLD   56  
   
 #define NEIGH_MOVE_THRESH 0  
 // how much a block's MV must differ from his neighbour  
 // to be search for INTER4V. The more, the faster...  
   
 /* sad16(0,0) bias; mpeg4 spec suggests nb/2+1 */  
 /* nb  = vop pixels * 2^(bpp-8) */  
 #define MV16_00_BIAS    (128+1)  
 #define MV8_00_BIAS     (0)  
   
 /* INTER bias for INTER/INTRA decision; mpeg4 spec suggests 2*nb */  
 #define MV16_INTER_BIAS 512  
   
 /* Parameters which control inter/inter4v decision */  
 #define IMV16X16                        5  
50    
51  /* vector map (vlc delta size) smoother parameters */  #define CHECK_CANDIDATE(X,Y,D) { \
52  #define NEIGH_TEND_16X16        2  (*CheckCandidate)((const int)(X),(const int)(Y), (D), &iDirection, data ); }
 #define NEIGH_TEND_8X8          2  
53    
54  // fast ((A)/2)*2  #define iDiamondSize 2
 #define EVEN(A)         (((A)<0?(A)+1:(A)) & ~1)  
55    
56  #define MVzero(A) ( ((A).x)==(0) && ((A).y)==(0) )  static __inline int
57  #define MVequal(A,B) ( ((A).x)==((B).x) && ((A).y)==((B).y) )  d_mv_bits(int x, int y, const uint32_t iFcode)
58    {
59            int xb, yb;
60    
61  int32_t PMVfastSearch16(const uint8_t * const pRef,          if (x == 0) xb = 1;
62                                                  const uint8_t * const pRefH,          else {
63                                                  const uint8_t * const pRefV,                  if (x < 0) x = -x;
64                                                  const uint8_t * const pRefHV,                  x += (1 << (iFcode - 1)) - 1;
65                                                  const IMAGE * const pCur,                  x >>= (iFcode - 1);
66                                                  const int x,                  if (x > 32) x = 32;
67                                                  const int y,                  xb = mvtab[x] + iFcode;
68                                                  const uint32_t MotionFlags,          }
                                                 const uint32_t iQuant,  
                                                 const uint32_t iFcode,  
                                                 const MBParam * const pParam,  
                                                 const MACROBLOCK * const pMBs,  
                                                 const MACROBLOCK * const prevMBs,  
                                                 VECTOR * const currMV,  
                                                 VECTOR * const currPMV);  
69    
70  int32_t EPZSSearch16(const uint8_t * const pRef,          if (y == 0) yb = 1;
71                                           const uint8_t * const pRefH,          else {
72                                           const uint8_t * const pRefV,                  if (y < 0) y = -y;
73                                           const uint8_t * const pRefHV,                  y += (1 << (iFcode - 1)) - 1;
74                                           const IMAGE * const pCur,                  y >>= (iFcode - 1);
75                                           const int x,                  if (y > 32) y = 32;
76                                           const int y,                  yb = mvtab[y] + iFcode;
77                                           const uint32_t MotionFlags,          }
78                                           const uint32_t iQuant,          return xb + yb;
79                                           const uint32_t iFcode,  }
                                          const MBParam * const pParam,  
                                          const MACROBLOCK * const pMBs,  
                                          const MACROBLOCK * const prevMBs,  
                                          VECTOR * const currMV,  
                                          VECTOR * const currPMV);  
80    
81    
82  int32_t PMVfastSearch8(const uint8_t * const pRef,  /* CHECK_CANDIATE FUNCTIONS START */
                                            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,  
                                            const int start_y,  
                                            const uint32_t MotionFlags,  
                                            const uint32_t iQuant,  
                                            const uint32_t iFcode,  
                                            const MBParam * const pParam,  
                                            const MACROBLOCK * const pMBs,  
                                            const MACROBLOCK * const prevMBs,  
                                            VECTOR * const currMV,  
                                            VECTOR * const currPMV);  
83    
84  int32_t EPZSSearch8(const uint8_t * const pRef,  static void
85                                          const uint8_t * const pRefH,  CheckCandidate16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
86                                          const uint8_t * const pRefV,  {
87                                          const uint8_t * const pRefHV,          int32_t * const sad = data->temp;
88                                          const IMAGE * const pCur,          int t;
89                                          const int x,          const uint8_t * Reference;
                                         const int y,  
                                         const int start_x,  
                                         const int start_y,  
                                         const uint32_t MotionFlags,  
                                         const uint32_t iQuant,  
                                         const uint32_t iFcode,  
                                         const MBParam * const pParam,  
                                         const MACROBLOCK * const pMBs,  
                                         const MACROBLOCK * const prevMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV);  
90    
91            if (( x > data->max_dx) || ( x < data->min_dx)
92                    || ( y > data->max_dy) || (y < data->min_dy)) return;
93    
94  typedef int32_t(MainSearch16Func) (const uint8_t * const pRef,          switch ( ((x&1)<<1) + (y&1) ) {
95                                                                     const uint8_t * const pRefH,                  case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
96                                                                     const uint8_t * const pRefV,                  case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;
97                                                                     const uint8_t * const pRefHV,                  case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;
98                                                                     const uint8_t * const cur,                  default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
99                                                                     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);  
100    
101  typedef MainSearch16Func *MainSearch16FuncPtr;          data->temp[0] = sad16v(data->Cur, Reference, data->iEdgedWidth, sad+1);
102    
103            t = d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
104            data->temp[0] += lambda_vec16[data->iQuant] * t;
105            data->temp[1] += lambda_vec8[data->iQuant] * t;
106    
107  typedef int32_t(MainSearch8Func) (const uint8_t * const pRef,          if (data->temp[0] < data->iMinSAD[0]) {
108                                                                    const uint8_t * const pRefH,                  data->iMinSAD[0] = data->temp[0];
109                                                                    const uint8_t * const pRefV,                  data->currentMV[0].x = x; data->currentMV[0].y = y;
110                                                                    const uint8_t * const pRefHV,                  *dir = Direction; }
                                                                   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);  
   
 typedef MainSearch8Func *MainSearch8FuncPtr;  
   
 static int32_t lambda_vec16[32] =       /* rounded values for lambda param for weight of motion bits as in modified H.26L */  
 { 0, (int) (1.00235 + 0.5), (int) (1.15582 + 0.5), (int) (1.31976 + 0.5),  
                 (int) (1.49591 + 0.5), (int) (1.68601 + 0.5),  
         (int) (1.89187 + 0.5), (int) (2.11542 + 0.5), (int) (2.35878 + 0.5),  
                 (int) (2.62429 + 0.5), (int) (2.91455 + 0.5),  
         (int) (3.23253 + 0.5), (int) (3.58158 + 0.5), (int) (3.96555 + 0.5),  
                 (int) (4.38887 + 0.5), (int) (4.85673 + 0.5),  
         (int) (5.37519 + 0.5), (int) (5.95144 + 0.5), (int) (6.59408 + 0.5),  
                 (int) (7.31349 + 0.5), (int) (8.12242 + 0.5),  
         (int) (9.03669 + 0.5), (int) (10.0763 + 0.5), (int) (11.2669 + 0.5),  
                 (int) (12.6426 + 0.5), (int) (14.2493 + 0.5),  
         (int) (16.1512 + 0.5), (int) (18.442 + 0.5), (int) (21.2656 + 0.5),  
                 (int) (24.8580 + 0.5), (int) (29.6436 + 0.5),  
         (int) (36.4949 + 0.5)  
 };  
   
 static int32_t *lambda_vec8 = lambda_vec16;     /* same table for INTER and INTER4V for now */  
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    }
122    
123  // mv.length table  static void
124  static const uint32_t mvtab[33] = {  CheckCandidate16no4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
125          1, 2, 3, 4, 6, 7, 7, 7,  {
126          9, 9, 9, 10, 10, 10, 10, 10,          int32_t sad;
127          10, 10, 10, 10, 10, 10, 10, 10,          const uint8_t * Reference;
         10, 11, 11, 11, 11, 11, 11, 12, 12  
 };  
128    
129            if (( x > data->max_dx) || ( x < data->min_dx)
130                    || ( y > data->max_dy) || (y < data->min_dy)) return;
131    
132  static __inline uint32_t          switch ( ((x&1)<<1) + (y&1) )
 mv_bits(int32_t component,  
                 const uint32_t iFcode)  
133  {  {
134          if (component == 0)                  case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
135                  return 1;                  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          if (component < 0)                  default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
138                  component = -component;          }
139    
140          if (iFcode == 1) {          sad = lambda_vec16[data->iQuant] *
141                  if (component > 32)                          d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
142                          component = 32;          sad += sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
143    
144                  return mvtab[component] + 1;          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          component += (1 << (iFcode - 1)) - 1;  static void
151          component >>= (iFcode - 1);  CheckCandidate16no4vI(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
152    {
153            int32_t sad;
154    
155          if (component > 32)          if (( x > data->max_dx) || ( x < data->min_dx)
156                  component = 32;                  || ( y > data->max_dy) || (y < data->min_dy)) return;
157    
158          return mvtab[component] + 1 + iFcode - 1;          sad = lambda_vec16[data->iQuant] *
159  }                          d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
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          if (sad < *(data->iMinSAD)) {
165  calc_delta_16(const int32_t dx,                  *(data->iMinSAD) = sad;
166                            const int32_t dy,                  data->currentMV[0].x = x; data->currentMV[0].y = y;
167                            const uint32_t iFcode,                  *dir = Direction; }
                           const uint32_t iQuant)  
 {  
         return NEIGH_TEND_16X16 * lambda_vec16[iQuant] * (mv_bits(dx, iFcode) +  
                                                                                                           mv_bits(dy, iFcode));  
168  }  }
169    
170  static __inline uint32_t  
171  calc_delta_8(const int32_t dx,  static void
172                           const int32_t dy,  CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)
                          const uint32_t iFcode,  
                          const uint32_t iQuant)  
173  {  {
174          return NEIGH_TEND_8X8 * lambda_vec8[iQuant] * (mv_bits(dx, iFcode) +          int32_t sad;
175                                                                                                     mv_bits(dy, iFcode));          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            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            switch ( ((xb&1)<<1) + (yb&1) ) {
190                    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            sad = lambda_vec16[data->iQuant] *
197                            ( 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  #ifndef SEARCH16          sad += sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
 #define SEARCH16        PMVfastSearch16  
 //#define SEARCH16  FullSearch16  
 //#define SEARCH16  EPZSSearch16  
 #endif  
201    
202  #ifndef SEARCH8          if (sad < *(data->iMinSAD)) {
203  #define SEARCH8         PMVfastSearch8                  *(data->iMinSAD) = sad;
204  //#define SEARCH8   EPZSSearch8                  data->currentMV->x = xf; data->currentMV->y = yf;
205  #endif                  *dir = Direction; }
206    }
207    
208  bool  static void
209  MotionEstimation(MBParam * const pParam,  CheckCandidateDirect(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                                  FRAMEINFO * const current,  
                                  FRAMEINFO * const reference,  
                                  const IMAGE * const pRefH,  
                                  const IMAGE * const pRefV,  
                                  const IMAGE * const pRefHV,  
                                  const uint32_t iLimit)  
210  {  {
211          const uint32_t iWcount = pParam->mb_width;          int32_t sad;
212          const uint32_t iHcount = pParam->mb_height;          int k;
213          MACROBLOCK *const pMBs = current->mbs;          const uint8_t *ReferenceF;
214          MACROBLOCK *const prevMBs = reference->mbs;          const uint8_t *ReferenceB;
215          const IMAGE *const pCurrent = &current->image;          VECTOR mvs, b_mvs;
         const IMAGE *const pRef = &reference->image;  
216    
217          const VECTOR zeroMV = { 0, 0 };          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
218    
219          int32_t x, y;          sad = lambda_vec16[data->iQuant] * d_mv_bits(x, y, 1);
         int32_t iIntra = 0;  
         VECTOR pmv;  
   
         if (sadInit)  
                 (*sadInit) ();  
   
         for (y = 0; y < iHcount; y++)  
                 for (x = 0; x < iWcount; x++) {  
                         MACROBLOCK *const pMB = &pMBs[x + y * iWcount];  
   
                         pMB->sad16 =  
                                 SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,  
                                                  y, current->motion_flags, current->quant,  
                                                  current->fcode, pParam, pMBs, prevMBs, &pMB->mv16,  
                                                  &pMB->pmvs[0]);  
220    
221                          if (0 < (pMB->sad16 - MV16_INTER_BIAS)) {          for (k = 0; k < 4; k++) {
222                                  int32_t deviation;                  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                                  deviation =                  mvs.y = data->directmvF[k].y + y;
228                                          dev16(pCurrent->y + x * 16 + y * 16 * pParam->edged_width,                  b_mvs.y = ((y == 0) ?
229                                                    pParam->edged_width);                          data->directmvB[k].y
230                            : mvs.y - data->referencemv[k].y);
231    
232                                  if (deviation < (pMB->sad16 - MV16_INTER_BIAS)) {                  if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
233                                          pMB->mode = MODE_INTRA;                          || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
234                                          pMB->mv16 = pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =                          || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
235                                                  pMB->mvs[3] = zeroMV;                          || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
                                         pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =  
                                                 pMB->sad8[3] = 0;  
236    
237                                          iIntra++;                  switch ( ((mvs.x&1)<<1) + (mvs.y&1) ) {
238                                          if (iIntra >= iLimit)                          case 0 : ReferenceF = data->Ref + mvs.x/2 + (mvs.y/2)*(data->iEdgedWidth); break;
239                                                  return 1;                          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                                          continue;                          default : ReferenceF = data->RefHV + (mvs.x-1)/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
                                 }  
                         }  
   
                         pmv = pMB->pmvs[0];  
                         if (current->global_flags & XVID_INTER4V)  
                                 if ((!(current->global_flags & XVID_LUMIMASKING) ||  
                                          pMB->dquant == NO_CHANGE)) {  
                                         int32_t sad8 = IMV16X16 * current->quant;  
   
                                         if (sad8 < pMB->sad16)  
   
                                                 sad8 += pMB->sad8[0] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x, 2 * y, pMB->mv16.x,  
                                                                         pMB->mv16.y, current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[0],  
                                                                         &pMB->pmvs[0]);  
   
                                         if (sad8 < pMB->sad16)  
                                                 sad8 += pMB->sad8[1] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x + 1, 2 * y, pMB->mv16.x,  
                                                                         pMB->mv16.y, current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[1],  
                                                                         &pMB->pmvs[1]);  
   
                                         if (sad8 < pMB->sad16)  
                                                 sad8 += pMB->sad8[2] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x, 2 * y + 1, pMB->mv16.x,  
                                                                         pMB->mv16.y, current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[2],  
                                                                         &pMB->pmvs[2]);  
   
                                         if (sad8 < pMB->sad16)  
                                                 sad8 += pMB->sad8[3] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x + 1, 2 * y + 1,  
                                                                         pMB->mv16.x, pMB->mv16.y,  
                                                                         current->motion_flags, current->quant,  
                                                                         current->fcode, pParam, pMBs, prevMBs,  
                                                                         &pMB->mvs[3], &pMB->pmvs[3]);  
   
                                         /* decide: MODE_INTER or MODE_INTER4V  
                                            mpeg4:   if (sad8 < pMB->sad16 - nb/2+1) use_inter4v  
                                          */  
   
                                         if (sad8 < pMB->sad16) {  
                                                 pMB->mode = MODE_INTER4V;  
                                                 pMB->sad8[0] *= 4;  
                                                 pMB->sad8[1] *= 4;  
                                                 pMB->sad8[2] *= 4;  
                                                 pMB->sad8[3] *= 4;  
                                                 continue;  
242                                          }                                          }
243    
244                    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                          pMB->mode = MODE_INTER;                  sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
252                          pMB->pmvs[0] = pmv;     /* pMB->pmvs[1] = pMB->pmvs[2] = pMB->pmvs[3]  are not needed for INTER */                                                  ReferenceF + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
253                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mv16;                                                  ReferenceB + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
254                          pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] =                                                  data->iEdgedWidth);
255                                  pMB->sad16;                  if (sad > *(data->iMinSAD)) return;
   
                 }  
         return 0;  
256  }  }
257    
258  #define CHECK_MV16_ZERO {\          if (sad < *(data->iMinSAD)) {
259    if ( (0 <= max_dx) && (0 >= min_dx) \                  *(data->iMinSAD) = sad;
260      && (0 <= max_dy) && (0 >= min_dy) ) \                  data->currentMV->x = x; data->currentMV->y = y;
261    { \                  *dir = Direction; }
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \  
     iSAD += calc_delta_16(-pmv[0].x, -pmv[0].y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=0; currMV->y=0; }  }     \  
 }  
   
 #define NOCHECK_MV16_CANDIDATE(X,Y) { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - 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(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 NOCHECK_MV8_CANDIDATE(X,Y) \  
   { \  
     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(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; } } \  
262  }  }
263    
264  /* too slow and not fully functional at the moment */  static void
265  /*  CheckCandidateDirectno4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
 int32_t ZeroSearch16(  
                                         const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const IMAGE * const pCur,  
                                         const int x, const int y,  
                                         const uint32_t MotionFlags,  
                                         const uint32_t iQuant,  
                                         const uint32_t iFcode,  
                                         MBParam * const pParam,  
                                         const MACROBLOCK * const pMBs,  
                                         const MACROBLOCK * const prevMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
266  {  {
267          const int32_t iEdgedWidth = pParam->edged_width;          int32_t sad;
268          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;          const uint8_t *ReferenceF;
269          int32_t iSAD;          const uint8_t *ReferenceB;
270          int32_t pred_x,pred_y;          VECTOR mvs, b_mvs;
   
         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;  
271    
272          return iSAD;          if (( x > 31) || ( x < -31) || ( y > 31) || (y < -31)) return;
273    
274  }                  sad = lambda_vec16[data->iQuant] * d_mv_bits(x, y, 1);
 */  
275    
276  int32_t          mvs.x = data->directmvF[0].x + x;
277  Diamond16_MainSearch(const uint8_t * const pRef,          b_mvs.x = ((x == 0) ?
278                                           const uint8_t * const pRefH,                  data->directmvB[0].x
279                                           const uint8_t * const pRefV,                  : mvs.x - data->referencemv[0].x);
                                          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 {  
                 currMV->x = startx;  
                 currMV->y = starty;  
         }  
         return iMinSAD;  
 }  
   
 int32_t  
 Square16_MainSearch(const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x,  
                                         const int y,  
                                         int32_t 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 square 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 square pattern, and new parts for all following diamonds */  
   
 /*   new direction are extra, so 1-4 is normal diamond  
       537  
       1*2  
       648  
 */  
280    
281          CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);          mvs.y = data->directmvF[0].y + y;
282          CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);          b_mvs.y = ((y == 0) ?
283          CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);                  data->directmvB[0].y
284          CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);                  : mvs.y - data->referencemv[0].y);
   
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 5);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 6);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 7);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 8);  
   
   
         if (iDirection)  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;  
285    
286                          switch (iDirection) {          if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
287                          case 1:                  || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
288                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
289                                                                                     backupMV.y, 1);                  || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
                         case 2:  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
290    
291                          case 3:          switch ( ((mvs.x&1)<<1) + (mvs.y&1) ) {
292                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize,                  case 0 : ReferenceF = data->Ref + mvs.x/2 + (mvs.y/2)*(data->iEdgedWidth); break;
293                                                                                   4);                  case 1 : ReferenceF = data->RefV + mvs.x/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
294                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,                  case 2 : ReferenceF = data->RefH + (mvs.x-1)/2 + (mvs.y/2)*(data->iEdgedWidth); break;
295                                                                                   backupMV.y - iDiamondSize, 7);                  default : ReferenceF = data->RefHV + (mvs.x-1)/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;
296                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,          }
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
297    
298                          case 4:          switch ( ((b_mvs.x&1)<<1) + (b_mvs.y&1) ) {
299                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize,                  case 0 : ReferenceB = data->bRef + b_mvs.x/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
300                                                                                   3);                  case 1 : ReferenceB = data->bRefV + b_mvs.x/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
301                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,                  case 2 : ReferenceB = data->bRefH + (b_mvs.x-1)/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;
302                                                                                   backupMV.y - iDiamondSize, 5);                  default : ReferenceB = data->bRefHV + (b_mvs.x-1)/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;
303                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,          }
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 break;  
304    
305                          case 5:          sad += sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
306    
307                          case 6:          if (sad < *(data->iMinSAD)) {
308                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y,                  *(data->iMinSAD) = sad;
309                                                                                   2);                  data->currentMV->x = x; data->currentMV->y = y;
310                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize,                  *dir = Direction; }
311                                                                                   3);  }
   
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
312    
313                                  break;  static void
314    CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
315    {
316            int32_t sad;
317            const uint8_t * Reference;
318    
319                          case 7:          if (( x > data->max_dx) || ( x < data->min_dx)
320                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  || ( y > data->max_dy) || (y < data->min_dy)) return;
                                                                                    backupMV.y, 1);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
321    
322                          case 8:          switch ( ((x&1)<<1) + (y&1) )
323                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y,          {
324                                                                                   2);                  case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;
325                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize,                  case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;
326                                                                                   4);                  case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;
327                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,                  default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         default:  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
   
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         }  
         } else {  
                 currMV->x = startx;  
                 currMV->y = starty;  
         }  
         return iMinSAD;  
328  }  }
329    
330            sad = sad8(data->Cur, Reference, data->iEdgedWidth);
331            sad += lambda_vec8[data->iQuant] * d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);
332    
333  int32_t          if (sad < *(data->iMinSAD)) {
334  Full16_MainSearch(const uint8_t * const pRef,                  *(data->iMinSAD) = sad;
335                                    const uint8_t * const pRefH,                  data->currentMV->x = x; data->currentMV->y = y;
336                                    const uint8_t * const pRefV,                  *dir = Direction; }
                                   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)  
 {  
         int32_t iSAD;  
         int32_t dx, dy;  
         VECTOR backupMV;  
   
         backupMV.x = startx;  
         backupMV.y = starty;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV16_CANDIDATE(dx, dy);  
   
         return iMinSAD;  
337  }  }
338    
339  int32_t  /* CHECK_CANDIATE FUNCTIONS END */
 AdvDiamond16_MainSearch(const uint8_t * const pRef,  
                                                 const uint8_t * const pRefH,  
                                                 const uint8_t * const pRefV,  
                                                 const uint8_t * const pRefHV,  
                                                 const uint8_t * const cur,  
                                                 const int x,  
                                                 const int y,  
                                                 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 iDirection)  
 {  
340    
341          int32_t iSAD;  /* MAINSEARCH FUNCTIONS START */
342    
343    static void
344    AdvDiamondSearch(int x, int y, const SearchData * const data, int bDirection)
345    {
346    
347  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
348    
349          if (iDirection) {                  int iDirection;
                 CHECK_MV16_CANDIDATE(startx - iDiamondSize, starty);  
                 CHECK_MV16_CANDIDATE(startx + iDiamondSize, starty);  
                 CHECK_MV16_CANDIDATE(startx, starty - iDiamondSize);  
                 CHECK_MV16_CANDIDATE(startx, starty + iDiamondSize);  
         } else {  
                 int bDirection = 1 + 2 + 4 + 8;  
350    
351                  do {                  do {
352                          iDirection = 0;                          iDirection = 0;
353                          if (bDirection & 1)     //we only want to check left if we came from the right (our last motion was to the left, up-left or down-left)                          if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
354                                  CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);                          if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
355                            if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
356                          if (bDirection & 2)                          if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
                                 CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);  
   
                         if (bDirection & 4)  
                                 CHECK_MV16_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);  
   
                         if (bDirection & 8)  
                                 CHECK_MV16_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);  
357    
358                          /* now we're doing diagonal checks near our candidate */                          /* now we're doing diagonal checks near our candidate */
359    
360                          if (iDirection)         //checking if anything found                          if (iDirection) {               //checking if anything found
                         {  
361                                  bDirection = iDirection;                                  bDirection = iDirection;
362                                  iDirection = 0;                                  iDirection = 0;
363                                  startx = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
364                                  starty = currMV->y;                                  if (bDirection & 3) {   //our candidate is left or right
365                                  if (bDirection & 3)     //our candidate is left or right                                          CHECK_CANDIDATE(x, y + iDiamondSize, 8);
366                                  {                                          CHECK_CANDIDATE(x, y - iDiamondSize, 4);
367                                          CHECK_MV16_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);                                  } else {                        // what remains here is up or down
368                                          CHECK_MV16_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y, 2);
369                                  } else                  // what remains here is up or down                                          CHECK_CANDIDATE(x - iDiamondSize, y, 1); }
                                 {  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);  
                                 }  
370    
371                                  if (iDirection) {                                  if (iDirection) {
372                                          bDirection += iDirection;                                          bDirection += iDirection;
373                                          startx = currMV->x;                                          x = data->currentMV->x; y = data->currentMV->y; }
374                                          starty = currMV->y;                          } else {                                //about to quit, eh? not so fast....
                                 }  
                         } else                          //about to quit, eh? not so fast....  
                         {  
375                                  switch (bDirection) {                                  switch (bDirection) {
376                                  case 2:                                  case 2:
377                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
378                                                                                           starty - iDiamondSize, 2 + 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
379                                          break;                                          break;
380                                  case 1:                                  case 1:
381                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
382                                                                                           starty - iDiamondSize, 1 + 4);                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty + iDiamondSize, 1 + 8);  
383                                          break;                                          break;
384                                  case 2 + 4:                                  case 2 + 4:
385                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
386                                                                                           starty - iDiamondSize, 1 + 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
387                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                          starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
388                                          break;                                          break;
389                                  case 4:                                  case 4:
390                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
391                                                                                           starty - iDiamondSize, 2 + 4);                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty - iDiamondSize, 1 + 4);  
392                                          break;                                          break;
393                                  case 8:                                  case 8:
394                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
395                                                                                           starty + iDiamondSize, 2 + 8);                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty + iDiamondSize, 1 + 8);  
396                                          break;                                          break;
397                                  case 1 + 4:                                  case 1 + 4:
398                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
399                                                                                           starty + iDiamondSize, 1 + 8);                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
400                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
                                                                                          starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty - iDiamondSize, 2 + 4);  
401                                          break;                                          break;
402                                  case 2 + 8:                                  case 2 + 8:
403                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
404                                                                                           starty - iDiamondSize, 1 + 4);                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
405                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                          starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
406                                          break;                                          break;
407                                  case 1 + 8:                                  case 1 + 8:
408                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
409                                                                                           starty - iDiamondSize, 2 + 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
410                                          CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                                                                          starty + iDiamondSize, 2 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                          starty + iDiamondSize, 1 + 8);  
411                                          break;                                          break;
412                                  default:                //1+2+4+8 == we didn't find anything at all                                  default:                //1+2+4+8 == we didn't find anything at all
413                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
414                                                                                           starty - iDiamondSize, 1 + 4);                                          CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
415                                          CHECK_MV16_CANDIDATE_DIR(startx - iDiamondSize,                                          CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
416                                                                                           starty + iDiamondSize, 1 + 8);                                          CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                          starty + iDiamondSize, 2 + 8);  
417                                          break;                                          break;
418                                  }                                  }
419                                  if (!iDirection)                                  if (!iDirection) break;         //ok, the end. really
                                         break;          //ok, the end. really  
                                 else {  
420                                          bDirection = iDirection;                                          bDirection = iDirection;
421                                          startx = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
                                         starty = currMV->y;  
                                 }  
422                          }                          }
423                  }                  }
424                  while (1);                              //forever                  while (1);                              //forever
425          }          }
         return iMinSAD;  
 }  
426    
427  int32_t  static void
428  AdvDiamond8_MainSearch(const uint8_t * const pRef,  SquareSearch(int x, int y, const SearchData * const data, int bDirection)
                                            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 iDirection)  
429  {  {
430            int iDirection;
431    
432          int32_t iSAD;          do {
433                    iDirection = 0;
434                    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                    bDirection = iDirection;
444                    x = data->currentMV->x; y = data->currentMV->y;
445            } while (iDirection);
446    }
447    
448    static void
449    DiamondSearch(int x, int y, const SearchData * const data, int bDirection)
450    {
451    
452  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
453    
454          if (iDirection) {                  int iDirection;
                 CHECK_MV8_CANDIDATE(startx - iDiamondSize, starty);  
                 CHECK_MV8_CANDIDATE(startx + iDiamondSize, starty);  
                 CHECK_MV8_CANDIDATE(startx, starty - iDiamondSize);  
                 CHECK_MV8_CANDIDATE(startx, starty + iDiamondSize);  
         } else {  
                 int bDirection = 1 + 2 + 4 + 8;  
455    
456                  do {                  do {
457                          iDirection = 0;                          iDirection = 0;
458                          if (bDirection & 1)     //we only want to check left if we came from the right (our last motion was to the left, up-left or down-left)                          if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
459                                  CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);                          if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
460                            if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
461                          if (bDirection & 2)                          if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
                                 CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);  
   
                         if (bDirection & 4)  
                                 CHECK_MV8_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);  
   
                         if (bDirection & 8)  
                                 CHECK_MV8_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);  
462    
463                          /* now we're doing diagonal checks near our candidate */                          /* now we're doing diagonal checks near our candidate */
464    
465                          if (iDirection)         //checking if anything found                          if (iDirection) {               //checking if anything found
                         {  
466                                  bDirection = iDirection;                                  bDirection = iDirection;
467                                  iDirection = 0;                                  iDirection = 0;
468                                  startx = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
469                                  starty = currMV->y;                                  if (bDirection & 3) {   //our candidate is left or right
470                                  if (bDirection & 3)     //our candidate is left or right                                          CHECK_CANDIDATE(x, y + iDiamondSize, 8);
471                                  {                                          CHECK_CANDIDATE(x, y - iDiamondSize, 4);
472                                          CHECK_MV8_CANDIDATE_DIR(startx, starty + iDiamondSize, 8);                                  } else {                        // what remains here is up or down
473                                          CHECK_MV8_CANDIDATE_DIR(startx, starty - iDiamondSize, 4);                                          CHECK_CANDIDATE(x + iDiamondSize, y, 2);
474                                  } else                  // what remains here is up or down                                          CHECK_CANDIDATE(x - iDiamondSize, y, 1); }
                                 {  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize, starty, 2);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize, starty, 1);  
                                 }  
475    
                                 if (iDirection) {  
476                                          bDirection += iDirection;                                          bDirection += iDirection;
477                                          startx = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
                                         starty = currMV->y;  
                                 }  
                         } else                          //about to quit, eh? not so fast....  
                         {  
                                 switch (bDirection) {  
                                 case 2:  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1:  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 2 + 4:  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 4:  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         break;  
                                 case 8:  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 1 + 4:  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         break;  
                                 case 2 + 8:  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1 + 8:  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         break;  
                                 default:                //1+2+4+8 == we didn't find anything at all  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx - iDiamondSize,  
                                                                                         starty + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(startx + iDiamondSize,  
                                                                                         starty + iDiamondSize, 2 + 8);  
                                         break;  
                                 }  
                                 if (!(iDirection))  
                                         break;          //ok, the end. really  
                                 else {  
                                         bDirection = iDirection;  
                                         startx = currMV->x;  
                                         starty = currMV->y;  
                                 }  
478                          }                          }
479                  }                  }
480                  while (1);                              //forever                  while (iDirection);
         }  
         return iMinSAD;  
 }  
   
   
 int32_t  
 Full8_MainSearch(const uint8_t * const pRef,  
                                  const uint8_t * const pRefH,  
                                  const uint8_t * const pRefV,  
                                  const uint8_t * const pRefHV,  
                                  const uint8_t * const cur,  
                                  const int x,  
                                  const int y,  
                                  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)  
 {  
         int32_t iSAD;  
         int32_t dx, dy;  
         VECTOR backupMV;  
   
         backupMV.x = startx;  
         backupMV.y = starty;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV8_CANDIDATE(dx, dy);  
   
         return iMinSAD;  
481  }  }
482    
483    /* MAINSEARCH FUNCTIONS END */
484    
485    /* HALFPELREFINE COULD BE A MAINSEARCH FUNCTION, BUT THERE IS NO NEED FOR IT */
486    
487  int32_t  static void
488  Halfpel16_Refine(const uint8_t * const pRef,  HalfpelRefine(const SearchData * const data)
                                  const uint8_t * const pRefH,  
                                  const uint8_t * const pRefV,  
                                  const uint8_t * const pRefHV,  
                                  const uint8_t * const cur,  
                                  const int x,  
                                  const int y,  
                                  VECTOR * const currMV,  
                                  int32_t iMinSAD,  
                                  const 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)  
489  {  {
490  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */
491    
492          int32_t iSAD;          VECTOR backupMV = *(data->currentMV);
493          VECTOR backupMV = *currMV;          int iDirection; //not needed
   
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y - 1);  
         CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y - 1);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y - 1);  
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y + 1);  
         CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y + 1);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y + 1);  
   
         return iMinSAD;  
 }  
   
 #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)  
   
494    
495  int32_t          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y - 1, 0);
496  PMVfastSearch16(const uint8_t * const pRef,          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y - 1, 0);
497                                  const uint8_t * const pRefH,          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y + 1, 0);
498                                  const uint8_t * const pRefV,          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y + 1, 0);
                                 const uint8_t * const pRefHV,  
                                 const IMAGE * const pCur,  
                                 const int x,  
                                 const int y,  
                                 const uint32_t MotionFlags,  
                                 const uint32_t iQuant,  
                                 const uint32_t iFcode,  
                                 const MBParam * const pParam,  
                                 const MACROBLOCK * const pMBs,  
                                 const MACROBLOCK * const prevMBs,  
                                 VECTOR * const currMV,  
                                 VECTOR * const currPMV)  
 {  
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
   
         const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;  
   
         int32_t iDiamondSize;  
   
         int32_t min_dx;  
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
   
         int32_t iFound;  
   
         VECTOR newMV;  
         VECTOR backupMV;                        /* just for PMVFAST */  
499    
500          VECTOR pmv[4];          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y, 0);
501          int32_t psad[4];          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y, 0);
502    
503          MainSearch16FuncPtr MainSearchPtr;          CHECK_CANDIDATE(backupMV.x, backupMV.y + 1, 0);
504            CHECK_CANDIDATE(backupMV.x, backupMV.y - 1, 0);
 //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;  
         const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;  
   
         static int32_t threshA, threshB;  
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD;  
   
 /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
   
 /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  
   
         if (!(MotionFlags & PMV_HALFPEL16)) {  
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
505          }          }
506    
507          /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  static __inline int
508          bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  SkipDecisionP(const IMAGE * current, const IMAGE * reference,
509                                                            const int x, const int y,
510          if ((x == 0) && (y == 0)) {                                                          const uint32_t iEdgedWidth, const uint32_t iQuant)
                 threshA = 512;  
                 threshB = 1024;  
   
         } else {  
                 threshA = psad[0];  
                 threshB = threshA + 256;  
                 if (threshA < 512)  
                         threshA = 512;  
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
         }  
   
         iFound = 0;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
511    
512          *currMV = pmv[0];                       /* current best := prediction */  {
513          if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */  /*      keep repeating checks for all b-frames before this P frame,
514                  currMV->x = EVEN(currMV->x);          to make sure that SKIP is possible (todo)
515                  currMV->y = EVEN(currMV->y);          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          if (currMV->x > max_dx) {          return 1;
                 currMV->x = max_dx;  
         }  
         if (currMV->x < min_dx) {  
                 currMV->x = min_dx;  
         }  
         if (currMV->y > max_dy) {  
                 currMV->y = max_dy;  
         }  
         if (currMV->y < min_dy) {  
                 currMV->y = min_dy;  
525          }          }
526    
527          iMinSAD =  static __inline void
528                  sad16(cur,  SkipMacroblockP(MACROBLOCK *pMB, const int32_t sad)
                           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);  
   
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->mvs[0])) &&  
                  ((uint32_t) iMinSAD < prevMB->sad16))) {  
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
529                  {                  {
530                          if (!MVzero(*currMV)) {          pMB->mode = MODE_NOT_CODED;
531                                  iMinSAD += MV16_00_BIAS;          pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = 0;
532                                  CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures          pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = 0;
533                                  iMinSAD -= MV16_00_BIAS;          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
                         }  
534                  }                  }
535    
536                  if (MotionFlags & PMV_QUICKSTOP16)  bool
537                          goto PMVfast16_Terminate_without_Refine;  MotionEstimation(MBParam * const pParam,
538                  if (MotionFlags & PMV_EARLYSTOP16)                                   FRAMEINFO * const current,
539                          goto PMVfast16_Terminate_with_Refine;                                   FRAMEINFO * const reference,
540          }                                   const IMAGE * const pRefH,
541                                     const IMAGE * const pRefV,
542                                     const IMAGE * const pRefHV,
543  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion                                   const uint32_t iLimit)
544     vector of the median.  {
545     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2          MACROBLOCK *const pMBs = current->mbs;
546  */          const IMAGE *const pCurrent = &current->image;
547            const IMAGE *const pRef = &reference->image;
         if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[0])))  
                 iFound = 2;  
   
 /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.  
    Otherwise select large Diamond Search.  
 */  
   
         if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))  
                 iDiamondSize = 1;               // halfpel!  
         else  
                 iDiamondSize = 2;               // halfpel!  
   
         if (!(MotionFlags & PMV_HALFPELDIAMOND16))  
                 iDiamondSize *= 2;  
   
 /*  
    Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  
    Also calculate (0,0) but do not subtract offset.  
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset.  
 */  
   
 // (0,0) is always possible  
548    
549          if (!MVzero(pmv[0]))          const VECTOR zeroMV = { 0, 0 };
                 CHECK_MV16_ZERO;  
550    
551  // previous frame MV is always possible          uint32_t x, y;
552            uint32_t iIntra = 0;
553            int32_t InterBias;
554    
555            // some pre-initialized thingies for SearchP
556            int32_t temp[5];
557            VECTOR currentMV[5];
558            int32_t iMinSAD[5];
559            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          if (!MVzero(prevMB->mvs[0]))                          SearchP(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
592                  if (!MVequal(prevMB->mvs[0], pmv[0]))                                                  y, current->motion_flags, pMB->quant,
593                          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);                                                  &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  // left neighbour, if allowed  /* finally, intra decision */
602    
603          if (!MVzero(pmv[1]))                          InterBias = MV16_INTER_BIAS;
604                  if (!MVequal(pmv[1], prevMB->mvs[0]))                          if (pMB->quant > 8)  InterBias += 50 * (pMB->quant - 8); // to make high quants work
605                          if (!MVequal(pmv[1], pmv[0])) {                          if (y != 0)
606                                  if (!(MotionFlags & PMV_HALFPEL16)) {                                  if ((pMB - pParam->mb_width)->mode == MODE_INTER ) InterBias -= 50;
607                                          pmv[1].x = EVEN(pmv[1].x);                          if (x != 0)
608                                          pmv[1].y = EVEN(pmv[1].y);                                  if ((pMB - 1)->mode == MODE_INTER ) InterBias -= 50;
                                 }  
609    
610                                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);                          if (InterBias < pMB->sad16)  {
611                          }                                  const int32_t deviation =
612  // top neighbour, if allowed                                          dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,
613          if (!MVzero(pmv[2]))                                                    pParam->edged_width);
                 if (!MVequal(pmv[2], prevMB->mvs[0]))  
                         if (!MVequal(pmv[2], pmv[0]))  
                                 if (!MVequal(pmv[2], pmv[1])) {  
                                         if (!(MotionFlags & PMV_HALFPEL16)) {  
                                                 pmv[2].x = EVEN(pmv[2].x);  
                                                 pmv[2].y = EVEN(pmv[2].y);  
                                         }  
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
614    
615  // top right neighbour, if allowed                                  if (deviation < (pMB->sad16 - InterBias)) {
616                                          if (!MVzero(pmv[3]))                                          if (++iIntra >= iLimit) return 1;
617                                                  if (!MVequal(pmv[3], prevMB->mvs[0]))                                          pMB->mode = MODE_INTRA;
618                                                          if (!MVequal(pmv[3], pmv[0]))                                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =
619                                                                  if (!MVequal(pmv[3], pmv[1]))                                                          pMB->mvs[3] = zeroMV;
620                                                                          if (!MVequal(pmv[3], pmv[2])) {                                          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =
621                                                                                  if (!(MotionFlags & PMV_HALFPEL16)) {                                                  pMB->sad8[3] = 0;
                                                                                         pmv[3].x = EVEN(pmv[3].x);  
                                                                                         pmv[3].y = EVEN(pmv[3].y);  
622                                                                                  }                                                                                  }
                                                                                 CHECK_MV16_CANDIDATE(pmv[3].x,  
                                                                                                                          pmv[3].y);  
623                                                                          }                                                                          }
624                                  }                                  }
   
         if ((MVzero(*currMV)) &&  
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV16_00_BIAS;  
   
   
 /* Step 6: If MinSAD <= thresa goto Step 10.  
    If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
 */  
   
         if ((iMinSAD <= threshA) ||  
                 (MVequal(*currMV, prevMB->mvs[0]) &&  
                  ((uint32_t) iMinSAD < prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
625          }          }
626            return 0;
   
 /************ (Diamond Search)  **************/  
 /*  
    Step 7: Perform Diamond search, with either the small or large diamond.  
    If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
    Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
    If center then goto step 10.  
    Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
    Refine by using small diamond and goto step 10.  
 */  
   
         if (MotionFlags & PMV_USESQUARES16)  
                 MainSearchPtr = Square16_MainSearch;  
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
   
         backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  
   
 /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  
                                                   currMV->y, iMinSAD, &newMV, pmv, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
627          }          }
628    
         if (MotionFlags & PMV_EXTSEARCH16) {  
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
629    
630                  if (!(MVequal(pmv[0], backupMV))) {  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)
                         iSAD =  
                                 (*MainSearchPtr) (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);  
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
                 }  
631    
632                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {  static __inline int
633                          iSAD =  make_mask(const VECTOR * const pmv, const int i)
634                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  {
635                                                                    iMinSAD, &newMV, pmv, min_dx, max_dx, min_dy,          int mask = 255, j;
636                                                                    max_dy, iEdgedWidth, iDiamondSize, iFcode,          for (j = 0; j < i; j++) {
637                                                                    iQuant, iFound);                  if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already
638                    if (pmv[i].x == pmv[j].x) {
639                          if (iSAD < iMinSAD) {                          if (pmv[i].y == pmv[j].y + iDiamondSize) { mask &= ~4; continue; }
640                                  *currMV = newMV;                          if (pmv[i].y == pmv[j].y - iDiamondSize) { mask &= ~8; continue; }
641                                  iMinSAD = iSAD;                  } 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  /*  static __inline void
651     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  PreparePredictionsP(VECTOR * const pmv, int x, int y, const int iWcount,
652  */                          const int iHcount, const MACROBLOCK * const prevMB)
653    {
   PMVfast16_Terminate_with_Refine:  
         if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step  
                 iMinSAD =  
                         Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                          iMinSAD, pmv, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
   
   PMVfast16_Terminate_without_Refine:  
         currPMV->x = currMV->x - pmv[0].x;  
         currPMV->y = currMV->y - pmv[0].y;  
         return iMinSAD;  
 }  
   
   
   
   
654    
655    //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself
656    
657  int32_t          if ( (y != 0) && (x != (iWcount-1)) ) {         // [5] top-right neighbour
658  Diamond8_MainSearch(const uint8_t * const pRef,                  pmv[5].x = EVEN(pmv[3].x);
659                                          const uint8_t * const pRefH,                  pmv[5].y = EVEN(pmv[3].y);
660                                          const uint8_t * const pRefV,          } else pmv[5].x = pmv[5].y = 0;
                                         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_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;  
 }  
661    
662  int32_t          if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }// pmv[3] is left neighbour
663  Halfpel8_Refine(const uint8_t * const pRef,          else pmv[3].x = pmv[3].y = 0;
                                 const uint8_t * const pRefH,  
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const uint8_t * const cur,  
                                 const int x,  
                                 const int y,  
                                 VECTOR * const currMV,  
                                 int32_t iMinSAD,  
                                 const 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)  
 {  
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
664    
665          int32_t iSAD;          if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }// [4] top neighbour
666          VECTOR backupMV = *currMV;      else pmv[4].x = pmv[4].y = 0;
667    
668          CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y - 1);          // [1] median prediction
669          CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y - 1);          pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y + 1);  
         CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y + 1);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y + 1);  
670    
671          return iMinSAD;          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            pmv[2].x = EVEN(prevMB->mvs[0].x); // [2] is last frame
674            pmv[2].y = EVEN(prevMB->mvs[0].y);
675    
676  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)          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    
682  int32_t  static void
683  PMVfastSearch8(const uint8_t * const pRef,  SearchP(const uint8_t * const pRef,
684                             const uint8_t * const pRefH,                             const uint8_t * const pRefH,
685                             const uint8_t * const pRefV,                             const uint8_t * const pRefV,
686                             const uint8_t * const pRefHV,                             const uint8_t * const pRefHV,
687                             const IMAGE * const pCur,                             const IMAGE * const pCur,
688                             const int x,                             const int x,
689                             const int y,                             const int y,
                            const int start_x,  
                            const int start_y,  
690                             const uint32_t MotionFlags,                             const uint32_t MotionFlags,
691                             const uint32_t iQuant,                             const uint32_t iQuant,
692                             const uint32_t iFcode,                  SearchData * const Data,
693                             const MBParam * const pParam,                             const MBParam * const pParam,
694                             const MACROBLOCK * const pMBs,                             const MACROBLOCK * const pMBs,
695                             const MACROBLOCK * const prevMBs,                             const MACROBLOCK * const prevMBs,
696                             VECTOR * const currMV,                  int inter4v,
697                             VECTOR * const currPMV)                  MACROBLOCK * const pMB)
698  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
699    
700          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;          int i, iDirection = 255, mask, threshA;
701            VECTOR pmv[7];
702    
703          int32_t iDiamondSize;          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          int32_t min_dx;          Data->predMV = pmv[0];
708          int32_t max_dx;          Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16;
709          int32_t min_dy;          Data->Ref = pRef + (x + Data->iEdgedWidth*y)*16;
710          int32_t max_dy;          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          VECTOR pmv[4];          Data->iQuant = iQuant;
         int32_t psad[4];  
         VECTOR newMV;  
         VECTOR backupMV;  
         VECTOR startMV;  
715    
716  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          if (!(MotionFlags & PMV_HALFPEL16)) {
717          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;                  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          static int32_t threshA, threshB;          for(i = 0;  i < 5; i++) Data->iMinSAD[i] = 256*4096;
         int32_t iFound, bPredEq;  
         int32_t iMinSAD, iSAD;  
723    
724          int32_t iSubBlock = (y & 1) + (y & 1) + (x & 1);          if (inter4v) CheckCandidate = CheckCandidate16;
725            else CheckCandidate = CheckCandidate16no4v;
726    
727          MainSearch8FuncPtr MainSearchPtr;          (*CheckCandidate)(Data->predMV.x, Data->predMV.y, 0, &iDirection, Data);
728    
729          /* Init variables */          for(i = 0;  i < 5; i++) Data->currentMV[i].x = Data->currentMV[i].y = 0;
         startMV.x = start_x;  
         startMV.y = start_y;  
730    
731          /* Get maximum range */          i = d_mv_bits(Data->predMV.x, Data->predMV.y, Data->iFcode);
732          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,          Data->iMinSAD[0] = pMB->sad16 + lambda_vec16[iQuant] * i;
733                            iFcode);          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 (!(MotionFlags & PMV_HALFPELDIAMOND8)) {          if (pMB->dquant != NO_CHANGE) inter4v = 0;
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
         }  
739    
740          /* because we might use IF (dx>max_dx) THEN dx=max_dx; */          if ((x == 0) && (y == 0)) threshA = 512;
741          bPredEq =          else {
742                  get_pmvdata(pMBs, (x >> 1), (y >> 1), iWcount, iSubBlock, pmv, psad);                  threshA = Data->temp[0] + 20;
743                    if (threshA < 512) threshA = 512;
744                    if (threshA > 1024) threshA = 1024; }
745    
746          if ((x == 0) && (y == 0)) {          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
747                  threshA = 512 / 4;                                          prevMBs + x + y * pParam->mb_width);
                 threshB = 1024 / 4;  
748    
749          } else {  /* main loop. checking all predictions */
                 threshA = psad[0] / 4;  /* good estimate */  
                 threshB = threshA + 256 / 4;  
                 if (threshA < 512 / 4)  
                         threshA = 512 / 4;  
                 if (threshA > 1024 / 4)  
                         threshA = 1024 / 4;  
                 if (threshB > 1792 / 4)  
                         threshB = 1792 / 4;  
         }  
   
         iFound = 0;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
750    
751            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  // Prepare for main loop          if ((Data->iMinSAD[0] <= threshA) ||
758                            (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  //  if (MotionFlags & PMV_USESQUARES8)                  MainSearchFunc * MainSearchPtr;
764  //      MainSearchPtr = Square8_MainSearch;                  if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
765  //  else                  else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
766                            else MainSearchPtr = DiamondSearch;
767          if (MotionFlags & PMV_ADVANCEDDIAMOND8)  
768                  MainSearchPtr = AdvDiamond8_MainSearch;                  (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
769          else  
770                  MainSearchPtr = Diamond8_MainSearch;  /* 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 */
         *currMV = startMV;  
   
         iMinSAD =  
                 sad8(cur,  
                          get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  
                                                 iEdgedWidth), iEdgedWidth);  
         iMinSAD +=  
                 calc_delta_8(currMV->x - pmv[0].x, currMV->y - pmv[0].y,  
                                          (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256 / 4) || ((MVequal(*currMV, prevMB->mvs[iSubBlock]))  
                                                                 && ((uint32_t) iMinSAD <  
                                                                         prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  
    vector of the median.  
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
773    
774          if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[iSubBlock])))                  if (MotionFlags & PMV_EXTSEARCH16) {
775                  iFound = 2;                          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                                    CheckCandidate16(startMV.x, startMV.y, 255, &iDirection, Data);
783                                    (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
784                                    if (bSAD < Data->iMinSAD[0]) {
785                                            Data->currentMV[0] = backupMV;
786                                            Data->iMinSAD[0] = bSAD; }
787                            }
788    
789                            backupMV = Data->currentMV[0];
790                            if (MotionFlags & PMV_HALFPELREFINE16) startMV.x = startMV.y = 1;
791                            else startMV.x = startMV.y = 0;
792                            if (!(MVequal(startMV, backupMV))) {
793                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
794    
795                                    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                            }
801                    }
802            }
803    
804  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.          if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(Data);
805     Otherwise select large Diamond Search.  
806  */          if (inter4v) {
807                    SearchData Data8;
808                    Data8.iFcode = Data->iFcode;
809                    Data8.iQuant = Data->iQuant;
810                    Data8.iEdgedWidth = Data->iEdgedWidth;
811                    Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
812                    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                    (Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
819                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {
820    // INTER MODE
821                    pMB->mode = MODE_INTER;
822                    pMB->mvs[0] = pMB->mvs[1]
823                            = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
824    
825          if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
826                  iDiamondSize = 1;               // 1 halfpel!                          pMB->sad8[2] = pMB->sad8[3] =  Data->iMinSAD[0];
         else  
                 iDiamondSize = 2;               // 2 halfpel = 1 full pixel!  
827    
828          if (!(MotionFlags & PMV_HALFPELDIAMOND8))                  pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
829                  iDiamondSize *= 2;                  pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
830            } else {
831    // INTER4V MODE; all other things are already set in Search8
832                    pMB->mode = MODE_INTER4V;
833                    pMB->sad16 = Data->iMinSAD[1] + Data->iMinSAD[2] +
834                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * iQuant;
835            }
836    
837    }
838    
839  /*  static void
840     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  Search8(const SearchData * const OldData,
841     Also calculate (0,0) but do not subtract offset.                  const int x, const int y,
842     Let MinSAD be the smallest SAD up to this point.                  const uint32_t MotionFlags,
843     If MV is (0,0) subtract offset.                  const MBParam * const pParam,
844  */                  MACROBLOCK * const pMB,
845                    const MACROBLOCK * const pMBs,
846                    const int block,
847                    SearchData * const Data)
848    {
849            Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2 , y/2, block);
850            Data->iMinSAD = OldData->iMinSAD + 1 + block;
851            Data->currentMV = OldData->currentMV + 1 + block;
852    
853  // the median prediction might be even better than mv16          if (block != 0)
854                    *(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 (!MVequal(pmv[0], startMV))          if (MotionFlags & (PMV_EXTSEARCH8|PMV_HALFPELREFINE8)) {
                 CHECK_MV8_CANDIDATE(pmv[0].x, pmv[0].y);  
860    
861  // (0,0) if needed                  Data->Ref = OldData->Ref + 8 * ((block&1) + pParam->edged_width*(block>>1));
862          if (!MVzero(pmv[0]))                  Data->RefH = OldData->RefH + 8 * ((block&1) + pParam->edged_width*(block>>1));
863                  if (!MVzero(startMV))                  Data->RefV = OldData->RefV + 8 * ((block&1) + pParam->edged_width*(block>>1));
864                          CHECK_MV8_ZERO;                  Data->RefHV = OldData->RefHV + 8 * ((block&1) + pParam->edged_width*(block>>1));
   
 // previous frame MV if needed  
         if (!MVzero(prevMB->mvs[iSubBlock]))  
                 if (!MVequal(prevMB->mvs[iSubBlock], startMV))  
                         if (!MVequal(prevMB->mvs[iSubBlock], pmv[0]))  
                                 CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x,  
                                                                         prevMB->mvs[iSubBlock].y);  
   
         if ((iMinSAD <= threshA) ||  
                 (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&  
                  ((uint32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 // left neighbour, if allowed and needed  
         if (!MVzero(pmv[1]))  
                 if (!MVequal(pmv[1], startMV))  
                         if (!MVequal(pmv[1], prevMB->mvs[iSubBlock]))  
                                 if (!MVequal(pmv[1], pmv[0])) {  
                                         if (!(MotionFlags & PMV_HALFPEL8)) {  
                                                 pmv[1].x = EVEN(pmv[1].x);  
                                                 pmv[1].y = EVEN(pmv[1].y);  
                                         }  
                                         CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);  
                                 }  
 // top neighbour, if allowed and needed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], startMV))  
                         if (!MVequal(pmv[2], prevMB->mvs[iSubBlock]))  
                                 if (!MVequal(pmv[2], pmv[0]))  
                                         if (!MVequal(pmv[2], pmv[1])) {  
                                                 if (!(MotionFlags & PMV_HALFPEL8)) {  
                                                         pmv[2].x = EVEN(pmv[2].x);  
                                                         pmv[2].y = EVEN(pmv[2].y);  
                                                 }  
                                                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed and needed  
                                                 if (!MVzero(pmv[3]))  
                                                         if (!MVequal(pmv[3], startMV))  
                                                                 if (!MVequal(pmv[3], prevMB->mvs[iSubBlock]))  
                                                                         if (!MVequal(pmv[3], pmv[0]))  
                                                                                 if (!MVequal(pmv[3], pmv[1]))  
                                                                                         if (!MVequal(pmv[3], pmv[2])) {  
                                                                                                 if (!  
                                                                                                         (MotionFlags &  
                                                                                                          PMV_HALFPEL8)) {  
                                                                                                         pmv[3].x = EVEN(pmv[3].x);  
                                                                                                         pmv[3].y = EVEN(pmv[3].y);  
                                                                                                 }  
                                                                                                 CHECK_MV8_CANDIDATE(pmv[3].x,  
                                                                                                                                         pmv[3].y);  
                                                                                         }  
                                         }  
   
         if ((MVzero(*currMV)) &&  
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV8_00_BIAS;  
865    
866                    Data->Cur = OldData->Cur + 8 * ((block&1) + pParam->edged_width*(block>>1));
867    
868  /* Step 6: If MinSAD <= thresa goto Step 10.                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
869     If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.                                  pParam->width, pParam->height, OldData->iFcode);
 */  
870    
871          if ((iMinSAD <= threshA) ||                  CheckCandidate = CheckCandidate8;
                 (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&  
                  ((uint32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
872    
873  /************ (Diamond Search)  **************/                  if (MotionFlags & PMV_EXTSEARCH8) {
 /*  
    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.  
 */  
874    
875          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                          MainSearchFunc *MainSearchPtr;
876                            if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
877                                    else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
878                                            else MainSearchPtr = DiamondSearch;
879    
880  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */                          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);    }
         iSAD =  
                 (*MainSearchPtr) (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);  
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
881    
882          if (MotionFlags & PMV_EXTSEARCH8) {                  if (MotionFlags & PMV_HALFPELREFINE8) HalfpelRefine(Data);
883  /* extended: search (up to) two more times: orignal prediction and (0,0) */          }
884    
885                  if (!(MVequal(pmv[0], backupMV))) {          pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
886                          iSAD =          pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
887                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,          pMB->mvs[block] = *(Data->currentMV);
888                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, pmv,          pMB->sad8[block] =  4 * (*Data->iMinSAD);
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
889    
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
890                  }                  }
891    
892                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {  /* B-frames code starts here */
                         iSAD =  
                                 (*MainSearchPtr) (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                                  *currMV = newMV;  ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
896                                  iMinSAD = iSAD;  {
897                          }  /* the stupidiest function ever */
898                  }          if (mode == MODE_FORWARD) return pMB->mvs[0];
899            else return pMB->b_mvs[0];
900          }          }
901    
902  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.  static void __inline
903     By performing an optional local half-pixel search, we can refine this result even further.  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    PMVfast8_Terminate_with_Refine:          // [0] is prediction
910          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step          pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
                 iMinSAD =  
                         Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                         iMinSAD, pmv, min_dx, max_dx, min_dy, max_dy,  
                                                         iFcode, iQuant, iEdgedWidth);  
911    
912            pmv[1].x = pmv[1].y = 0; // [1] is zero
913    
914    PMVfast8_Terminate_without_Refine:          pmv[2] = ChoosePred(pMB, mode_curr);
915          currPMV->x = currMV->x - pmv[0].x;          pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
         currPMV->y = currMV->y - pmv[0].y;  
916    
917          return iMinSAD;          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            if ((x != 0)&&(y != 0)) {
933                    pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
934                    pmv[6].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
935            } else pmv[6].x = pmv[6].y = 0;
936    
937    // more?
938  }  }
939    
940  int32_t  
941  EPZSSearch16(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 IMAGE * const pCur,                           const IMAGE * const pCur,
948                           const int x,                          const int x, const int y,
                          const int y,  
949                           const uint32_t MotionFlags,                           const uint32_t MotionFlags,
950                           const uint32_t iQuant,                           const uint32_t iQuant,
951                           const uint32_t iFcode,                           const uint32_t iFcode,
952                           const MBParam * const pParam,                           const MBParam * const pParam,
953                           const MACROBLOCK * const pMBs,                          MACROBLOCK * const pMB,
954                           const MACROBLOCK * const prevMBs,                          const VECTOR * const predMV,
955                           VECTOR * const currMV,                          int32_t * const best_sad,
956                           VECTOR * const currPMV)                          const int32_t mode_current)
957  {  {
         const uint32_t iWcount = pParam->mb_width;  
         const uint32_t iHcount = pParam->mb_height;  
958    
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
959          const int32_t iEdgedWidth = pParam->edged_width;          const int32_t iEdgedWidth = pParam->edged_width;
960    
961          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          int i, iDirection, mask;
962            VECTOR currentMV, pmv[7];
963          int32_t min_dx;          MainSearchFunc *MainSearchPtr;
964          int32_t max_dx;          int32_t iMinSAD = MV_MAX_ERROR;
965          int32_t min_dy;          SearchData Data;
966          int32_t max_dy;  
967            Data.iMinSAD = &iMinSAD;
968            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          VECTOR newMV;          get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 16,
982          VECTOR backupMV;                                  pParam->width, pParam->height, iFcode);
983    
984          VECTOR pmv[4];          if (!(MotionFlags & PMV_HALFPEL16)) {
985          int32_t psad[8];                  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    
         static MACROBLOCK *oldMBs = NULL;  
990    
991  //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;          pmv[0] = Data.predMV;
992          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;          PreparePredictionsBF(pmv, x, y, pParam->mb_width,
993          MACROBLOCK *oldMB = NULL;                                          pMB, mode_current);
994    
995          static int32_t thresh2;          currentMV.x = currentMV.y = 0;
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD = 9999;  
996    
997          MainSearch16FuncPtr MainSearchPtr;          CheckCandidate = CheckCandidate16no4v;
998    
999          if (oldMBs == NULL) {  // main loop. checking all predictions
1000                  oldMBs = (MACROBLOCK *) calloc(iWcount * iHcount, sizeof(MACROBLOCK));          for (i = 0; i < 8; i++) {
1001  //      fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));                  if (!(mask = make_mask(pmv, i)) ) continue;
1002                    CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, &Data);
1003          }          }
         oldMB = oldMBs + x + y * iWcount;  
   
 /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
   
         if (!(MotionFlags & PMV_HALFPEL16)) {  
                 min_dx = EVEN(min_dx);  
                 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; */  
         bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  
   
 /* Step 4: Calculate SAD around the Median prediction.  
         MinSAD=SAD  
         If Motion Vector equal to Previous frame motion vector  
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
 */  
   
 // Prepare for main loop  
1004    
1005          *currMV = pmv[0];                       /* current best := median prediction */          if (MotionFlags & PMV_USESQUARES16)
1006          if (!(MotionFlags & PMV_HALFPEL16)) {                  MainSearchPtr = SquareSearch;
1007                  currMV->x = EVEN(currMV->x);          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
1008                  currMV->y = EVEN(currMV->y);                  MainSearchPtr = AdvDiamondSearch;
1009          }                  else MainSearchPtr = DiamondSearch;
1010    
1011          if (currMV->x > max_dx)          (*MainSearchPtr)(currentMV.x, currentMV.y, &Data, 255);
                 currMV->x = max_dx;  
         if (currMV->x < min_dx)  
                 currMV->x = min_dx;  
         if (currMV->y > max_dy)  
                 currMV->y = max_dy;  
         if (currMV->y < min_dy)  
                 currMV->y = min_dy;  
   
 /***************** This is predictor SET A: only median prediction ******************/  
   
         iMinSAD =  
                 sad16(cur,  
                           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);  
   
 // thresh1 is fixed to 256  
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->mvs[0])) &&  
                  ((uint32_t) iMinSAD < prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
         }  
   
 /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/  
1012    
1013  // previous frame MV          if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(&Data);
         CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);  
1014    
1015  // set threshhold based on Min of Prediction and SAD of collocated block  // three bits are needed to code backward mode. four for forward
1016  // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want  // 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    
         if ((x == 0) && (y == 0)) {  
                 thresh2 = 512;  
         } else {  
 /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */  
1020    
1021                  thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;          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    
 // MV=(0,0) is often a good choice  
   
         CHECK_MV16_ZERO;  
   
   
 // left neighbour, if allowed  
         if (x != 0) {  
                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                         pmv[1].x = EVEN(pmv[1].x);  
                         pmv[1].y = EVEN(pmv[1].y);  
1030                  }                  }
                 CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
         }  
 // top neighbour, if allowed  
         if (y != 0) {  
                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                         pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
                 }  
                 CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
1031    
1032  // top right neighbour, if allowed  static int32_t
1033                  if ((uint32_t) x != (iWcount - 1)) {  SearchDirect(const IMAGE * const f_Ref,
1034                          if (!(MotionFlags & PMV_HALFPEL16)) {                                  const uint8_t * const f_RefH,
1035                                  pmv[3].x = EVEN(pmv[3].x);                                  const uint8_t * const f_RefV,
1036                                  pmv[3].y = EVEN(pmv[3].y);                                  const uint8_t * const f_RefHV,
1037                          }                                  const IMAGE * const b_Ref,
1038                          CHECK_MV16_CANDIDATE(pmv[3].x, pmv[3].y);                                  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    
 /* Terminate if MinSAD <= T_2  
    Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]  
1078  */  */
1079            Data.max_dx = 2 * pParam->width - 2 * (x) * 16;
1080          if ((iMinSAD <= thresh2)          Data.max_dy = 2 * pParam->height - 2 * (y) * 16;
1081                  || (MVequal(*currMV, prevMB->mvs[0]) &&          Data.min_dx = -(2 * 16 + 2 * (x) * 16);
1082                          ((uint32_t) iMinSAD <= prevMB->sad16))) {          Data.min_dy = -(2 * 16 + 2 * (y) * 16);
1083                  if (MotionFlags & PMV_QUICKSTOP16)  
1084                          goto EPZS16_Terminate_without_Refine;          for (k = 0; k < 4; k++) {
1085                  if (MotionFlags & PMV_EARLYSTOP16)                  pMB->mvs[k].x = Data.directmvF[k].x = ((TRB * Data.referencemv[k].x) / TRD);
1086                          goto EPZS16_Terminate_with_Refine;                  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  /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/          if (b_mb->mode == MODE_INTER4V)
1110                    CheckCandidate = CheckCandidateDirect;
1111            else CheckCandidate = CheckCandidateDirectno4v;
1112    
1113          backupMV = prevMB->mvs[0];      // collocated MV          (*CheckCandidate)(0, 0, 255, &k, &Data);
         backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x);     // acceleration X  
         backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y);     // acceleration Y  
1114    
1115          CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y);  // 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  // left neighbour                  sum = pMB->mvs[0].x + pMB->mvs[1].x + pMB->mvs[2].x + pMB->mvs[3].x;
1122          if (x != 0)                  dx = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
                 CHECK_MV16_CANDIDATE((prevMB - 1)->mvs[0].x, (prevMB - 1)->mvs[0].y);  
1123    
1124  // top neighbour                  sum = pMB->mvs[0].y + pMB->mvs[1].y + pMB->mvs[2].y + pMB->mvs[3].y;
1125          if (y != 0)                  dy = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
                 CHECK_MV16_CANDIDATE((prevMB - iWcount)->mvs[0].x,  
                                                          (prevMB - iWcount)->mvs[0].y);  
1126    
1127  // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs                  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          if ((uint32_t) x != iWcount - 1)                  sum = pMB->b_mvs[0].y + pMB->b_mvs[1].y + pMB->b_mvs[2].y + pMB->b_mvs[3].y;
1131                  CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);                  b_dy = (sum == 0 ? 0 : SIGN(sum) * (roundtab[ABS(sum) % 16] + (ABS(sum) / 16) * 2));
1132    
1133  // bottom neighbour, dito                  sum = sad8bi(pCur->u + 8*x + 8*y*(iEdgedWidth/2),
1134          if ((uint32_t) y != iHcount - 1)                                          f_Ref->u + (y*8 + dy/2) * (iEdgedWidth/2) + x*8 + dx/2,
1135                  CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,                                          b_Ref->u + (y*8 + b_dy/2) * (iEdgedWidth/2) + x*8 + b_dx/2,
1136                                                           (prevMB + iWcount)->mvs[0].y);                                          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  /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */                  if ((uint32_t) sum < MAX_CHROMA_SAD_FOR_SKIP * Data.iQuant) {
1143          if (iMinSAD <= thresh2) {                          pMB->mode = MODE_DIRECT_NONE_MV;
1144                  if (MotionFlags & PMV_QUICKSTOP16)                          return iMinSAD;
1145                          goto EPZS16_Terminate_without_Refine;                  }
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
1146          }          }
1147    
1148  /************ (if Diamond Search)  **************/          skip_sad = iMinSAD;
   
         backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  
   
         if (MotionFlags & PMV_USESQUARES8)  
                 MainSearchPtr = Square16_MainSearch;  
         else  
          if (MotionFlags & PMV_ADVANCEDDIAMOND8)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
   
 /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  
1149    
1150          iSAD =  //  DIRECT MODE DELTA VECTOR SEARCH.
1151                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  //      This has to be made more effective, but at the moment I'm happy it's running at all
                                                   currMV->y, iMinSAD, &newMV, pmv, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);  
1152    
1153          if (iSAD < iMinSAD) {          if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1154                  *currMV = newMV;                  else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1155                  iMinSAD = iSAD;                          else MainSearchPtr = DiamondSearch;
         }  
1156    
1157            (*MainSearchPtr)(0, 0, &Data, 255);
1158    
1159          if (MotionFlags & PMV_EXTSEARCH16) {          HalfpelRefine(&Data);
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
1160    
1161                  if (!(MVequal(pmv[0], backupMV))) {          iMinSAD +=  1 * lambda_vec16[iQuant]; // one bit is needed to code direct mode. we treat this bit just like it was vector's
1162                          iSAD =          *best_sad = iMinSAD;
                                 (*MainSearchPtr) (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,  
                                                                   2, iFcode, iQuant, 0);  
                 }  
1163    
1164                  if (iSAD < iMinSAD) {          if (b_mb->mode == MODE_INTER4V)
1165                          *currMV = newMV;                  pMB->mode = MODE_DIRECT;
1166                          iMinSAD = iSAD;          else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation
                 }  
1167    
1168                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          pMB->pmvs[3] = currentMV;
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, pmv, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);  
1169    
1170                          if (iSAD < iMinSAD) {          for (k = 0; k < 4; k++) {
1171                                  *currMV = newMV;                  pMB->mvs[k].x = Data.directmvF[k].x + currentMV.x;
1172                                  iMinSAD = iSAD;                  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;
 /***************        Choose best MV found     **************/  
   
   EPZS16_Terminate_with_Refine:  
         if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step  
                 iMinSAD =  
                         Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                          iMinSAD, pmv, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
   
   EPZS16_Terminate_without_Refine:  
   
         *oldMB = *prevMB;  
   
         currPMV->x = currMV->x - pmv[0].x;  
         currPMV->y = currMV->y - pmv[0].y;  
         return iMinSAD;  
1186  }  }
1187    
1188    static __inline void
1189  int32_t  SearchInterpolate(const uint8_t * const f_Ref,
1190  EPZSSearch8(const uint8_t * const pRef,                                  const uint8_t * const f_RefH,
1191                          const uint8_t * const pRefH,                                  const uint8_t * const f_RefV,
1192                          const uint8_t * const pRefV,                                  const uint8_t * const f_RefHV,
1193                          const uint8_t * const pRefHV,                                  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 x, const int y,
1199                          const int y,                                  const uint32_t fcode,
1200                          const int start_x,                                  const uint32_t bcode,
                         const int start_y,  
1201                          const uint32_t MotionFlags,                          const uint32_t MotionFlags,
1202                          const uint32_t iQuant,                          const uint32_t iQuant,
                         const uint32_t iFcode,  
1203                          const MBParam * const pParam,                          const MBParam * const pParam,
1204                          const MACROBLOCK * const pMBs,                                  const VECTOR * const f_predMV,
1205                          const MACROBLOCK * const prevMBs,                                  const VECTOR * const b_predMV,
1206                          VECTOR * const currMV,                                  MACROBLOCK * const pMB,
1207                          VECTOR * const currPMV)                                  int32_t * const best_sad)
1208    
1209  {  {
1210  /* Please not that EPZS might not be a good choice for 8x8-block motion search ! */  /* 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 uint32_t iWcount = pParam->mb_width;  
         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          int32_t iDiamondSize = 1;          CheckCandidateInt(currentMV[0].x, currentMV[0].y, 255, &iDirection, &fData);
1258    
1259          int32_t min_dx;  //diamond. I wish we could use normal mainsearch functions (square, advdiamond)
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
1260    
1261          VECTOR newMV;          do {
1262          VECTOR backupMV;                  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          VECTOR pmv[4];  void
1298          int32_t psad[8];  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          const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
1321    
1322  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          const int32_t TRB = time_pp - time_bp;
1323          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;          const int32_t TRD = time_pp;
1324    
1325          int32_t bPredEq;          // note: i==horizontal, j==vertical
         int32_t iMinSAD, iSAD = 9999;  
1326    
1327          MainSearch8FuncPtr MainSearchPtr;          for (j = 0; j < pParam->mb_height; j++) {
1328    
1329  /* Get maximum range */                  f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,  
                           iFcode);  
1330    
1331  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */                  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          if (!(MotionFlags & PMV_HALFPEL8)) {  /* special case, if collocated block is SKIPed: encoding is forward (0,0), cpb=0 without further ado */
1336                  min_dx = EVEN(min_dx);                          if (b_mb->mode == MODE_NOT_CODED) {
1337                  max_dx = EVEN(max_dx);                                  pMB->mode = MODE_NOT_CODED;
1338                  min_dy = EVEN(min_dy);                                  continue;
                 max_dy = EVEN(max_dy);  
1339          }          }
         /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
         bPredEq = get_pmvdata(pMBs, x >> 1, y >> 1, iWcount, iSubBlock, pmv, psad);  
1340    
1341    /* 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  /* Step 4: Calculate SAD around the Median prediction.                          skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
1345          MinSAD=SAD                                                                          b_ref, b_refH->y, b_refV->y, b_refHV->y,
1346          If Motion Vector equal to Previous frame motion vector                                                                          &frame->image,
1347                  and MinSAD<PrevFrmSAD goto Step 10.                                                                          i, j,
1348          If SAD<=256 goto Step 10.                                                                          frame->motion_flags,
1349  */                                                                          frame->quant,
1350                                                                            TRB, TRD,
1351                                                                            pParam,
1352                                                                            pMB, b_mb,
1353                                                                            &best_sad);
1354    
1355  // Prepare for main loop                          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          if (!(MotionFlags & PMV_HALFPEL8)) {                          // forward search
1361                  currMV->x = EVEN(currMV->x);                          SearchBF(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
1362                  currMV->y = EVEN(currMV->y);                                                  &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          if (currMV->x > max_dx)  //      fprintf(debug,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d, N: %04d\n",
1413                  currMV->x = max_dx;  //                              f_count,b_count,i_count,d_count,n_count);
1414          if (currMV->x < min_dx)  
1415                  currMV->x = min_dx;  }
1416          if (currMV->y > max_dy)  
1417                  currMV->y = max_dy;  /* Hinted ME starts here */
1418          if (currMV->y < min_dy)  
1419                  currMV->y = min_dy;  static __inline void
1420    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            SearchData Data;
1429            MainSearchFunc *MainSearchPtr;
1430    
1431  /***************** This is predictor SET A: only median prediction ******************/          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            Data.Ref = OldData->Ref + 8 * ((block&1) + pParam->edged_width*(block>>1));
1438            Data.RefH = OldData->RefH + 8 * ((block&1) + pParam->edged_width*(block>>1));
1439            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          iMinSAD =          CheckCandidate = CheckCandidate8;
                 sad8(cur,  
                          get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  
                                                 iEdgedWidth), iEdgedWidth);  
         iMinSAD +=  
                 calc_delta_8(currMV->x - pmv[0].x, currMV->y - pmv[0].y,  
                                          (uint8_t) iFcode, iQuant);  
1445    
1446            if (block != 0)
1447                    *(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    
 // thresh1 is fixed to 256  
         if (iMinSAD < 256 / 4) {  
                 if (MotionFlags & PMV_QUICKSTOP8)  
                         goto EPZS8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
         }  
1452    
1453  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/          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            if (pMB->mode == MODE_INTER4V) {
1457                    int dummy;
1458                    CheckCandidate8(pMB->mvs[block].x, pMB->mvs[block].y, 0, &dummy, &Data); }
1459    
1460  // MV=(0,0) is often a good choice          if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
1461          CHECK_MV8_ZERO;                  else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1462                            else MainSearchPtr = DiamondSearch;
1463    
1464  // previous frame MV          (*MainSearchPtr)(Data.currentMV->x, Data.currentMV->y, &Data, 255);
         CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x, prevMB->mvs[iSubBlock].y);  
1465    
1466  // left neighbour, if allowed          if (MotionFlags & PMV_HALFPELREFINE8) HalfpelRefine(&Data);
         if (psad[1] != MV_MAX_ERROR) {  
                 if (!(MotionFlags & PMV_HALFPEL8)) {  
                         pmv[1].x = EVEN(pmv[1].x);  
                         pmv[1].y = EVEN(pmv[1].y);  
                 }  
                 CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);  
         }  
 // top neighbour, if allowed  
         if (psad[2] != MV_MAX_ERROR) {  
                 if (!(MotionFlags & PMV_HALFPEL8)) {  
                         pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
                 }  
                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
1467    
1468  // top right neighbour, if allowed          pMB->pmvs[block].x = Data.currentMV->x - Data.predMV.x;
1469                  if (psad[3] != MV_MAX_ERROR) {          pMB->pmvs[block].y = Data.currentMV->y - Data.predMV.y;
1470                          if (!(MotionFlags & PMV_HALFPEL8)) {          pMB->mvs[block] = *(Data.currentMV);
1471                                  pmv[3].x = EVEN(pmv[3].x);          pMB->sad8[block] =  4 * (*(Data.iMinSAD));
                                 pmv[3].y = EVEN(pmv[3].y);  
                         }  
                         CHECK_MV8_CANDIDATE(pmv[3].x, pmv[3].y);  
                 }  
1472          }          }
1473    
 /*  // this bias is zero anyway, at the moment!  
1474    
1475          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)  static void
1476                  iMinSAD -= MV8_00_BIAS;  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  */          const int32_t iEdgedWidth = pParam->edged_width;
1493    
1494  /* Terminate if MinSAD <= T_2          int i;
1495     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]          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 (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */          if (!(MotionFlags & PMV_HALFPEL16)) {
1518                  if (MotionFlags & PMV_QUICKSTOP8)                  Data.min_dx = EVEN(Data.min_dx);
1519                          goto EPZS8_Terminate_without_Refine;                  Data.max_dx = EVEN(Data.max_dx);
1520                  if (MotionFlags & PMV_EARLYSTOP8)                  Data.min_dy = EVEN(Data.min_dy);
1521                          goto EPZS8_Terminate_with_Refine;                  Data.max_dy = EVEN(Data.max_dy);
1522          }          }
1523    
1524  /************ (Diamond Search)  **************/          for(i = 0; i < 5; i++) iMinSAD[i] = MV_MAX_ERROR;
1525    
1526          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          if (pMB->dquant != NO_CHANGE) inter4v = 0;
1527    
1528          if (!(MotionFlags & PMV_HALFPELDIAMOND8))          if (inter4v)
1529                  iDiamondSize *= 2;                  CheckCandidate = CheckCandidate16;
1530            else CheckCandidate = CheckCandidate16no4v;
1531    
 /* default: use best prediction as starting point for one call of EPZS_MainSearch */  
1532    
1533  // there is no EPZS^2 for inter4v at the moment          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  //  if (MotionFlags & PMV_USESQUARES8)          CheckCandidate16(pMB->mvs[0].x, pMB->mvs[0].y, 0, &i, &Data);
 //      MainSearchPtr = Square8_MainSearch;  
 //  else  
1541    
1542          if (MotionFlags & PMV_ADVANCEDDIAMOND8)          if (pMB->mode == MODE_INTER4V)
1543                  MainSearchPtr = AdvDiamond8_MainSearch;                  for (i = 1; i < 4; i++) { // all four vectors will be used as four predictions for 16x16 search
1544          else                          pMB->mvs[i].x = EVEN(pMB->mvs[i].x);
1545                  MainSearchPtr = Diamond8_MainSearch;                          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          iSAD =          if (MotionFlags & PMV_USESQUARES16)
1551                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,                  MainSearchPtr = SquareSearch;
1552                                                    currMV->y, iMinSAD, &newMV, pmv, min_dx, max_dx,          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
1553                                                    min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,                  MainSearchPtr = AdvDiamondSearch;
1554                                                    iQuant, 0);                  else MainSearchPtr = DiamondSearch;
1555    
1556            (*MainSearchPtr)(currentMV->x, currentMV->y, &Data, 255);
1557    
1558          if (iSAD < iMinSAD) {          if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(&Data);
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
1559    
1560          if (MotionFlags & PMV_EXTSEARCH8) {          if (inter4v)
1561  /* extended mode: search (up to) two more times: orignal prediction and (0,0) */                  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 (!(MVequal(pmv[0], backupMV))) {          if (!(inter4v) ||
1565                          iSAD =                  (iMinSAD[0] < iMinSAD[1] + iMinSAD[2] + iMinSAD[3] + iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {
1566                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  // INTER MODE
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, pmv,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, 0);  
1567    
1568                          if (iSAD < iMinSAD) {                  pMB->mode = MODE_INTER;
1569                                  *currMV = newMV;                  pMB->mvs[0] = pMB->mvs[1]
1570                                  iMinSAD = iSAD;                          = pMB->mvs[2] = pMB->mvs[3] = currentMV[0];
                         }  
                 }  
1571    
1572                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
1573                          iSAD =                          pMB->sad8[2] = pMB->sad8[3] =  iMinSAD[0];
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, pmv, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, 0);  
1574    
1575                          if (iSAD < iMinSAD) {                  pMB->pmvs[0].x = currentMV[0].x - Data.predMV.x;
1576                                  *currMV = newMV;                  pMB->pmvs[0].y = currentMV[0].y - Data.predMV.y;
1577                                  iMinSAD = iSAD;          } 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    
1583  /***************        Choose best MV found     **************/  }
1584    
1585    EPZS8_Terminate_with_Refine:  void
1586          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step  MotionEstimationHinted( MBParam * const pParam,
1587                  iMinSAD =                                                  FRAMEINFO * const current,
1588                          Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,                                                  FRAMEINFO * const reference,
1589                                                          iMinSAD, pmv, min_dx, max_dx, min_dy, max_dy,                                                  const IMAGE * const pRefH,
1590                                                          iFcode, iQuant, iEdgedWidth);                                                  const IMAGE * const pRefV,
1591                                                    const IMAGE * const pRefHV)
1592    {
1593            MACROBLOCK *const pMBs = current->mbs;
1594            const IMAGE *const pCurrent = &current->image;
1595            const IMAGE *const pRef = &reference->image;
1596    
1597    EPZS8_Terminate_without_Refine:          uint32_t x, y;
1598    
1599          currPMV->x = currMV->x - pmv[0].x;          if (sadInit) (*sadInit) ();
         currPMV->y = currMV->y - pmv[0].y;  
         return iMinSAD;  
 }  
1600    
1601            for (y = 0; y < pParam->mb_height; y++) {
1602                    for (x = 0; x < pParam->mb_width; x++)  {
1603    
1604                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1605    
1606    //intra mode is copied from the first pass. At least for the time being
1607                            if  ((pMB->mode == MODE_INTRA) || (pMB->mode == MODE_NOT_CODED) ) continue;
1608    
1609                            if (!(current->global_flags & XVID_LUMIMASKING)) {
1610                                    pMB->dquant = NO_CHANGE;
1611                                    pMB->quant = current->quant; }
1612    
1613  /* ***********************************************************                          SearchPhinted(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
1614          bvop motion estimation                                                          y, current->motion_flags, pMB->quant,
1615  // TODO: need to incorporate prediction here (eg. sad += calc_delta_16)                                                          current->fcode, pParam, pMBs,
1616  ***************************************************************/                                                          current->global_flags & XVID_INTER4V, pMB);
1617    
1618                    }
1619            }
1620    }
1621    
1622  void  static __inline int
1623  MotionEstimationBVOP(MBParam * const pParam,  MEanalyzeMB (   const uint8_t * const pRef,
1624                                           FRAMEINFO * const frame,                                  const uint8_t * const pCur,
1625                                           // forward (past) reference                                  const int x,
1626                                           const MACROBLOCK * const f_mbs,                                  const int y,
1627                                           const IMAGE * const f_ref,                                  const uint32_t iFcode,
1628                                           const IMAGE * const f_refH,                                  const MBParam * const pParam,
1629                                           const IMAGE * const f_refV,                                  const MACROBLOCK * const pMBs,
1630                                           const IMAGE * const f_refHV,                                  MACROBLOCK * const pMB)
                                          // backward (future) reference  
                                          const MACROBLOCK * const b_mbs,  
                                          const IMAGE * const b_ref,  
                                          const IMAGE * const b_refH,  
                                          const IMAGE * const b_refV,  
                                          const IMAGE * const b_refHV)  
1631  {  {
         const uint32_t mb_width = pParam->mb_width;  
         const uint32_t mb_height = pParam->mb_height;  
         const int32_t edged_width = pParam->edged_width;  
1632    
1633          uint32_t i, j;          const int32_t iEdgedWidth = pParam->edged_width;
1634            int i, mask;
1635            VECTOR currentMV, pmv[3];
1636            int32_t iMinSAD = MV_MAX_ERROR;
1637            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          int32_t f_sad16;          DiamondSearch(currentMV.x, currentMV.y, &Data, i);
         int32_t b_sad16;  
         int32_t i_sad16;  
         int32_t d_sad16;  
         int32_t best_sad;  
1666    
1667          VECTOR pmv_dontcare;          pMB->mvs[0] = pMB->mvs[1]
1668                            = pMB->mvs[2] = pMB->mvs[3] = currentMV; // all, for future get_pmv()
1669    
1670          // note: i==horizontal, j==vertical          return iMinSAD;
         for (j = 0; j < mb_height; j++) {  
                 for (i = 0; i < mb_width; i++) {  
                         MACROBLOCK *mb = &frame->mbs[i + j * mb_width];  
                         const MACROBLOCK *f_mb = &f_mbs[i + j * mb_width];  
                         const MACROBLOCK *b_mb = &b_mbs[i + j * mb_width];  
   
                         if (b_mb->mode == MODE_INTER && b_mb->cbp == 0 &&  
                                 b_mb->mvs[0].x == 0 && b_mb->mvs[0].y == 0) {  
                                 mb->mode = MODE_NOT_CODED;  
                                 mb->mvs[0].x = 0;  
                                 mb->mvs[0].y = 0;  
                                 mb->b_mvs[0].x = 0;  
                                 mb->b_mvs[0].y = 0;  
                                 continue;  
1671                          }                          }
                 /* force F_SAD16  
                         f_sad16 = 100;  
                         b_sad16 = 65535;  
   
                         mb->mode = MODE_FORWARD;  
                         mb->mvs[0].x = 1;  
                         mb->mvs[0].y = 1;  
                         mb->b_mvs[0].x = 1;  
                         mb->b_mvs[0].y = 1;  
                         continue;  
                  ^^ force F_SAD16 */  
1672    
1673    #define INTRA_THRESH    1350
1674    #define INTER_THRESH    900
1675    
1676                          // forward search  int
1677                          f_sad16 =  MEanalysis(     const IMAGE * const pRef,
1678                                  SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,                          const IMAGE * const pCurrent,
1679                                                   &frame->image, i, j, frame->motion_flags,                          MBParam * const pParam,
1680                                                   frame->quant, frame->fcode, pParam,                          MACROBLOCK * const pMBs,
1681                                                   f_mbs,  f_mbs, /* todo */                          const uint32_t iFcode)
1682                                                   &mb->mvs[0], &pmv_dontcare);   // ignore pmv  {
1683            uint32_t x, y, intra = 0;
1684                          // backward search          int sSAD = 0;
                         b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 &frame->image, i, j, frame->motion_flags,  
                                                 frame->quant, frame->bcode, pParam,  
                                                 b_mbs, b_mbs,   /* todo */  
                                                 &mb->b_mvs[0], &pmv_dontcare);  // ignore pmv  
   
                         // interpolate search (simple, but effective)  
                         i_sad16 = 65535;  
1685    
1686                          /*          if (sadInit) (*sadInit) ();
                         x/y range somewhat buggy  
                         i_sad16 =  
                                 sad16bi_c(frame->image.y + i * 16 + j * 16 * edged_width,  
                                                   get_ref(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                   i, j, 16, mb->mvs[0].x, mb->mvs[0].y,  
                                                                   edged_width), get_ref(b_ref->y, b_refH->y,  
                                                                                                                 b_refV->y, b_refHV->y,  
                                                                                                                 i, j, 16,  
                                                                                                                 mb->b_mvs[0].x,  
                                                                                                                 mb->b_mvs[0].x,  
                                                                                                                 edged_width),  
                                                   edged_width);  
                         */  
1687    
1688                          // TODO: direct search          for (y = 0; y < pParam->mb_height-1; y++) {
1689                          // predictor + range of [-32,32]                  for (x = 0; x < pParam->mb_width; x++) {
1690                          d_sad16 = 65535;                          int sad, dev;
1691    
1692                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
1693    
1694                          if (f_sad16 < b_sad16) {                          sad = MEanalyzeMB(pRef->y, pCurrent->y, x, y,
1695                                  best_sad = f_sad16;                                                                  iFcode, pParam, pMBs, pMB);
                                 mb->mode = MODE_FORWARD;  
                         } else {  
                                 best_sad = b_sad16;  
                                 mb->mode = MODE_BACKWARD;  
                         }  
1696    
1697                          if (i_sad16 < best_sad) {                          if ( x != 0 && y != 0 && x != pParam->mb_width-1 ) { //no edge macroblocks, they just don't work
1698                                  best_sad = i_sad16;                                  if (sad > INTRA_THRESH) {
1699                                  mb->mode = MODE_INTERPOLATE;                                          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;
                         if (d_sad16 < best_sad) {  
                                 best_sad = d_sad16;  
                                 mb->mode = MODE_DIRECT;  
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    
1714  }  }

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

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