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

Legend:
Removed from v.195  
changed lines
  Added in v.709

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