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

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

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