[cvs] / xvidcore / src / motion / motion_est.c Repository:
ViewVC logotype

Diff of /xvidcore/src/motion/motion_est.c

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

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

Legend:
Removed from v.1.44.2.19  
changed lines
  Added in v.1.51

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