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

Legend:
Removed from v.234  
changed lines
  Added in v.530

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