[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.50, Thu Feb 6 09:25:37 2003 UTC revision 1.45, Fri Sep 6 16:59:47 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     *  Copyright(C) 2002 chenm001 <chenm001@163.com>
10   *   *
11   *      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
12   *      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 29 
29   *   *
30   *      You should have received a copy of the GNU General Public License   *      You should have received a copy of the GNU General Public License
31   *      along with this program; if not, write to the Free Software   *      along with this program; if not, write to the Free Software
32   *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
33   *   *
34   *************************************************************************/   *************************************************************************/
35    
36  #include <assert.h>  #include <assert.h>
37  #include <stdio.h>  #include <stdio.h>
38  #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>     // memcpy  
 #include <math.h>       // lrint  
39    
40  #include "../encoder.h"  #include "../encoder.h"
41  #include "../utils/mbfunctions.h"  #include "../utils/mbfunctions.h"
42  #include "../prediction/mbprediction.h"  #include "../prediction/mbprediction.h"
43  #include "../global.h"  #include "../global.h"
44  #include "../utils/timer.h"  #include "../utils/timer.h"
 #include "../image/interpolate8x8.h"  
 #include "motion_est.h"  
45  #include "motion.h"  #include "motion.h"
46  #include "sad.h"  #include "sad.h"
 #include "../utils/emms.h"  
47    
 #define INITIAL_SKIP_THRESH     (10)  
 #define FINAL_SKIP_THRESH       (50)  
 #define MAX_SAD00_FOR_SKIP      (20)  
 #define MAX_CHROMA_SAD_FOR_SKIP (22)  
48    
 #define CHECK_CANDIDATE(X,Y,D) { \  
 (*CheckCandidate)((const int)(X),(const int)(Y), (D), &iDirection, data ); }  
49    
50  static __inline uint32_t  static int32_t lambda_vec16[32] =       /* rounded values for lambda param for weight of motion bits as in modified H.26L */
51  d_mv_bits(int x, int y, const VECTOR pred, const uint32_t iFcode, const int qpel, const int rrv)  { 0, (int) (1.00235 + 0.5), (int) (1.15582 + 0.5), (int) (1.31976 + 0.5),
52  {                  (int) (1.49591 + 0.5), (int) (1.68601 + 0.5),
53          int xb, yb;          (int) (1.89187 + 0.5), (int) (2.11542 + 0.5), (int) (2.35878 + 0.5),
54          x = qpel ? x<<1 : x;                  (int) (2.62429 + 0.5), (int) (2.91455 + 0.5),
55          y = qpel ? y<<1 : y;          (int) (3.23253 + 0.5), (int) (3.58158 + 0.5), (int) (3.96555 + 0.5),
56          if (rrv) { x = RRV_MV_SCALEDOWN(x); y = RRV_MV_SCALEDOWN(y); }                  (int) (4.38887 + 0.5), (int) (4.85673 + 0.5),
57            (int) (5.37519 + 0.5), (int) (5.95144 + 0.5), (int) (6.59408 + 0.5),
58          x -= pred.x;                  (int) (7.31349 + 0.5), (int) (8.12242 + 0.5),
59          y -= pred.y;          (int) (9.03669 + 0.5), (int) (10.0763 + 0.5), (int) (11.2669 + 0.5),
60                    (int) (12.6426 + 0.5), (int) (14.2493 + 0.5),
61          if (x) {          (int) (16.1512 + 0.5), (int) (18.442 + 0.5), (int) (21.2656 + 0.5),
62                  x = ABS(x);                  (int) (24.8580 + 0.5), (int) (29.6436 + 0.5),
63                  x += (1 << (iFcode - 1)) - 1;          (int) (36.4949 + 0.5)
64                  x >>= (iFcode - 1);  };
65                  if (x > 32) x = 32;  
66                  xb = mvtab[x] + iFcode;  static int32_t *lambda_vec8 = lambda_vec16;     /* same table for INTER and INTER4V for now */
         } else xb = 1;  
   
         if (y) {  
                 y = ABS(y);  
                 y += (1 << (iFcode - 1)) - 1;  
                 y >>= (iFcode - 1);  
                 if (y > 32) y = 32;  
                 yb = mvtab[y] + iFcode;  
         } else yb = 1;  
         return xb + yb;  
 }  
   
 static int32_t ChromaSAD2(int fx, int fy, int bx, int by, const SearchData * const data)  
 {  
         int sad;  
         const uint32_t stride = data->iEdgedWidth/2;  
         uint8_t * f_refu = data->RefQ,  
                 * f_refv = data->RefQ + 8,  
                 * b_refu = data->RefQ + 16,  
                 * b_refv = data->RefQ + 24;  
   
         switch (((fx & 1) << 1) | (fy & 1))     {  
                 case 0:  
                         fx = fx / 2; fy = fy / 2;  
                         f_refu = (uint8_t*)data->RefCU + fy * stride + fx, stride;  
                         f_refv = (uint8_t*)data->RefCV + fy * stride + fx, stride;  
                         break;  
                 case 1:  
                         fx = fx / 2; fy = (fy - 1) / 2;  
                         interpolate8x8_halfpel_v(f_refu, data->RefCU + fy * stride + fx, stride, data->rounding);  
                         interpolate8x8_halfpel_v(f_refv, data->RefCV + fy * stride + fx, stride, data->rounding);  
                         break;  
                 case 2:  
                         fx = (fx - 1) / 2; fy = fy / 2;  
                         interpolate8x8_halfpel_h(f_refu, data->RefCU + fy * stride + fx, stride, data->rounding);  
                         interpolate8x8_halfpel_h(f_refv, data->RefCV + fy * stride + fx, stride, data->rounding);  
                         break;  
                 default:  
                         fx = (fx - 1) / 2; fy = (fy - 1) / 2;  
                         interpolate8x8_halfpel_hv(f_refu, data->RefCU + fy * stride + fx, stride, data->rounding);  
                         interpolate8x8_halfpel_hv(f_refv, data->RefCV + fy * stride + fx, stride, data->rounding);  
                         break;  
         }  
67    
         switch (((bx & 1) << 1) | (by & 1))     {  
                 case 0:  
                         bx = bx / 2; by = by / 2;  
                         b_refu = (uint8_t*)data->b_RefCU + by * stride + bx, stride;  
                         b_refv = (uint8_t*)data->b_RefCV + by * stride + bx, stride;  
                         break;  
                 case 1:  
                         bx = bx / 2; by = (by - 1) / 2;  
                         interpolate8x8_halfpel_v(b_refu, data->b_RefCU + by * stride + bx, stride, data->rounding);  
                         interpolate8x8_halfpel_v(b_refv, data->b_RefCV + by * stride + bx, stride, data->rounding);  
                         break;  
                 case 2:  
                         bx = (bx - 1) / 2; by = by / 2;  
                         interpolate8x8_halfpel_h(b_refu, data->b_RefCU + by * stride + bx, stride, data->rounding);  
                         interpolate8x8_halfpel_h(b_refv, data->b_RefCV + by * stride + bx, stride, data->rounding);  
                         break;  
                 default:  
                         bx = (bx - 1) / 2; by = (by - 1) / 2;  
                         interpolate8x8_halfpel_hv(b_refu, data->b_RefCU + by * stride + bx, stride, data->rounding);  
                         interpolate8x8_halfpel_hv(b_refv, data->b_RefCV + by * stride + bx, stride, data->rounding);  
                         break;  
         }  
68    
         sad = sad8bi(data->CurU, b_refu, f_refu, stride);  
         sad += sad8bi(data->CurV, b_refv, f_refv, stride);  
69    
70          return sad;  // mv.length table
71  }  static const uint32_t mvtab[33] = {
72            1, 2, 3, 4, 6, 7, 7, 7,
73            9, 9, 9, 10, 10, 10, 10, 10,
74            10, 10, 10, 10, 10, 10, 10, 10,
75            10, 11, 11, 11, 11, 11, 11, 12, 12
76    };
77    
78    
79  static int32_t  static __inline uint32_t
80  ChromaSAD(int dx, int dy, const SearchData * const data)  mv_bits(int32_t component,
81                    const uint32_t iFcode)
82  {  {
83          int sad;          if (component == 0)
84          const uint32_t stride = data->iEdgedWidth/2;                  return 1;
85    
86          if (dx == data->temp[5] && dy == data->temp[6]) return data->temp[7]; //it has been checked recently          if (component < 0)
87          data->temp[5] = dx; data->temp[6] = dy; // backup                  component = -component;
88    
89          switch (((dx & 1) << 1) | (dy & 1))     {          if (iFcode == 1) {
90                  case 0:                  if (component > 32)
91                          dx = dx / 2; dy = dy / 2;                          component = 32;
                         sad = sad8(data->CurU, data->RefCU + dy * stride + dx, stride);  
                         sad += sad8(data->CurV, data->RefCV + dy * stride + dx, stride);  
                         break;  
                 case 1:  
                         dx = dx / 2; dy = (dy - 1) / 2;  
                         sad = sad8bi(data->CurU, data->RefCU + dy * stride + dx, data->RefCU + (dy+1) * stride + dx, stride);  
                         sad += sad8bi(data->CurV, data->RefCV + dy * stride + dx, data->RefCV + (dy+1) * stride + dx, stride);  
                         break;  
                 case 2:  
                         dx = (dx - 1) / 2; dy = dy / 2;  
                         sad = sad8bi(data->CurU, data->RefCU + dy * stride + dx, data->RefCU + dy * stride + dx+1, stride);  
                         sad += sad8bi(data->CurV, data->RefCV + dy * stride + dx, data->RefCV + dy * stride + dx+1, stride);  
                         break;  
                 default:  
                         dx = (dx - 1) / 2; dy = (dy - 1) / 2;  
                         interpolate8x8_halfpel_hv(data->RefQ, data->RefCU + dy * stride + dx, stride, data->rounding);  
                         sad = sad8(data->CurU, data->RefQ, stride);  
92    
93                          interpolate8x8_halfpel_hv(data->RefQ, data->RefCV + dy * stride + dx, stride, data->rounding);                  return mvtab[component] + 1;
                         sad += sad8(data->CurV, data->RefQ, stride);  
                         break;  
94          }          }
95          data->temp[7] = sad; //backup, part 2  
96          return sad;          component += (1 << (iFcode - 1)) - 1;
97            component >>= (iFcode - 1);
98    
99            if (component > 32)
100                    component = 32;
101    
102            return mvtab[component] + 1 + iFcode - 1;
103  }  }
104    
105  static __inline const uint8_t *  
106  GetReferenceB(const int x, const int y, const uint32_t dir, const SearchData * const data)  static __inline uint32_t
107    calc_delta_16(const int32_t dx,
108                              const int32_t dy,
109                              const uint32_t iFcode,
110                              const uint32_t iQuant)
111  {  {
112  //      dir : 0 = forward, 1 = backward          return NEIGH_TEND_16X16 * lambda_vec16[iQuant] * (mv_bits(dx, iFcode) +
113          switch ( (dir << 2) | ((x&1)<<1) | (y&1) ) {                                                                                                            mv_bits(dy, iFcode));
                 case 0 : return data->Ref + x/2 + (y/2)*(data->iEdgedWidth);  
                 case 1 : return data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth);  
                 case 2 : return data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth);  
                 case 3 : return data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth);  
                 case 4 : return data->bRef + x/2 + (y/2)*(data->iEdgedWidth);  
                 case 5 : return data->bRefV + x/2 + ((y-1)/2)*(data->iEdgedWidth);  
                 case 6 : return data->bRefH + (x-1)/2 + (y/2)*(data->iEdgedWidth);  
                 default : return data->bRefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth);  
         }  
114  }  }
115    
116  // this is a simpler copy of GetReferenceB, but as it's __inline anyway, we can keep the two separate  static __inline uint32_t
117  static __inline const uint8_t *  calc_delta_8(const int32_t dx,
118  GetReference(const int x, const int y, const SearchData * const data)                           const int32_t dy,
119                             const uint32_t iFcode,
120                             const uint32_t iQuant)
121  {  {
122          switch ( ((x&1)<<1) | (y&1) ) {          return NEIGH_TEND_8X8 * lambda_vec8[iQuant] * (mv_bits(dx, iFcode) +
123                  case 0 : return data->Ref + x/2 + (y/2)*(data->iEdgedWidth);                                                                                                     mv_bits(dy, iFcode));
                 case 3 : return data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth);  
                 case 1 : return data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth);  
                 default : return data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth);      //case 2  
         }  
124  }  }
125    
126  static uint8_t *  bool
127  Interpolate8x8qpel(const int x, const int y, const uint32_t block, const uint32_t dir, const SearchData * const data)  MotionEstimation(MBParam * const pParam,
128                                     FRAMEINFO * const current,
129                                     FRAMEINFO * const reference,
130                                     const IMAGE * const pRefH,
131                                     const IMAGE * const pRefV,
132                                     const IMAGE * const pRefHV,
133                                     const uint32_t iLimit)
134  {  {
135  // create or find a qpel-precision reference picture; return pointer to it          const uint32_t iWcount = pParam->mb_width;
136          uint8_t * Reference = data->RefQ + 16*dir;          const uint32_t iHcount = pParam->mb_height;
137          const uint32_t iEdgedWidth = data->iEdgedWidth;          MACROBLOCK *const pMBs = current->mbs;
138          const uint32_t rounding = data->rounding;          MACROBLOCK *const prevMBs = reference->mbs;
139          const int halfpel_x = x/2;          const IMAGE *const pCurrent = &current->image;
140          const int halfpel_y = y/2;          const IMAGE *const pRef = &reference->image;
         const uint8_t *ref1, *ref2, *ref3, *ref4;  
141    
142          ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);          static const VECTOR zeroMV = { 0, 0 };
143          ref1 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;          VECTOR predMV;
         switch( ((x&1)<<1) + (y&1) ) {  
         case 0: // pure halfpel position  
                 return (uint8_t *) ref1;  
                 break;  
144    
145          case 1: // x halfpel, y qpel - top or bottom during qpel refinement          int32_t x, y;
146                  ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);          int32_t iIntra = 0;
147                  ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;          VECTOR pmv;
                 interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);  
                 break;  
148    
149          case 2: // x qpel, y halfpel - left or right during qpel refinement          if (sadInit)
150                  ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);                  (*sadInit) ();
                 ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;  
                 interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);  
                 break;  
151    
152          default: // x and y in qpel resolution - the "corners" (top left/right and          for (y = 0; y < iHcount; y++)   {
153                           // bottom left/right) during qpel refinement                  for (x = 0; x < iWcount; x ++)  {
                 ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);  
                 ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);  
                 ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);  
                 ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;  
                 ref3 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;  
                 ref4 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;  
                 interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);  
                 break;  
         }  
         return Reference;  
 }  
154    
155  static uint8_t *                          MACROBLOCK *const pMB = &pMBs[x + y * iWcount];
 Interpolate16x16qpel(const int x, const int y, const uint32_t dir, const SearchData * const data)  
 {  
 // create or find a qpel-precision reference picture; return pointer to it  
         uint8_t * Reference = data->RefQ + 16*dir;  
         const uint32_t iEdgedWidth = data->iEdgedWidth;  
         const uint32_t rounding = data->rounding;  
         const int halfpel_x = x/2;  
         const int halfpel_y = y/2;  
         const uint8_t *ref1, *ref2, *ref3, *ref4;  
156    
157          ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);                          if (pMB->mode == MODE_NOT_CODED)
158          switch( ((x&1)<<1) + (y&1) ) {                                  continue;
         case 3: // x and y in qpel resolution - the "corners" (top left/right and  
                          // bottom left/right) during qpel refinement  
                 ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);  
                 ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);  
                 ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);  
                 interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);  
                 interpolate8x8_avg4(Reference+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, rounding);  
                 interpolate8x8_avg4(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, rounding);  
                 interpolate8x8_avg4(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, rounding);  
                 break;  
159    
160          case 1: // x halfpel, y qpel - top or bottom during qpel refinement                          predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
                 ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);  
                 interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);  
                 interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);  
                 interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);  
                 interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);  
                 break;  
161    
162          case 2: // x qpel, y halfpel - left or right during qpel refinement                          pMB->sad16 =
163                  ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);                                  SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,
164                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);                                                   x, y, predMV.x, predMV.y, predMV.x, predMV.y,
165                  interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);                                                   current->motion_flags, current->quant,
166                  interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);                                                   current->fcode, pParam, pMBs, prevMBs, &pMB->mv16,
167                  interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);                                                   &pMB->pmvs[0]);
                 break;  
168    
169          case 0: // pure halfpel position                          if (0 < (pMB->sad16 - MV16_INTER_BIAS)) {
170                  return (uint8_t *) ref1;                                  int32_t deviation;
         }  
         return Reference;  
 }  
171    
172  /* CHECK_CANDIATE FUNCTIONS START */                                  deviation =
173                                            dev16(pCurrent->y + x * 16 + y * 16 * pParam->edged_width,
174                                                      pParam->edged_width);
175    
176  static void                                  if (deviation < (pMB->sad16 - MV16_INTER_BIAS)) {
177  CheckCandidate16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)                                          pMB->mode = MODE_INTRA;
178  {                                          pMB->mv16 = pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =
179          int xc, yc;                                                  pMB->mvs[3] = zeroMV;
180          const uint8_t * Reference;                                          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =
181          VECTOR * current;                                                  pMB->sad8[3] = 0;
         int32_t sad; uint32_t t;  
182    
183          if ( (x > data->max_dx) || (x < data->min_dx)                                          iIntra++;
184                  || (y > data->max_dy) || (y < data->min_dy) ) return;                                          if (iIntra >= iLimit)
185                                                    return 1;
186    
187          if (!data->qpel_precision) {                                          continue;
188                  Reference = GetReference(x, y, data);                                  }
                 current = data->currentMV;  
                 xc = x; yc = y;  
         } else { // x and y are in 1/4 precision  
                 Reference = Interpolate16x16qpel(x, y, 0, data);  
                 xc = x/2; yc = y/2; //for chroma sad  
                 current = data->currentQMV;  
189          }          }
190    
191          sad = sad16v(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);                          pmv = pMB->pmvs[0];
192          t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);                          if (current->global_flags & XVID_INTER4V)
193                                    if ((!(current->global_flags & XVID_LUMIMASKING) ||
194                                             pMB->dquant == NO_CHANGE)) {
195                                            int32_t sad8 = IMV16X16 * current->quant;
196    
197                                            if (sad8 < pMB->sad16) {
198                                                    sad8 += pMB->sad8[0] =
199                                                            SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,
200                                                                            pCurrent, 2 * x, 2 * y,
201                                                                            pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,
202                                                                            current->motion_flags,
203                                                                            current->quant, current->fcode, pParam,
204                                                                            pMBs, prevMBs, &pMB->mvs[0],
205                                                                            &pMB->pmvs[0]);
206                                            }
207                                            if (sad8 < pMB->sad16) {
208    
209                                                    predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 1);
210                                                    sad8 += pMB->sad8[1] =
211                                                            SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,
212                                                                            pCurrent, 2 * x + 1, 2 * y,
213                                                                            pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,
214                                                                            current->motion_flags,
215                                                                            current->quant, current->fcode, pParam,
216                                                                            pMBs, prevMBs, &pMB->mvs[1],
217                                                                            &pMB->pmvs[1]);
218                                            }
219                                            if (sad8 < pMB->sad16) {
220                                                    predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 2);
221                                                    sad8 += pMB->sad8[2] =
222                                                            SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,
223                                                                            pCurrent, 2 * x, 2 * y + 1,
224                                                                            pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,
225                                                                            current->motion_flags,
226                                                                            current->quant, current->fcode, pParam,
227                                                                            pMBs, prevMBs, &pMB->mvs[2],
228                                                                            &pMB->pmvs[2]);
229                                            }
230                                            if (sad8 < pMB->sad16) {
231                                                    predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 3);
232                                                    sad8 += pMB->sad8[3] =
233                                                            SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,
234                                                                            pCurrent, 2 * x + 1, 2 * y + 1,
235                                                                            pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,
236                                                                            current->motion_flags,
237                                                                            current->quant, current->fcode, pParam,
238                                                                            pMBs, prevMBs,
239                                                                            &pMB->mvs[3],
240                                                                            &pMB->pmvs[3]);
241                                            }
242    
243          sad += (data->lambda16 * t * sad)>>10;                                          /* decide: MODE_INTER or MODE_INTER4V
244          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;                                             mpeg4:   if (sad8 < pMB->sad16 - nb/2+1) use_inter4v
245                                             */
246    
247          if (data->chroma) sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],                                          if (sad8 < pMB->sad16) {
248                                                                                                          (yc >> 1) + roundtab_79[yc & 0x3], data);                                                  pMB->mode = MODE_INTER4V;
249                                                    pMB->sad8[0] *= 4;
250                                                    pMB->sad8[1] *= 4;
251                                                    pMB->sad8[2] *= 4;
252                                                    pMB->sad8[3] *= 4;
253                                                    continue;
254                                            }
255    
         if (sad < data->iMinSAD[0]) {  
                 data->iMinSAD[0] = sad;  
                 current[0].x = x; current[0].y = y;  
                 *dir = Direction;  
256          }          }
257    
258          if (data->temp[1] < data->iMinSAD[1]) {                          pMB->mode = MODE_INTER;
259                  data->iMinSAD[1] = data->temp[1]; current[1].x = x; current[1].y = y; }                          pMB->pmvs[0] = pmv;     /* pMB->pmvs[1] = pMB->pmvs[2] = pMB->pmvs[3]  are not needed for INTER */
260          if (data->temp[2] < data->iMinSAD[2]) {                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mv16;
261                  data->iMinSAD[2] = data->temp[2]; current[2].x = x; current[2].y = y; }                          pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] =
262          if (data->temp[3] < data->iMinSAD[3]) {                                  pMB->sad16;
263                  data->iMinSAD[3] = data->temp[3]; current[3].x = x; current[3].y = y; }                          }
264          if (data->temp[4] < data->iMinSAD[4]) {                          }
                 data->iMinSAD[4] = data->temp[4]; current[4].x = x; current[4].y = y; }  
265    
266            return 0;
267  }  }
268    
269  static void  
270  CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)  #define CHECK_MV16_ZERO {\
271      if ( (0 <= max_dx) && (0 >= min_dx) \
272        && (0 <= max_dy) && (0 >= min_dy) ) \
273      { \
274        iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \
275        iSAD += calc_delta_16(-center_x, -center_y, (uint8_t)iFcode, iQuant);\
276        if (iSAD < iMinSAD) \
277        {  iMinSAD=iSAD; currMV->x=0; currMV->y=0; }  }     \
278    }
279    
280    #define NOCHECK_MV16_CANDIDATE(X,Y) { \
281        iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \
282        iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\
283        if (iSAD < iMinSAD) \
284        {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \
285    }
286    
287    #define CHECK_MV16_CANDIDATE(X,Y) { \
288      if ( ((X) <= max_dx) && ((X) >= min_dx) \
289        && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
290      { \
291        iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \
292        iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\
293        if (iSAD < iMinSAD) \
294        {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \
295    }
296    
297    #define CHECK_MV16_CANDIDATE_DIR(X,Y,D) { \
298      if ( ((X) <= max_dx) && ((X) >= min_dx) \
299        && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
300      { \
301        iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \
302        iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\
303        if (iSAD < iMinSAD) \
304        {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \
305    }
306    
307    #define CHECK_MV16_CANDIDATE_FOUND(X,Y,D) { \
308      if ( ((X) <= max_dx) && ((X) >= min_dx) \
309        && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
310      { \
311        iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \
312        iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\
313        if (iSAD < iMinSAD) \
314        {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \
315    }
316    
317    
318    #define CHECK_MV8_ZERO {\
319      iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, 0, 0 , iEdgedWidth), iEdgedWidth); \
320      iSAD += calc_delta_8(-center_x, -center_y, (uint8_t)iFcode, iQuant);\
321      if (iSAD < iMinSAD) \
322      { iMinSAD=iSAD; currMV->x=0; currMV->y=0; } \
323    }
324    
325    #define NOCHECK_MV8_CANDIDATE(X,Y) \
326      { \
327        iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \
328        iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\
329        if (iSAD < iMinSAD) \
330        {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \
331    }
332    
333    #define CHECK_MV8_CANDIDATE(X,Y) { \
334      if ( ((X) <= max_dx) && ((X) >= min_dx) \
335        && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
336      { \
337        iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \
338        iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\
339        if (iSAD < iMinSAD) \
340        {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \
341    }
342    
343    #define CHECK_MV8_CANDIDATE_DIR(X,Y,D) { \
344      if ( ((X) <= max_dx) && ((X) >= min_dx) \
345        && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
346      { \
347        iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \
348        iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\
349        if (iSAD < iMinSAD) \
350        {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \
351    }
352    
353    #define CHECK_MV8_CANDIDATE_FOUND(X,Y,D) { \
354      if ( ((X) <= max_dx) && ((X) >= min_dx) \
355        && ((Y) <= max_dy) && ((Y) >= min_dy) ) \
356      { \
357        iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \
358        iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\
359        if (iSAD < iMinSAD) \
360        {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \
361    }
362    
363    /* too slow and not fully functional at the moment */
364    /*
365    int32_t ZeroSearch16(
366                                            const uint8_t * const pRef,
367                                            const uint8_t * const pRefH,
368                                            const uint8_t * const pRefV,
369                                            const uint8_t * const pRefHV,
370                                            const IMAGE * const pCur,
371                                            const int x, const int y,
372                                            const uint32_t MotionFlags,
373                                            const uint32_t iQuant,
374                                            const uint32_t iFcode,
375                                            MBParam * const pParam,
376                                            const MACROBLOCK * const pMBs,
377                                            const MACROBLOCK * const prevMBs,
378                                            VECTOR * const currMV,
379                                            VECTOR * const currPMV)
380  {  {
381          int32_t sad; uint32_t t;          const int32_t iEdgedWidth = pParam->edged_width;
382          const uint8_t * Reference;          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;
383            int32_t iSAD;
384            VECTOR pred;
385    
         if ( (x > data->max_dx) || (x < data->min_dx)  
                 || (y > data->max_dy) || (y < data->min_dy) ) return;  
386    
387          if (!data->qpel_precision) Reference = GetReference(x, y, data);          pred = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);
         else Reference = Interpolate16x16qpel(x, y, 0, data);  
388    
389          sad = sad8(data->Cur, Reference, data->iEdgedWidth);          iSAD = sad16( cur,
390          t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);                  get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth),
391                    iEdgedWidth, MV_MAX_ERROR);
392            if (iSAD <= iQuant * 96)
393                    iSAD -= MV16_00_BIAS;
394    
395          sad += (data->lambda8 * t * (sad+NEIGH_8X8_BIAS))>>10;          currMV->x = 0;
396            currMV->y = 0;
397            currPMV->x = -pred.x;
398            currPMV->y = -pred.y;
399    
400            return iSAD;
401    
         if (sad < *(data->iMinSAD)) {  
                 *(data->iMinSAD) = sad;  
                 data->currentMV->x = x; data->currentMV->y = y;  
                 *dir = Direction;  
         }  
402  }  }
403    */
404    
405    int32_t
406    Diamond16_MainSearch(const uint8_t * const pRef,
407                                             const uint8_t * const pRefH,
408                                             const uint8_t * const pRefV,
409                                             const uint8_t * const pRefHV,
410                                             const uint8_t * const cur,
411                                             const int x,
412                                             const int y,
413                                       const int start_x,
414                                       const int start_y,
415                                       int iMinSAD,
416                                       VECTOR * const currMV,
417                                       const int center_x,
418                                       const int center_y,
419                                             const int32_t min_dx,
420                                             const int32_t max_dx,
421                                             const int32_t min_dy,
422                                             const int32_t max_dy,
423                                             const int32_t iEdgedWidth,
424                                             const int32_t iDiamondSize,
425                                             const int32_t iFcode,
426                                             const int32_t iQuant,
427                                             int iFound)
428    {
429    /* Do a diamond search around given starting point, return SAD of best */
430    
431            int32_t iDirection = 0;
432            int32_t iDirectionBackup;
433            int32_t iSAD;
434            VECTOR backupMV;
435    
436            backupMV.x = start_x;
437            backupMV.y = start_y;
438    
439    /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */
440    
441            CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);
442            CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);
443            CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);
444            CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);
445    
446  static void          if (iDirection) {
447  CheckCandidate32(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)                  while (!iFound) {
448  {                          iFound = 1;
449          uint32_t t;                          backupMV = *currMV;
450          const uint8_t * Reference;                          iDirectionBackup = iDirection;
451    
452                            if (iDirectionBackup != 2)
453                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
454                                                                                       backupMV.y, 1);
455                            if (iDirectionBackup != 1)
456                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
457                                                                                       backupMV.y, 2);
458                            if (iDirectionBackup != 4)
459                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x,
460                                                                                       backupMV.y - iDiamondSize, 3);
461                            if (iDirectionBackup != 3)
462                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x,
463                                                                                       backupMV.y + iDiamondSize, 4);
464                    }
465            } else {
466                    currMV->x = start_x;
467                    currMV->y = start_y;
468            }
469            return iMinSAD;
470    }
471    
472          if ( (!(x&1) && x !=0) || (!(y&1) && y !=0) || //non-zero integer value  int32_t
473                  (x > data->max_dx) || (x < data->min_dx)  Square16_MainSearch(const uint8_t * const pRef,
474                  || (y > data->max_dy) || (y < data->min_dy) ) return;                                          const uint8_t * const pRefH,
475                                            const uint8_t * const pRefV,
476                                            const uint8_t * const pRefHV,
477                                            const uint8_t * const cur,
478                                            const int x,
479                                            const int y,
480                                       const int start_x,
481                                       const int start_y,
482                                       int iMinSAD,
483                                       VECTOR * const currMV,
484                                       const int center_x,
485                                       const int center_y,
486                                            const int32_t min_dx,
487                                            const int32_t max_dx,
488                                            const int32_t min_dy,
489                                            const int32_t max_dy,
490                                            const int32_t iEdgedWidth,
491                                            const int32_t iDiamondSize,
492                                            const int32_t iFcode,
493                                            const int32_t iQuant,
494                                            int iFound)
495    {
496    /* Do a square search around given starting point, return SAD of best */
497    
498            int32_t iDirection = 0;
499            int32_t iSAD;
500            VECTOR backupMV;
501    
502            backupMV.x = start_x;
503            backupMV.y = start_y;
504    
505    /* It's one search with full square pattern, and new parts for all following diamonds */
506    
507    /*   new direction are extra, so 1-4 is normal diamond
508          537
509          1*2
510          648
511    */
512    
513          Reference = GetReference(x, y, data);          CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);
514          t = d_mv_bits(x, y, data->predMV, data->iFcode, 0, 1);          CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);
515            CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);
516            CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);
517    
518            CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,
519                                                             backupMV.y - iDiamondSize, 5);
520            CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,
521                                                             backupMV.y + iDiamondSize, 6);
522            CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,
523                                                             backupMV.y - iDiamondSize, 7);
524            CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,
525                                                             backupMV.y + iDiamondSize, 8);
526    
         data->temp[0] = sad32v_c(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);  
527    
528          data->temp[0] += (data->lambda16 * t * data->temp[0]) >> 10;          if (iDirection) {
529          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;                  while (!iFound) {
530                            iFound = 1;
531                            backupMV = *currMV;
532    
533          if (data->temp[0] < data->iMinSAD[0]) {                          switch (iDirection) {
534                  data->iMinSAD[0] = data->temp[0];                          case 1:
535                  data->currentMV[0].x = x; data->currentMV[0].y = y;                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
536                  *dir = Direction; }                                                                                     backupMV.y, 1);
537                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
538                                                                                     backupMV.y - iDiamondSize, 5);
539                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
540                                                                                     backupMV.y - iDiamondSize, 7);
541                                    break;
542                            case 2:
543                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
544                                                                                     2);
545                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
546                                                                                     backupMV.y + iDiamondSize, 6);
547                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
548                                                                                     backupMV.y + iDiamondSize, 8);
549                                    break;
550    
551          if (data->temp[1] < data->iMinSAD[1]) {                          case 3:
552                  data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
553          if (data->temp[2] < data->iMinSAD[2]) {                                                                                   4);
554                  data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
555          if (data->temp[3] < data->iMinSAD[3]) {                                                                                   backupMV.y - iDiamondSize, 7);
556                  data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
557          if (data->temp[4] < data->iMinSAD[4]) {                                                                                   backupMV.y + iDiamondSize, 8);
558                  data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }                                  break;
 }  
559    
560  static void                          case 4:
561  CheckCandidate16no4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
562  {                                                                                   3);
563          int32_t sad, xc, yc;                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
564          const uint8_t * Reference;                                                                                   backupMV.y - iDiamondSize, 5);
565          uint32_t t;                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
566          VECTOR * current;                                                                                   backupMV.y + iDiamondSize, 6);
567                                    break;
568    
569                            case 5:
570                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,
571                                                                                     1);
572                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
573                                                                                     3);
574                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
575                                                                                     backupMV.y - iDiamondSize, 5);
576                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
577                                                                                     backupMV.y + iDiamondSize, 6);
578                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
579                                                                                     backupMV.y - iDiamondSize, 7);
580                                    break;
581    
582                            case 6:
583                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
584                                                                                     2);
585                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
586                                                                                     3);
587    
588                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
589                                                                                     backupMV.y - iDiamondSize, 5);
590                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
591                                                                                     backupMV.y + iDiamondSize, 6);
592                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
593                                                                                     backupMV.y + iDiamondSize, 8);
594    
595          if ( (x > data->max_dx) | ( x < data->min_dx)                                  break;
                 | (y > data->max_dy) | (y < data->min_dy) ) return;  
596    
597          if (data->rrv && (!(x&1) && x !=0) | (!(y&1) && y !=0) ) return; //non-zero even value                          case 7:
598                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
599                                                                                       backupMV.y, 1);
600                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
601                                                                                     4);
602                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
603                                                                                     backupMV.y - iDiamondSize, 5);
604                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
605                                                                                     backupMV.y - iDiamondSize, 7);
606                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
607                                                                                     backupMV.y + iDiamondSize, 8);
608                                    break;
609    
610          if (data->qpel_precision) { // x and y are in 1/4 precision                          case 8:
611                  Reference = Interpolate16x16qpel(x, y, 0, data);                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
612                  current = data->currentQMV;                                                                                   2);
613                  xc = x/2; yc = y/2;                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
614                                                                                     4);
615                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
616                                                                                     backupMV.y + iDiamondSize, 6);
617                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
618                                                                                     backupMV.y - iDiamondSize, 7);
619                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
620                                                                                     backupMV.y + iDiamondSize, 8);
621                                    break;
622                            default:
623                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,
624                                                                                     1);
625                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
626                                                                                     2);
627                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
628                                                                                     3);
629                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
630                                                                                     4);
631    
632                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
633                                                                                     backupMV.y - iDiamondSize, 5);
634                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
635                                                                                     backupMV.y + iDiamondSize, 6);
636                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
637                                                                                     backupMV.y - iDiamondSize, 7);
638                                    CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
639                                                                                     backupMV.y + iDiamondSize, 8);
640                                    break;
641                            }
642                    }
643          } else {          } else {
644                  Reference = GetReference(x, y, data);                  currMV->x = start_x;
645                  current = data->currentMV;                  currMV->y = start_y;
646                  xc = x; yc = y;          }
647            return iMinSAD;
648          }          }
         t = d_mv_bits(x, y, data->predMV, data->iFcode,  
                                         data->qpel^data->qpel_precision, data->rrv);  
   
         sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);  
         sad += (data->lambda16 * t * sad)>>10;  
649    
         if (data->chroma) sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],  
                                                                                 (yc >> 1) + roundtab_79[yc & 0x3], data);  
650    
651    int32_t
652    Full16_MainSearch(const uint8_t * const pRef,
653                                      const uint8_t * const pRefH,
654                                      const uint8_t * const pRefV,
655                                      const uint8_t * const pRefHV,
656                                      const uint8_t * const cur,
657                                      const int x,
658                                      const int y,
659                                       const int start_x,
660                                       const int start_y,
661                                       int iMinSAD,
662                                       VECTOR * const currMV,
663                                       const int center_x,
664                                       const int center_y,
665                                      const int32_t min_dx,
666                                      const int32_t max_dx,
667                                      const int32_t min_dy,
668                                      const int32_t max_dy,
669                                      const int32_t iEdgedWidth,
670                                      const int32_t iDiamondSize,
671                                      const int32_t iFcode,
672                                      const int32_t iQuant,
673                                      int iFound)
674    {
675            int32_t iSAD;
676            int32_t dx, dy;
677            VECTOR backupMV;
678    
679            backupMV.x = start_x;
680            backupMV.y = start_y;
681    
682            for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)
683                    for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)
684                            NOCHECK_MV16_CANDIDATE(dx, dy);
685    
686          if (sad < *(data->iMinSAD)) {          return iMinSAD;
                 *(data->iMinSAD) = sad;  
                 current->x = x; current->y = y;  
                 *dir = Direction;  
         }  
687  }  }
688    
689  static void  int32_t
690  CheckCandidate32I(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)  AdvDiamond16_MainSearch(const uint8_t * const pRef,
691                                                    const uint8_t * const pRefH,
692                                                    const uint8_t * const pRefV,
693                                                    const uint8_t * const pRefHV,
694                                                    const uint8_t * const cur,
695                                                    const int x,
696                                                    const int y,
697                                               int start_x,
698                                               int start_y,
699                                               int iMinSAD,
700                                               VECTOR * const currMV,
701                                               const int center_x,
702                                               const int center_y,
703                                                    const int32_t min_dx,
704                                                    const int32_t max_dx,
705                                                    const int32_t min_dy,
706                                                    const int32_t max_dy,
707                                                    const int32_t iEdgedWidth,
708                                                    const int32_t iDiamondSize,
709                                                    const int32_t iFcode,
710                                                    const int32_t iQuant,
711                                                    int iDirection)
712  {  {
 // maximum speed - for P/B/I decision  
         int32_t sad;  
713    
714          if ( (x > data->max_dx) || (x < data->min_dx)          int32_t iSAD;
                 || (y > data->max_dy) || (y < data->min_dy) ) return;  
715    
716          sad = sad32v_c(data->Cur, data->Ref + x/2 + (y/2)*(data->iEdgedWidth),  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
                                                         data->iEdgedWidth, data->temp+1);  
717    
718          if (sad < *(data->iMinSAD)) {          if (iDirection) {
719                  *(data->iMinSAD) = sad;                  CHECK_MV16_CANDIDATE(start_x - iDiamondSize, start_y);
720                  data->currentMV[0].x = x; data->currentMV[0].y = y;                  CHECK_MV16_CANDIDATE(start_x + iDiamondSize, start_y);
721                  *dir = Direction;                  CHECK_MV16_CANDIDATE(start_x, start_y - iDiamondSize);
722          }                  CHECK_MV16_CANDIDATE(start_x, start_y + iDiamondSize);
723          if (data->temp[1] < data->iMinSAD[1]) {          } else {
724                  data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }                  int bDirection = 1 + 2 + 4 + 8;
         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; }  
725    
726  }                  do {
727                            iDirection = 0;
728                            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)
729                                    CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);
730    
731  static void                          if (bDirection & 2)
732  CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)                                  CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);
 {  
         int32_t sad, xb, yb, xcf, ycf, xcb, ycb;  
         uint32_t t;  
         const uint8_t *ReferenceF, *ReferenceB;  
         VECTOR *current;  
733    
734          if ( (xf > data->max_dx) | (xf < data->min_dx)                          if (bDirection & 4)
735                  | (yf > data->max_dy) | (yf < data->min_dy) ) return;                                  CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);
736    
737          if (!data->qpel_precision) {                          if (bDirection & 8)
738                  ReferenceF = GetReference(xf, yf, data);                                  CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);
                 xb = data->currentMV[1].x; yb = data->currentMV[1].y;  
                 ReferenceB = GetReferenceB(xb, yb, 1, data);  
                 current = data->currentMV;  
                 xcf = xf; ycf = yf;  
                 xcb = xb; ycb = yb;  
         } else {  
                 ReferenceF = Interpolate16x16qpel(xf, yf, 0, data);  
                 xb = data->currentQMV[1].x; yb = data->currentQMV[1].y;  
                 current = data->currentQMV;  
                 ReferenceB = Interpolate16x16qpel(xb, yb, 1, data);  
                 xcf = xf/2; ycf = yf/2;  
                 xcb = xb/2; ycb = yb/2;  
         }  
739    
740          t = d_mv_bits(xf, yf, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0)                          /* now we're doing diagonal checks near our candidate */
                  + d_mv_bits(xb, yb, data->bpredMV, data->iFcode, data->qpel^data->qpel_precision, 0);  
741    
742          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);                          if (iDirection)         //checking if anything found
743          sad += (data->lambda16 * t * sad)>>10;                          {
744                                    bDirection = iDirection;
745                                    iDirection = 0;
746                                    start_x = currMV->x;
747                                    start_y = currMV->y;
748                                    if (bDirection & 3)     //our candidate is left or right
749                                    {
750                                            CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);
751                                            CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);
752                                    } else                  // what remains here is up or down
753                                    {
754                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);
755                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);
756                                    }
757    
758          if (data->chroma) sad += ChromaSAD2((xcf >> 1) + roundtab_79[xcf & 0x3],                                  if (iDirection) {
759                                                                                  (ycf >> 1) + roundtab_79[ycf & 0x3],                                          bDirection += iDirection;
760                                                                                  (xcb >> 1) + roundtab_79[xcb & 0x3],                                          start_x = currMV->x;
761                                                                                  (ycb >> 1) + roundtab_79[ycb & 0x3], data);                                          start_y = currMV->y;
762                                    }
763                            } else                          //about to quit, eh? not so fast....
764                            {
765                                    switch (bDirection) {
766                                    case 2:
767                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
768                                                                                             start_y - iDiamondSize, 2 + 4);
769                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
770                                                                                             start_y + iDiamondSize, 2 + 8);
771                                            break;
772                                    case 1:
773    
774          if (sad < *(data->iMinSAD)) {                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
775                  *(data->iMinSAD) = sad;                                                                                           start_y - iDiamondSize, 1 + 4);
776                  current->x = xf; current->y = yf;                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
777                  *dir = Direction;                                                                                           start_y + iDiamondSize, 1 + 8);
778                                            break;
779                                    case 2 + 4:
780                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
781                                                                                             start_y - iDiamondSize, 1 + 4);
782                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
783                                                                                             start_y - iDiamondSize, 2 + 4);
784                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
785                                                                                             start_y + iDiamondSize, 2 + 8);
786                                            break;
787                                    case 4:
788                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
789                                                                                             start_y - iDiamondSize, 2 + 4);
790                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
791                                                                                             start_y - iDiamondSize, 1 + 4);
792                                            break;
793                                    case 8:
794                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
795                                                                                             start_y + iDiamondSize, 2 + 8);
796                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
797                                                                                             start_y + iDiamondSize, 1 + 8);
798                                            break;
799                                    case 1 + 4:
800                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
801                                                                                             start_y + iDiamondSize, 1 + 8);
802                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
803                                                                                             start_y - iDiamondSize, 1 + 4);
804                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
805                                                                                             start_y - iDiamondSize, 2 + 4);
806                                            break;
807                                    case 2 + 8:
808                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
809                                                                                             start_y - iDiamondSize, 1 + 4);
810                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
811                                                                                             start_y + iDiamondSize, 1 + 8);
812                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
813                                                                                             start_y + iDiamondSize, 2 + 8);
814                                            break;
815                                    case 1 + 8:
816                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
817                                                                                             start_y - iDiamondSize, 2 + 4);
818                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
819                                                                                             start_y + iDiamondSize, 2 + 8);
820                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
821                                                                                             start_y + iDiamondSize, 1 + 8);
822                                            break;
823                                    default:                //1+2+4+8 == we didn't find anything at all
824                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
825                                                                                             start_y - iDiamondSize, 1 + 4);
826                                            CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,
827                                                                                             start_y + iDiamondSize, 1 + 8);
828                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
829                                                                                             start_y - iDiamondSize, 2 + 4);
830                                            CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,
831                                                                                             start_y + iDiamondSize, 2 + 8);
832                                            break;
833                                    }
834                                    if (!iDirection)
835                                            break;          //ok, the end. really
836                                    else {
837                                            bDirection = iDirection;
838                                            start_x = currMV->x;
839                                            start_y = currMV->y;
840                                    }
841          }          }
842  }  }
843                    while (1);                              //forever
844            }
845            return iMinSAD;
846    }
847    
848  static void  #define CHECK_MV16_F_INTERPOL(X,Y) { \
849  CheckCandidateDirect(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)    if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \
850  {      && ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \
851          int32_t sad = 0, xcf = 0, ycf = 0, xcb = 0, ycb = 0;    { \
852          uint32_t k;      iSAD = sad16bi( cur, \
853          const uint8_t *ReferenceF;                          get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \
854          const uint8_t *ReferenceB;                          get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, b_currMV->x, b_currMV->y, iEdgedWidth),   \
855          VECTOR mvs, b_mvs;                          iEdgedWidth); \
856        iSAD += calc_delta_16((X) - f_center_x, (Y) - f_center_y, (uint8_t)f_iFcode, iQuant);\
857        iSAD += calc_delta_16(b_currMV->x - b_center_x, b_currMV->y - b_center_y, (uint8_t)b_iFcode, iQuant);\
858        if (iSAD < iMinSAD) \
859        {  iMinSAD=iSAD; f_currMV->x=(X); f_currMV->y=(Y); } } \
860    }
861    
862    #define CHECK_MV16_F_INTERPOL_FOUND(X,Y) { \
863      if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \
864        && ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \
865      { \
866        iSAD = sad16bi( cur, \
867                            get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \
868                            get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, b_currMV->x, b_currMV->y, iEdgedWidth),   \
869                            iEdgedWidth); \
870        iSAD += calc_delta_16((X) - f_center_x, (Y) - f_center_y, (uint8_t)f_iFcode, iQuant);\
871        iSAD += calc_delta_16(b_currMV->x - b_center_x, b_currMV->y - b_center_y, (uint8_t)b_iFcode, iQuant);\
872        if (iSAD < iMinSAD) \
873        {  iMinSAD=iSAD; f_currMV->x=(X); f_currMV->y=(Y); iFound=0;} } \
874    }
875    
876    #define CHECK_MV16_B_INTERPOL(X,Y) { \
877      if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \
878        && ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \
879      { \
880        iSAD = sad16bi( cur, \
881                            get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth),   \
882                            get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \
883                            iEdgedWidth); \
884        iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\
885        iSAD += calc_delta_16((X) - b_center_x, (Y) - b_center_y, (uint8_t)b_iFcode, iQuant);\
886        if (iSAD < iMinSAD) \
887        {  iMinSAD=iSAD; b_currMV->x=(X); b_currMV->y=(Y); } } \
888    }
889    
890    #define CHECK_MV16_B_INTERPOL_FOUND(X,Y) { \
891      if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \
892        && ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \
893      { \
894        iSAD = sad16bi( cur, \
895                            get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth),   \
896                            get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \
897                            iEdgedWidth); \
898        iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\
899        iSAD += calc_delta_16((X) - b_center_x, (Y) - b_center_y, (uint8_t)b_iFcode, iQuant);\
900        if (iSAD < iMinSAD) \
901        {  iMinSAD=iSAD; b_currMV->x=(X); b_currMV->y=(Y); iFound=0;} } \
902    }
903    
904    int32_t
905    Diamond16_InterpolMainSearch(
906                                            const uint8_t * const f_pRef,
907                                             const uint8_t * const f_pRefH,
908                                             const uint8_t * const f_pRefV,
909                                             const uint8_t * const f_pRefHV,
910    
911                                             const uint8_t * const cur,
912    
913                                            const uint8_t * const b_pRef,
914                                             const uint8_t * const b_pRefH,
915                                             const uint8_t * const b_pRefV,
916                                             const uint8_t * const b_pRefHV,
917    
918          if (( x > 31) | ( x < -32) | ( y > 31) | (y < -32)) return;                                           const int x,
919                                             const int y,
920    
921          for (k = 0; k < 4; k++) {                                     const int f_start_x,
922                  mvs.x = data->directmvF[k].x + x;                                     const int f_start_y,
923                  b_mvs.x = ((x == 0) ?                                     const int b_start_x,
924                          data->directmvB[k].x                                     const int b_start_y,
925                          : mvs.x - data->referencemv[k].x);  
926                                       int iMinSAD,
927                  mvs.y = data->directmvF[k].y + y;                                     VECTOR * const f_currMV,
928                  b_mvs.y = ((y == 0) ?                                     VECTOR * const b_currMV,
929                          data->directmvB[k].y  
930                          : mvs.y - data->referencemv[k].y);                                     const int f_center_x,
931                                       const int f_center_y,
932                  if ( (mvs.x > data->max_dx) | (mvs.x < data->min_dx)                                     const int b_center_x,
933                          | (mvs.y > data->max_dy) | (mvs.y < data->min_dy)                                     const int b_center_y,
934                          | (b_mvs.x > data->max_dx) | (b_mvs.x < data->min_dx)  
935                          | (b_mvs.y > data->max_dy) | (b_mvs.y < data->min_dy) ) return;                                      const int32_t f_min_dx,
936                                            const int32_t f_max_dx,
937                  if (data->qpel) {                                          const int32_t f_min_dy,
938                          xcf += mvs.x/2; ycf += mvs.y/2;                                          const int32_t f_max_dy,
939                          xcb += b_mvs.x/2; ycb += b_mvs.y/2;  
940                  } else {                                      const int32_t b_min_dx,
941                          xcf += mvs.x; ycf += mvs.y;                                          const int32_t b_max_dx,
942                          xcb += b_mvs.x; ycb += b_mvs.y;                                          const int32_t b_min_dy,
943                          mvs.x *= 2; mvs.y *= 2; //we move to qpel precision anyway                                          const int32_t b_max_dy,
944                          b_mvs.x *= 2; b_mvs.y *= 2;  
945                  }                                          const int32_t iEdgedWidth,
946                                            const int32_t iDiamondSize,
947    
948                                            const int32_t f_iFcode,
949                                            const int32_t b_iFcode,
950    
951                                            const int32_t iQuant,
952                                            int iFound)
953    {
954    /* Do a diamond search around given starting point, return SAD of best */
955    
956            int32_t iSAD;
957    
958            VECTOR f_backupMV;
959            VECTOR b_backupMV;
960    
961            f_currMV->x = f_start_x;
962            f_currMV->y = f_start_y;
963            b_currMV->x = b_start_x;
964            b_currMV->y = b_start_y;
965    
966            do
967            {
968                    iFound = 1;
969    
970                    f_backupMV = *f_currMV;
971    
972                    CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x - iDiamondSize, f_backupMV.y);
973                    CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x + iDiamondSize, f_backupMV.y);
974                    CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y - iDiamondSize);
975                    CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y + iDiamondSize);
976    
977                    b_backupMV = *b_currMV;
978    
979                    CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x - iDiamondSize, b_backupMV.y);
980                    CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x + iDiamondSize, b_backupMV.y);
981                    CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y - iDiamondSize);
982                    CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y + iDiamondSize);
983    
984            } while (!iFound);
985    
986            return iMinSAD;
987    }
988    
989    /* Sorry, these MACROS really got too large... I'll turn them into function soon! */
990    
991    #define CHECK_MV16_DIRECT_FOUND(X,Y) \
992            if ( (X)>=(-32) && (X)<=(31) && ((Y)>=-32) && ((Y)<=31) ) \
993            { int k;\
994            VECTOR mvs,b_mvs;       \
995            iSAD = 0;\
996            for (k = 0; k < 4; k++) {       \
997                                            mvs.x = (int32_t) ((TRB * directmv[k].x) / TRD + (X));          \
998                        b_mvs.x = (int32_t) (((X) == 0)                                                     \
999                                                                                    ? ((TRB - TRD) * directmv[k].x) / TRD   \
1000                                                : mvs.x - directmv[k].x);                           \
1001                                                                                                                                                                    \
1002                        mvs.y = (int32_t) ((TRB * directmv[k].y) / TRD + (Y));              \
1003                            b_mvs.y = (int32_t) (((Y) == 0)                                                         \
1004                                                                                    ? ((TRB - TRD) * directmv[k].y) / TRD   \
1005                                                : mvs.y - directmv[k].y);                           \
1006                                                                                                                                                                    \
1007      if ( (mvs.x <= max_dx) && (mvs.x >= min_dx) \
1008        && (mvs.y <= max_dy) && (mvs.y >= min_dy)  \
1009            && (b_mvs.x <= max_dx) && (b_mvs.x >= min_dx)  \
1010        && (b_mvs.y <= max_dy) && (b_mvs.y >= min_dy) ) { \
1011                iSAD += sad8bi( cur + 8*(k&1) + 8*(k>>1)*iEdgedWidth,                                                                                                       \
1012                            get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \
1013                                            mvs.x, mvs.y, iEdgedWidth),                                                             \
1014                            get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \
1015                                            b_mvs.x, b_mvs.y, iEdgedWidth),                                                         \
1016                            iEdgedWidth); \
1017                    }       \
1018            else    \
1019                    iSAD = 65535;   \
1020            } \
1021            iSAD += calc_delta_16((X),(Y), 1, iQuant);\
1022            if (iSAD < iMinSAD) \
1023                {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iFound=0; } \
1024    }
1025    
1026    
1027    
1028    int32_t
1029    Diamond16_DirectMainSearch(
1030                                            const uint8_t * const f_pRef,
1031                                            const uint8_t * const f_pRefH,
1032                                            const uint8_t * const f_pRefV,
1033                                            const uint8_t * const f_pRefHV,
1034    
1035                                            const uint8_t * const cur,
1036    
1037                                            const uint8_t * const b_pRef,
1038                                            const uint8_t * const b_pRefH,
1039                                            const uint8_t * const b_pRefV,
1040                                            const uint8_t * const b_pRefHV,
1041    
1042                  ReferenceF = Interpolate8x8qpel(mvs.x, mvs.y, k, 0, data);                                          const int x,
1043                  ReferenceB = Interpolate8x8qpel(b_mvs.x, b_mvs.y, k, 1, data);                                          const int y,
1044    
1045                  sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),                                          const int TRB,
1046                                                  ReferenceF, ReferenceB, data->iEdgedWidth);                                          const int TRD,
                 if (sad > *(data->iMinSAD)) return;  
         }  
1047    
1048          sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;                                      const int start_x,
1049                                        const int start_y,
1050    
1051          if (data->chroma) sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],                                      int iMinSAD,
1052                                                                                  (ycf >> 3) + roundtab_76[ycf & 0xf],                                      VECTOR * const currMV,
1053                                                                                  (xcb >> 3) + roundtab_76[xcb & 0xf],                                          const VECTOR * const directmv,
                                                                                 (ycb >> 3) + roundtab_76[ycb & 0xf], data);  
1054    
1055          if (sad < *(data->iMinSAD)) {                                      const int32_t min_dx,
1056                  *(data->iMinSAD) = sad;                                          const int32_t max_dx,
1057                  data->currentMV->x = x; data->currentMV->y = y;                                          const int32_t min_dy,
1058                  *dir = Direction;                                          const int32_t max_dy,
1059          }  
1060  }                                          const int32_t iEdgedWidth,
1061                                            const int32_t iDiamondSize,
1062    
1063  static void                                          const int32_t iQuant,
1064  CheckCandidateDirectno4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)                                          int iFound)
1065  {  {
1066          int32_t sad, xcf, ycf, xcb, ycb;  /* Do a diamond search around given starting point, return SAD of best */
         const uint8_t *ReferenceF;  
         const uint8_t *ReferenceB;  
         VECTOR mvs, b_mvs;  
1067    
1068          if (( x > 31) | ( x < -32) | ( y > 31) | (y < -32)) return;          int32_t iSAD;
1069    
1070          mvs.x = data->directmvF[0].x + x;          VECTOR backupMV;
         b_mvs.x = ((x == 0) ?  
                 data->directmvB[0].x  
                 : mvs.x - data->referencemv[0].x);  
1071    
1072          mvs.y = data->directmvF[0].y + y;          currMV->x = start_x;
1073          b_mvs.y = ((y == 0) ?          currMV->y = start_y;
                 data->directmvB[0].y  
                 : mvs.y - data->referencemv[0].y);  
1074    
1075          if ( (mvs.x > data->max_dx) | (mvs.x < data->min_dx)  /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */
                 | (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;  
1076    
1077          if (data->qpel) {          do
1078                  xcf = 4*(mvs.x/2); ycf = 4*(mvs.y/2);          {
1079                  xcb = 4*(b_mvs.x/2); ycb = 4*(b_mvs.y/2);                  iFound = 1;
                 ReferenceF = Interpolate16x16qpel(mvs.x, mvs.y, 0, data);  
                 ReferenceB = Interpolate16x16qpel(b_mvs.x, b_mvs.y, 1, data);  
         } else {  
                 xcf = 4*mvs.x; ycf = 4*mvs.y;  
                 xcb = 4*b_mvs.x; ycb = 4*b_mvs.y;  
                 ReferenceF = GetReference(mvs.x, mvs.y, data);  
                 ReferenceB = GetReferenceB(b_mvs.x, b_mvs.y, 1, data);  
         }  
1080    
1081          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);                  backupMV = *currMV;
         sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;  
1082    
1083          if (data->chroma) sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],                  CHECK_MV16_DIRECT_FOUND(backupMV.x - iDiamondSize, backupMV.y);
1084                                                                                  (ycf >> 3) + roundtab_76[ycf & 0xf],                  CHECK_MV16_DIRECT_FOUND(backupMV.x + iDiamondSize, backupMV.y);
1085                                                                                  (xcb >> 3) + roundtab_76[xcb & 0xf],                  CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y - iDiamondSize);
1086                                                                                  (ycb >> 3) + roundtab_76[ycb & 0xf], data);                  CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y + iDiamondSize);
1087    
1088          if (sad < *(data->iMinSAD)) {          } while (!iFound);
                 *(data->iMinSAD) = sad;  
                 data->currentMV->x = x; data->currentMV->y = y;  
                 *dir = Direction;  
         }  
 }  
1089    
1090  /* CHECK_CANDIATE FUNCTIONS END */          return iMinSAD;
1091    }
1092    
 /* MAINSEARCH FUNCTIONS START */  
1093    
1094  static void  int32_t
1095  AdvDiamondSearch(int x, int y, const SearchData * const data, int bDirection)  AdvDiamond8_MainSearch(const uint8_t * const pRef,
1096                                               const uint8_t * const pRefH,
1097                                               const uint8_t * const pRefV,
1098                                               const uint8_t * const pRefHV,
1099                                               const uint8_t * const cur,
1100                                               const int x,
1101                                               const int y,
1102                                               int start_x,
1103                                               int start_y,
1104                                               int iMinSAD,
1105                                               VECTOR * const currMV,
1106                                               const int center_x,
1107                                               const int center_y,
1108                                               const int32_t min_dx,
1109                                               const int32_t max_dx,
1110                                               const int32_t min_dy,
1111                                               const int32_t max_dy,
1112                                               const int32_t iEdgedWidth,
1113                                               const int32_t iDiamondSize,
1114                                               const int32_t iFcode,
1115                                               const int32_t iQuant,
1116                                               int iDirection)
1117  {  {
1118    
1119            int32_t iSAD;
1120    
1121  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
1122    
1123          int iDirection;          if (iDirection) {
1124                    CHECK_MV8_CANDIDATE(start_x - iDiamondSize, start_y);
1125                    CHECK_MV8_CANDIDATE(start_x + iDiamondSize, start_y);
1126                    CHECK_MV8_CANDIDATE(start_x, start_y - iDiamondSize);
1127                    CHECK_MV8_CANDIDATE(start_x, start_y + iDiamondSize);
1128            } else {
1129                    int bDirection = 1 + 2 + 4 + 8;
1130    
1131          for(;;) { //forever                  do {
1132                  iDirection = 0;                  iDirection = 0;
1133                  if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);                          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)
1134                  if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);                                  CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);
1135                  if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);  
1136                  if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);                          if (bDirection & 2)
1137                                    CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);
1138    
1139                            if (bDirection & 4)
1140                                    CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);
1141    
1142                            if (bDirection & 8)
1143                                    CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);
1144    
1145                  /* now we're doing diagonal checks near our candidate */                  /* now we're doing diagonal checks near our candidate */
1146    
1147                  if (iDirection) {               //if anything found                          if (iDirection)         //checking if anything found
1148                            {
1149                          bDirection = iDirection;                          bDirection = iDirection;
1150                          iDirection = 0;                          iDirection = 0;
1151                          x = data->currentMV->x; y = data->currentMV->y;                                  start_x = currMV->x;
1152                          if (bDirection & 3) {   //our candidate is left or right                                  start_y = currMV->y;
1153                                  CHECK_CANDIDATE(x, y + iDiamondSize, 8);                                  if (bDirection & 3)     //our candidate is left or right
1154                                  CHECK_CANDIDATE(x, y - iDiamondSize, 4);                                  {
1155                          } else {                        // what remains here is up or down                                          CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);
1156                                  CHECK_CANDIDATE(x + iDiamondSize, y, 2);                                          CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);
1157                                  CHECK_CANDIDATE(x - iDiamondSize, y, 1);                                  } else                  // what remains here is up or down
1158                                    {
1159                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);
1160                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);
1161                          }                          }
1162    
1163                          if (iDirection) {                          if (iDirection) {
1164                                  bDirection += iDirection;                                  bDirection += iDirection;
1165                                  x = data->currentMV->x; y = data->currentMV->y;                                          start_x = currMV->x;
1166                                            start_y = currMV->y;
1167                          }                          }
1168                  } else {                                //about to quit, eh? not so fast....                          } else                          //about to quit, eh? not so fast....
1169                            {
1170                          switch (bDirection) {                          switch (bDirection) {
1171                          case 2:                          case 2:
1172                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1173                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);                                                                                          start_y - iDiamondSize, 2 + 4);
1174                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1175                                                                                            start_y + iDiamondSize, 2 + 8);
1176                                  break;                                  break;
1177                          case 1:                          case 1:
1178                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1179                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);                                                                                          start_y - iDiamondSize, 1 + 4);
1180                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1181                                                                                            start_y + iDiamondSize, 1 + 8);
1182                                  break;                                  break;
1183                          case 2 + 4:                          case 2 + 4:
1184                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1185                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);                                                                                          start_y - iDiamondSize, 1 + 4);
1186                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1187                                                                                            start_y - iDiamondSize, 2 + 4);
1188                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1189                                                                                            start_y + iDiamondSize, 2 + 8);
1190                                  break;                                  break;
1191                          case 4:                          case 4:
1192                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1193                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);                                                                                          start_y - iDiamondSize, 2 + 4);
1194                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1195                                                                                            start_y - iDiamondSize, 1 + 4);
1196                                  break;                                  break;
1197                          case 8:                          case 8:
1198                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1199                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);                                                                                          start_y + iDiamondSize, 2 + 8);
1200                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1201                                                                                            start_y + iDiamondSize, 1 + 8);
1202                                  break;                                  break;
1203                          case 1 + 4:                          case 1 + 4:
1204                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1205                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);                                                                                          start_y + iDiamondSize, 1 + 8);
1206                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1207                                                                                            start_y - iDiamondSize, 1 + 4);
1208                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1209                                                                                            start_y - iDiamondSize, 2 + 4);
1210                                  break;                                  break;
1211                          case 2 + 8:                          case 2 + 8:
1212                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1213                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);                                                                                          start_y - iDiamondSize, 1 + 4);
1214                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1215                                                                                            start_y + iDiamondSize, 1 + 8);
1216                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1217                                                                                            start_y + iDiamondSize, 2 + 8);
1218                                  break;                                  break;
1219                          case 1 + 8:                          case 1 + 8:
1220                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1221                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);                                                                                          start_y - iDiamondSize, 2 + 4);
1222                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1223                                                                                            start_y + iDiamondSize, 2 + 8);
1224                                            CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1225                                                                                            start_y + iDiamondSize, 1 + 8);
1226                                  break;                                  break;
1227                          default:                //1+2+4+8 == we didn't find anything at all                          default:                //1+2+4+8 == we didn't find anything at all
1228                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1229                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);                                                                                          start_y - iDiamondSize, 1 + 4);
1230                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,
1231                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);                                                                                          start_y + iDiamondSize, 1 + 8);
1232                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1233                                                                                            start_y - iDiamondSize, 2 + 4);
1234                                            CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,
1235                                                                                            start_y + iDiamondSize, 2 + 8);
1236                                  break;                                  break;
1237                          }                          }
1238                          if (!iDirection) break;         //ok, the end. really                                  if (!(iDirection))
1239                                            break;          //ok, the end. really
1240                                    else {
1241                          bDirection = iDirection;                          bDirection = iDirection;
1242                          x = data->currentMV->x; y = data->currentMV->y;                                          start_x = currMV->x;
1243                                            start_y = currMV->y;
1244                  }                  }
1245          }          }
1246  }  }
1247                    while (1);                              //forever
1248            }
1249            return iMinSAD;
1250    }
1251    
 static void  
 SquareSearch(int x, int y, const SearchData * const data, int bDirection)  
 {  
         int iDirection;  
1252    
1253          do {  int32_t
1254                  iDirection = 0;  Full8_MainSearch(const uint8_t * const pRef,
1255                  if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);                                   const uint8_t * const pRefH,
1256                  if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);                                   const uint8_t * const pRefV,
1257                  if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);                                   const uint8_t * const pRefHV,
1258                  if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128);                                   const uint8_t * const cur,
1259                  if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64);                                   const int x,
1260                  if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128);                                   const int y,
1261                  if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128);                             const int start_x,
1262                  if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128);                             const int start_y,
1263                               int iMinSAD,
1264                               VECTOR * const currMV,
1265                               const int center_x,
1266                               const int center_y,
1267                                     const int32_t min_dx,
1268                                     const int32_t max_dx,
1269                                     const int32_t min_dy,
1270                                     const int32_t max_dy,
1271                                     const int32_t iEdgedWidth,
1272                                     const int32_t iDiamondSize,
1273                                     const int32_t iFcode,
1274                                     const int32_t iQuant,
1275                                     int iFound)
1276    {
1277            int32_t iSAD;
1278            int32_t dx, dy;
1279            VECTOR backupMV;
1280    
1281            backupMV.x = start_x;
1282            backupMV.y = start_y;
1283    
1284            for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)
1285                    for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)
1286                            NOCHECK_MV8_CANDIDATE(dx, dy);
1287    
1288                  bDirection = iDirection;          return iMinSAD;
                 x = data->currentMV->x; y = data->currentMV->y;  
         } while (iDirection);  
1289  }  }
1290    
1291  static void  Halfpel8_RefineFuncPtr Halfpel8_Refine;
 DiamondSearch(int x, int y, const SearchData * const data, int bDirection)  
 {  
   
 /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */  
1292    
1293          int iDirection;  int32_t
1294    Halfpel16_Refine(const uint8_t * const pRef,
1295                                     const uint8_t * const pRefH,
1296                                     const uint8_t * const pRefV,
1297                                     const uint8_t * const pRefHV,
1298                                     const uint8_t * const cur,
1299                                     const int x,
1300                                     const int y,
1301                                     VECTOR * const currMV,
1302                                     int32_t iMinSAD,
1303                               const int center_x,
1304                               const int center_y,
1305                                     const int32_t min_dx,
1306                                     const int32_t max_dx,
1307                                     const int32_t min_dy,
1308                                     const int32_t max_dy,
1309                                     const int32_t iFcode,
1310                                     const int32_t iQuant,
1311                                     const int32_t iEdgedWidth)
1312    {
1313    /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */
1314    
1315          do {          int32_t iSAD;
1316                  iDirection = 0;          VECTOR backupMV = *currMV;
                 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);  
1317    
1318                  /* now we're doing diagonal checks near our candidate */          CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y - 1);
1319            CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y - 1);
1320            CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y - 1);
1321            CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y);
1322            CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y);
1323            CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y + 1);
1324            CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y + 1);
1325            CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y + 1);
1326    
1327                  if (iDirection) {               //checking if anything found          return iMinSAD;
                         bDirection = iDirection;  
                         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);  
                         }  
                         bDirection += iDirection;  
                         x = data->currentMV->x; y = data->currentMV->y;  
                 }  
1328          }          }
         while (iDirection);  
 }  
   
 /* MAINSEARCH FUNCTIONS END */  
   
 static void  
 SubpelRefine(const SearchData * const data)  
 {  
 /* Do a half-pel or q-pel refinement */  
         const VECTOR centerMV = data->qpel_precision ? *data->currentQMV : *data->currentMV;  
         int iDirection; //only needed because macro expects it  
1329    
1330          CHECK_CANDIDATE(centerMV.x, centerMV.y - 1, 0);  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)
         CHECK_CANDIDATE(centerMV.x + 1, centerMV.y - 1, 0);  
         CHECK_CANDIDATE(centerMV.x + 1, centerMV.y, 0);  
         CHECK_CANDIDATE(centerMV.x + 1, centerMV.y + 1, 0);  
         CHECK_CANDIDATE(centerMV.x, centerMV.y + 1, 0);  
         CHECK_CANDIDATE(centerMV.x - 1, centerMV.y + 1, 0);  
         CHECK_CANDIDATE(centerMV.x - 1, centerMV.y, 0);  
         CHECK_CANDIDATE(centerMV.x - 1, centerMV.y - 1, 0);  
 }  
1331    
 static __inline int  
 SkipDecisionP(const IMAGE * current, const IMAGE * reference,  
                                                         const int x, const int y,  
                                                         const uint32_t stride, const uint32_t iQuant, int rrv)  
1332    
 {  
         if(!rrv) {  
                 uint32_t sadC = sad8(current->u + x*8 + y*stride*8,  
                                                 reference->u + x*8 + y*stride*8, stride);  
                 if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;  
                 sadC += sad8(current->v + (x + y*stride)*8,  
                                                 reference->v + (x + y*stride)*8, stride);  
                 if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;  
                 return 1;  
1333    
1334    int32_t
1335    PMVfastSearch16(const uint8_t * const pRef,
1336                                    const uint8_t * const pRefH,
1337                                    const uint8_t * const pRefV,
1338                                    const uint8_t * const pRefHV,
1339                                    const IMAGE * const pCur,
1340                                    const int x,
1341                                    const int y,
1342                                    const int start_x,      /* start is searched first, so it should contain the most */
1343                                    const int start_y,  /* likely motion vector for this block */
1344                                    const int center_x,     /* center is from where length of MVs is measured */
1345                                    const int center_y,
1346                                    const uint32_t MotionFlags,
1347                                    const uint32_t iQuant,
1348                                    const uint32_t iFcode,
1349                                    const MBParam * const pParam,
1350                                    const MACROBLOCK * const pMBs,
1351                                    const MACROBLOCK * const prevMBs,
1352                                    VECTOR * const currMV,
1353                                    VECTOR * const currPMV)
1354    {
1355            const uint32_t iWcount = pParam->mb_width;
1356            const int32_t iWidth = pParam->width;
1357            const int32_t iHeight = pParam->height;
1358            const int32_t iEdgedWidth = pParam->edged_width;
1359    
1360            const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;
1361    
1362            int32_t iDiamondSize;
1363    
1364            int32_t min_dx;
1365            int32_t max_dx;
1366            int32_t min_dy;
1367            int32_t max_dy;
1368    
1369            int32_t iFound;
1370    
1371            VECTOR newMV;
1372            VECTOR backupMV;                        /* just for PMVFAST */
1373    
1374            VECTOR pmv[4];
1375            int32_t psad[4];
1376    
1377            MainSearch16FuncPtr MainSearchPtr;
1378    
1379            const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;
1380    
1381            int32_t threshA, threshB;
1382            int32_t bPredEq;
1383            int32_t iMinSAD, iSAD;
1384    
1385    /* Get maximum range */
1386            get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,
1387                              iFcode);
1388    
1389    /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */
1390    
1391            if (!(MotionFlags & PMV_HALFPEL16)) {
1392                    min_dx = EVEN(min_dx);
1393                    max_dx = EVEN(max_dx);
1394                    min_dy = EVEN(min_dy);
1395                    max_dy = EVEN(max_dy);
1396            }
1397    
1398            /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */
1399            //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);
1400            bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);
1401    
1402            if ((x == 0) && (y == 0)) {
1403                    threshA = 512;
1404                    threshB = 1024;
1405          } else {          } else {
1406                  uint32_t sadC = sad16(current->u + x*16 + y*stride*16,                  threshA = psad[0];
1407                                                  reference->u + x*16 + y*stride*16, stride, 256*4096);                  threshB = threshA + 256;
1408                  if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;                  if (threshA < 512)
1409                  sadC += sad16(current->v + (x + y*stride)*16,                          threshA = 512;
1410                                                  reference->v + (x + y*stride)*16, stride, 256*4096);                  if (threshA > 1024)
1411                  if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;                          threshA = 1024;
1412                  return 1;                  if (threshB > 1792)
1413                            threshB = 1792;
1414            }
1415    
1416            iFound = 0;
1417    
1418    /* Step 4: Calculate SAD around the Median prediction.
1419       MinSAD=SAD
1420       If Motion Vector equal to Previous frame motion vector
1421       and MinSAD<PrevFrmSAD goto Step 10.
1422       If SAD<=256 goto Step 10.
1423    */
1424    
1425            currMV->x = start_x;
1426            currMV->y = start_y;
1427    
1428            if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */
1429                    currMV->x = EVEN(currMV->x);
1430                    currMV->y = EVEN(currMV->y);
1431            }
1432    
1433            if (currMV->x > max_dx) {
1434                    currMV->x = max_dx;
1435            }
1436            if (currMV->x < min_dx) {
1437                    currMV->x = min_dx;
1438          }          }
1439            if (currMV->y > max_dy) {
1440                    currMV->y = max_dy;
1441  }  }
1442            if (currMV->y < min_dy) {
1443                    currMV->y = min_dy;
1444            }
1445    
1446            iMinSAD =
1447                    sad16(cur,
1448                              get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,
1449                                                     iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);
1450            iMinSAD +=
1451                    calc_delta_16(currMV->x - center_x, currMV->y - center_y,
1452                                              (uint8_t) iFcode, iQuant);
1453    
1454  static __inline void          if ((iMinSAD < 256) ||
1455  SkipMacroblockP(MACROBLOCK *pMB, const int32_t sad)                  ((MVequal(*currMV, prevMB->mvs[0])) &&
1456                     ((int32_t) iMinSAD < prevMB->sad16))) {
1457                    if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode
1458  {  {
1459          pMB->mode = MODE_NOT_CODED;                          if (!MVzero(*currMV)) {
1460          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = zeroMV;                                  iMinSAD += MV16_00_BIAS;
1461          pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] = pMB->qmvs[3] = zeroMV;                                  CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures
1462          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;                                  iMinSAD -= MV16_00_BIAS;
1463                            }
1464  }  }
1465    
1466  bool                  if (MotionFlags & PMV_QUICKSTOP16)
1467  MotionEstimation(MBParam * const pParam,                          goto PMVfast16_Terminate_without_Refine;
1468                                   FRAMEINFO * const current,                  if (MotionFlags & PMV_EARLYSTOP16)
1469                                   FRAMEINFO * const reference,                          goto PMVfast16_Terminate_with_Refine;
1470                                   const IMAGE * const pRefH,          }
1471                                   const IMAGE * const pRefV,  
1472                                   const IMAGE * const pRefHV,  
1473                                   const uint32_t iLimit)  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion
1474  {     vector of the median.
1475          MACROBLOCK *const pMBs = current->mbs;     If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2
1476          const IMAGE *const pCurrent = &current->image;  */
1477          const IMAGE *const pRef = &reference->image;  
1478            if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[0])))
1479                    iFound = 2;
1480    
1481    /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.
1482       Otherwise select large Diamond Search.
1483    */
1484    
1485            if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))
1486                    iDiamondSize = 1;               // halfpel!
1487            else
1488                    iDiamondSize = 2;               // halfpel!
1489    
1490            if (!(MotionFlags & PMV_HALFPELDIAMOND16))
1491                    iDiamondSize *= 2;
1492    
1493          uint32_t mb_width = pParam->mb_width;  /*
1494          uint32_t mb_height = pParam->mb_height;     Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.
1495          const uint32_t iEdgedWidth = pParam->edged_width;     Also calculate (0,0) but do not subtract offset.
1496       Let MinSAD be the smallest SAD up to this point.
1497          uint32_t x, y;     If MV is (0,0) subtract offset.
1498          uint32_t iIntra = 0;  */
1499          int32_t InterBias, quant = current->quant, sad00;  
1500    // (0,0) is always possible
1501          // some pre-initialized thingies for SearchP  
1502          int32_t temp[8];          if (!MVzero(pmv[0]))
1503          VECTOR currentMV[5];                  CHECK_MV16_ZERO;
1504          VECTOR currentQMV[5];  
1505          int32_t iMinSAD[5];  // previous frame MV is always possible
1506          SearchData Data;  
1507          memset(&Data, 0, sizeof(SearchData));          if (!MVzero(prevMB->mvs[0]))
1508          Data.iEdgedWidth = iEdgedWidth;                  if (!MVequal(prevMB->mvs[0], pmv[0]))
1509          Data.currentMV = currentMV;                          CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);
1510          Data.currentQMV = currentQMV;  
1511          Data.iMinSAD = iMinSAD;  // left neighbour, if allowed
1512          Data.temp = temp;  
1513          Data.iFcode = current->fcode;          if (!MVzero(pmv[1]))
1514          Data.rounding = pParam->m_rounding_type;                  if (!MVequal(pmv[1], prevMB->mvs[0]))
1515          Data.qpel = pParam->m_quarterpel;                          if (!MVequal(pmv[1], pmv[0])) {
1516          Data.chroma = current->motion_flags & PMV_CHROMA16;                                  if (!(MotionFlags & PMV_HALFPEL16)) {
1517          Data.rrv = current->global_flags & XVID_REDUCED;                                          pmv[1].x = EVEN(pmv[1].x);
1518                                            pmv[1].y = EVEN(pmv[1].y);
         if ((current->global_flags & XVID_REDUCED)) {  
                 mb_width = (pParam->width + 31) / 32;  
                 mb_height = (pParam->height + 31) / 32;  
                 Data.qpel = Data.chroma = 0;  
         }  
   
         Data.RefQ = pRefV->u; // a good place, also used in MC (for similar purpose)  
         if (sadInit) (*sadInit) ();  
   
         for (y = 0; y < mb_height; y++) {  
                 for (x = 0; x < mb_width; x++)  {  
                         MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];  
   
                         if (!Data.rrv) pMB->sad16 =  
                                 sad16v(pCurrent->y + (x + y * iEdgedWidth) * 16,  
                                                         pRef->y + (x + y * iEdgedWidth) * 16,  
                                                         pParam->edged_width, pMB->sad8 );  
   
                         else pMB->sad16 =  
                                 sad32v_c(pCurrent->y + (x + y * iEdgedWidth) * 32,  
                                                         pRef->y + (x + y * iEdgedWidth) * 32,  
                                                         pParam->edged_width, pMB->sad8 );  
   
                         if (Data.chroma) {  
                                 Data.temp[7] = sad8(pCurrent->u + x*8 + y*(iEdgedWidth/2)*8,  
                                                                         pRef->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2)  
                                                                 + sad8(pCurrent->v + (x + y*(iEdgedWidth/2))*8,  
                                                                         pRef->v + (x + y*(iEdgedWidth/2))*8, iEdgedWidth/2);  
                                 pMB->sad16 += Data.temp[7];  
1519                          }                          }
1520    
1521                          sad00 = pMB->sad16;                                  CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);
1522                            }
1523    // top neighbour, if allowed
1524            if (!MVzero(pmv[2]))
1525                    if (!MVequal(pmv[2], prevMB->mvs[0]))
1526                            if (!MVequal(pmv[2], pmv[0]))
1527                                    if (!MVequal(pmv[2], pmv[1])) {
1528                                            if (!(MotionFlags & PMV_HALFPEL16)) {
1529                                                    pmv[2].x = EVEN(pmv[2].x);
1530                                                    pmv[2].y = EVEN(pmv[2].y);
1531                                            }
1532                                            CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);
1533    
1534                          if (!(current->global_flags & XVID_LUMIMASKING)) {  // top right neighbour, if allowed
1535                                  pMB->dquant = NO_CHANGE;                                          if (!MVzero(pmv[3]))
1536                          } else {                                                  if (!MVequal(pmv[3], prevMB->mvs[0]))
1537                                  if (pMB->dquant != NO_CHANGE) {                                                          if (!MVequal(pmv[3], pmv[0]))
1538                                          quant += DQtab[pMB->dquant];                                                                  if (!MVequal(pmv[3], pmv[1]))
1539                                          if (quant > 31) quant = 31;                                                                          if (!MVequal(pmv[3], pmv[2])) {
1540                                          else if (quant < 1) quant = 1;                                                                                  if (!(MotionFlags & PMV_HALFPEL16)) {
1541                                                                                            pmv[3].x = EVEN(pmv[3].x);
1542                                                                                            pmv[3].y = EVEN(pmv[3].y);
1543                                  }                                  }
1544                                                                                    CHECK_MV16_CANDIDATE(pmv[3].x,
1545                                                                                                                             pmv[3].y);
1546                          }                          }
                         pMB->quant = current->quant;  
   
 //initial skip decision  
 /* no early skip for GMC (global vector = skip vector is unknown!)  */  
                         if (!(current->global_flags & XVID_GMC))        { /* no fast SKIP for S(GMC)-VOPs */  
                                 if (pMB->dquant == NO_CHANGE && sad00 < pMB->quant * INITIAL_SKIP_THRESH * (Data.rrv ? 4:1) )  
                                         if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, iEdgedWidth/2, pMB->quant, Data.rrv)) {  
                                                 SkipMacroblockP(pMB, sad00);  
                                                 continue;  
1547                                          }                                          }
1548    
1549            if ((MVzero(*currMV)) &&
1550                    (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )
1551                    iMinSAD -= MV16_00_BIAS;
1552    
1553    
1554    /* Step 6: If MinSAD <= thresa goto Step 10.
1555       If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.
1556    */
1557    
1558            if ((iMinSAD <= threshA) ||
1559                    (MVequal(*currMV, prevMB->mvs[0]) &&
1560                     ((int32_t) iMinSAD < prevMB->sad16))) {
1561                    if (MotionFlags & PMV_QUICKSTOP16)
1562                            goto PMVfast16_Terminate_without_Refine;
1563                    if (MotionFlags & PMV_EARLYSTOP16)
1564                            goto PMVfast16_Terminate_with_Refine;
1565                          }                          }
1566    
1567                          SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,  
1568                                                  y, current->motion_flags, pMB->quant,  /************ (Diamond Search)  **************/
1569                                                  &Data, pParam, pMBs, reference->mbs,  /*
1570                                                  current->global_flags & XVID_INTER4V, pMB);     Step 7: Perform Diamond search, with either the small or large diamond.
1571       If Found=2 only examine one Diamond pattern, and afterwards goto step 10
1572  /* final skip decision, a.k.a. "the vector you found, really that good?" */     Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.
1573                          if (!(current->global_flags & XVID_GMC))        {     If center then goto step 10.
1574                                  if ( (pMB->dquant == NO_CHANGE) && (sad00 < pMB->quant * MAX_SAD00_FOR_SKIP)     Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.
1575                                          && ((100*pMB->sad16)/(sad00+1) > FINAL_SKIP_THRESH * (Data.rrv ? 4:1)) )     Refine by using small diamond and goto step 10.
1576                                          if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, iEdgedWidth/2, pMB->quant, Data.rrv)) {  */
1577                                                  SkipMacroblockP(pMB, sad00);  
1578                                                  continue;          if (MotionFlags & PMV_USESQUARES16)
1579                    MainSearchPtr = Square16_MainSearch;
1580            else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
1581                    MainSearchPtr = AdvDiamond16_MainSearch;
1582            else
1583                    MainSearchPtr = Diamond16_MainSearch;
1584    
1585            backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */
1586    
1587    
1588    /* default: use best prediction as starting point for one call of PMVfast_MainSearch */
1589            iSAD =
1590                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,
1591                                                      currMV->x, currMV->y, iMinSAD, &newMV, center_x, center_y,
1592                                                      min_dx, max_dx,
1593                                                      min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,
1594                                                      iQuant, iFound);
1595    
1596            if (iSAD < iMinSAD) {
1597                    *currMV = newMV;
1598                    iMinSAD = iSAD;
1599            }
1600    
1601            if (MotionFlags & PMV_EXTSEARCH16) {
1602    /* extended: search (up to) two more times: orignal prediction and (0,0) */
1603    
1604                    if (!(MVequal(pmv[0], backupMV))) {
1605                            iSAD =
1606                                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,
1607                                                                      center_x, center_y, iMinSAD, &newMV, center_x, center_y,
1608                                                                      min_dx, max_dx, min_dy, max_dy, iEdgedWidth,
1609                                                                      iDiamondSize, iFcode, iQuant, iFound);
1610    
1611                            if (iSAD < iMinSAD) {
1612                                    *currMV = newMV;
1613                                    iMinSAD = iSAD;
1614                                          }                                          }
1615                          }                          }
1616    
1617  /* finally, intra decision */                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {
1618                            iSAD =
1619                                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,
1620                                                                      iMinSAD, &newMV, center_x, center_y,
1621                                                                      min_dx, max_dx, min_dy, max_dy,
1622                                                                      iEdgedWidth, iDiamondSize, iFcode,
1623                                                                      iQuant, iFound);
1624    
1625                          InterBias = MV16_INTER_BIAS;                          if (iSAD < iMinSAD) {
1626                          if (pMB->quant > 8) InterBias += 100 * (pMB->quant - 8); // to make high quants work                                  *currMV = newMV;
1627                          if (y != 0)                                  iMinSAD = iSAD;
1628                                  if ((pMB - pParam->mb_width)->mode == MODE_INTRA ) InterBias -= 80;                          }
1629                          if (x != 0)                  }
1630                                  if ((pMB - 1)->mode == MODE_INTRA ) InterBias -= 80;          }
1631    
1632                          if (Data.chroma) InterBias += 50; // to compensate bigger SAD  /*
1633                          if (Data.rrv) InterBias *= 4;     Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.
1634    */
1635    
1636                          if (InterBias < pMB->sad16) {    PMVfast16_Terminate_with_Refine:
1637                                  int32_t deviation;          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step
1638                                  if (!Data.rrv)                  iMinSAD =
1639                                          deviation = dev16(pCurrent->y + (x + y * iEdgedWidth) * 16, iEdgedWidth);                          Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,
1640                                  else {                                                           iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,
1641                                          deviation = dev16(pCurrent->y + (x + y * iEdgedWidth) * 32, iEdgedWidth)                                                           iFcode, iQuant, iEdgedWidth);
1642                                                  + dev16(pCurrent->y + (x + y * iEdgedWidth) * 32 + 16, iEdgedWidth)  
1643                                                  + dev16(pCurrent->y + (x + y * iEdgedWidth) * 32 + 16 * iEdgedWidth, iEdgedWidth)    PMVfast16_Terminate_without_Refine:
1644                                                  + dev16(pCurrent->y + (x + y * iEdgedWidth) * 32 + 16 * (iEdgedWidth+1), iEdgedWidth);          currPMV->x = currMV->x - center_x;
1645                                  }          currPMV->y = currMV->y - center_y;
1646                                  if (deviation < (pMB->sad16 - InterBias)) {          return iMinSAD;
                                         if (++iIntra >= iLimit) return 1;  
                                         SkipMacroblockP(pMB, 0); //same thing  
                                         pMB->mode = MODE_INTRA;  
1647                                  }                                  }
1648    
1649    
1650    
1651    
1652    
1653    
1654    int32_t
1655    Diamond8_MainSearch(const uint8_t * const pRef,
1656                                            const uint8_t * const pRefH,
1657                                            const uint8_t * const pRefV,
1658                                            const uint8_t * const pRefHV,
1659                                            const uint8_t * const cur,
1660                                            const int x,
1661                                            const int y,
1662                                            int32_t start_x,
1663                                            int32_t start_y,
1664                                            int32_t iMinSAD,
1665                                            VECTOR * const currMV,
1666                                       const int center_x,
1667                                       const int center_y,
1668                                            const int32_t min_dx,
1669                                            const int32_t max_dx,
1670                                            const int32_t min_dy,
1671                                            const int32_t max_dy,
1672                                            const int32_t iEdgedWidth,
1673                                            const int32_t iDiamondSize,
1674                                            const int32_t iFcode,
1675                                            const int32_t iQuant,
1676                                            int iFound)
1677    {
1678    /* Do a diamond search around given starting point, return SAD of best */
1679    
1680            int32_t iDirection = 0;
1681            int32_t iDirectionBackup;
1682            int32_t iSAD;
1683            VECTOR backupMV;
1684    
1685            backupMV.x = start_x;
1686            backupMV.y = start_y;
1687    
1688    /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */
1689    
1690            CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);
1691            CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);
1692            CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);
1693            CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);
1694    
1695            if (iDirection) {
1696                    while (!iFound) {
1697                            iFound = 1;
1698                            backupMV = *currMV;     // since iDirection!=0, this is well defined!
1699                            iDirectionBackup = iDirection;
1700    
1701                            if (iDirectionBackup != 2)
1702                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1703                                                                                      backupMV.y, 1);
1704                            if (iDirectionBackup != 1)
1705                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1706                                                                                      backupMV.y, 2);
1707                            if (iDirectionBackup != 4)
1708                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x,
1709                                                                                      backupMV.y - iDiamondSize, 3);
1710                            if (iDirectionBackup != 3)
1711                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x,
1712                                                                                      backupMV.y + iDiamondSize, 4);
1713                          }                          }
1714            } else {
1715                    currMV->x = start_x;
1716                    currMV->y = start_y;
1717                  }                  }
1718            return iMinSAD;
1719          }          }
1720    
1721          if (current->global_flags & XVID_GMC )  /* GMC only for S(GMC)-VOPs */  
1722          {  
1723                  current->warp = GlobalMotionEst( pMBs, pParam, current, reference, pRefH, pRefV, pRefHV);  
1724    int32_t
1725    Square8_MainSearch(const uint8_t * const pRef,
1726                                            const uint8_t * const pRefH,
1727                                            const uint8_t * const pRefV,
1728                                            const uint8_t * const pRefHV,
1729                                            const uint8_t * const cur,
1730                                            const int x,
1731                                            const int y,
1732                                            int32_t start_x,
1733                                            int32_t start_y,
1734                                            int32_t iMinSAD,
1735                                            VECTOR * const currMV,
1736                                       const int center_x,
1737                                       const int center_y,
1738                                            const int32_t min_dx,
1739                                            const int32_t max_dx,
1740                                            const int32_t min_dy,
1741                                            const int32_t max_dy,
1742                                            const int32_t iEdgedWidth,
1743                                            const int32_t iDiamondSize,
1744                                            const int32_t iFcode,
1745                                            const int32_t iQuant,
1746                                            int iFound)
1747    {
1748    /* Do a square search around given starting point, return SAD of best */
1749    
1750            int32_t iDirection = 0;
1751            int32_t iSAD;
1752            VECTOR backupMV;
1753    
1754            backupMV.x = start_x;
1755            backupMV.y = start_y;
1756    
1757    /* It's one search with full square pattern, and new parts for all following diamonds */
1758    
1759    /*   new direction are extra, so 1-4 is normal diamond
1760          537
1761          1*2
1762          648
1763    */
1764    
1765            CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);
1766            CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);
1767            CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);
1768            CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);
1769    
1770            CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,
1771                                                             backupMV.y - iDiamondSize, 5);
1772            CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,
1773                                                             backupMV.y + iDiamondSize, 6);
1774            CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,
1775                                                             backupMV.y - iDiamondSize, 7);
1776            CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,
1777                                                             backupMV.y + iDiamondSize, 8);
1778    
1779    
1780            if (iDirection) {
1781                    while (!iFound) {
1782                            iFound = 1;
1783                            backupMV = *currMV;
1784    
1785                            switch (iDirection) {
1786                            case 1:
1787                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1788                                                                                       backupMV.y, 1);
1789                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1790                                                                                     backupMV.y - iDiamondSize, 5);
1791                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1792                                                                                     backupMV.y - iDiamondSize, 7);
1793                                    break;
1794                            case 2:
1795                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
1796                                                                                     2);
1797                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1798                                                                                     backupMV.y + iDiamondSize, 6);
1799                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1800                                                                                     backupMV.y + iDiamondSize, 8);
1801                                    break;
1802    
1803                            case 3:
1804                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
1805                                                                                     4);
1806                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1807                                                                                     backupMV.y - iDiamondSize, 7);
1808                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1809                                                                                     backupMV.y + iDiamondSize, 8);
1810                                    break;
1811    
1812                            case 4:
1813                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
1814                                                                                     3);
1815                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1816                                                                                     backupMV.y - iDiamondSize, 5);
1817                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1818                                                                                     backupMV.y + iDiamondSize, 6);
1819                                    break;
1820    
1821                            case 5:
1822                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,
1823                                                                                     1);
1824                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
1825                                                                                     3);
1826                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1827                                                                                     backupMV.y - iDiamondSize, 5);
1828                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1829                                                                                     backupMV.y + iDiamondSize, 6);
1830                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1831                                                                                     backupMV.y - iDiamondSize, 7);
1832                                    break;
1833    
1834                            case 6:
1835                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
1836                                                                                     2);
1837                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
1838                                                                                     3);
1839    
1840                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1841                                                                                     backupMV.y - iDiamondSize, 5);
1842                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1843                                                                                     backupMV.y + iDiamondSize, 6);
1844                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1845                                                                                     backupMV.y + iDiamondSize, 8);
1846    
1847                                    break;
1848    
1849                            case 7:
1850                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1851                                                                                       backupMV.y, 1);
1852                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
1853                                                                                     4);
1854                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1855                                                                                     backupMV.y - iDiamondSize, 5);
1856                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1857                                                                                     backupMV.y - iDiamondSize, 7);
1858                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1859                                                                                     backupMV.y + iDiamondSize, 8);
1860                                    break;
1861    
1862                            case 8:
1863                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
1864                                                                                     2);
1865                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
1866                                                                                     4);
1867                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1868                                                                                     backupMV.y + iDiamondSize, 6);
1869                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1870                                                                                     backupMV.y - iDiamondSize, 7);
1871                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1872                                                                                     backupMV.y + iDiamondSize, 8);
1873                                    break;
1874                            default:
1875                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,
1876                                                                                     1);
1877                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,
1878                                                                                     2);
1879                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,
1880                                                                                     3);
1881                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,
1882                                                                                     4);
1883    
1884                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1885                                                                                     backupMV.y - iDiamondSize, 5);
1886                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,
1887                                                                                     backupMV.y + iDiamondSize, 6);
1888                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1889                                                                                     backupMV.y - iDiamondSize, 7);
1890                                    CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,
1891                                                                                     backupMV.y + iDiamondSize, 8);
1892                                    break;
1893                            }
1894                    }
1895            } else {
1896                    currMV->x = start_x;
1897                    currMV->y = start_y;
1898            }
1899            return iMinSAD;
1900          }          }
1901    
1902          return 0;  
1903    
1904    
1905    
1906    int32_t
1907    Halfpel8_Refine_c(const uint8_t * const pRef,
1908                                    const uint8_t * const pRefH,
1909                                    const uint8_t * const pRefV,
1910                                    const uint8_t * const pRefHV,
1911                                    const uint8_t * const cur,
1912                                    const int x,
1913                                    const int y,
1914                                    VECTOR * const currMV,
1915                                    int32_t iMinSAD,
1916                               const int center_x,
1917                               const int center_y,
1918                                    const int32_t min_dx,
1919                                    const int32_t max_dx,
1920                                    const int32_t min_dy,
1921                                    const int32_t max_dy,
1922                                    const int32_t iFcode,
1923                                    const int32_t iQuant,
1924                                    const int32_t iEdgedWidth)
1925    {
1926    /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */
1927    
1928            int32_t iSAD;
1929            VECTOR backupMV = *currMV;
1930    
1931            CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y - 1);
1932            CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y - 1);
1933            CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y - 1);
1934            CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y);
1935            CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y);
1936            CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y + 1);
1937            CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y + 1);
1938            CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y + 1);
1939    
1940            return iMinSAD;
1941  }  }
1942    
1943    
1944  static __inline int  #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)
1945  make_mask(const VECTOR * const pmv, const int i)  
1946    int32_t
1947    PMVfastSearch8(const uint8_t * const pRef,
1948                               const uint8_t * const pRefH,
1949                               const uint8_t * const pRefV,
1950                               const uint8_t * const pRefHV,
1951                               const IMAGE * const pCur,
1952                               const int x,
1953                               const int y,
1954                               const int start_x,
1955                               const int start_y,
1956                                    const int center_x,
1957                                    const int center_y,
1958                               const uint32_t MotionFlags,
1959                               const uint32_t iQuant,
1960                               const uint32_t iFcode,
1961                               const MBParam * const pParam,
1962                               const MACROBLOCK * const pMBs,
1963                               const MACROBLOCK * const prevMBs,
1964                               VECTOR * const currMV,
1965                               VECTOR * const currPMV)
1966  {  {
1967          int mask = 255, j;          const uint32_t iWcount = pParam->mb_width;
1968          for (j = 0; j < i; j++) {          const int32_t iWidth = pParam->width;
1969                  if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already          const int32_t iHeight = pParam->height;
1970                  if (pmv[i].x == pmv[j].x) {          const int32_t iEdgedWidth = pParam->edged_width;
1971                          if (pmv[i].y == pmv[j].y + iDiamondSize) mask &= ~4;  
1972                          else if (pmv[i].y == pmv[j].y - iDiamondSize) mask &= ~8;          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;
1973                  } else  
1974                          if (pmv[i].y == pmv[j].y) {          int32_t iDiamondSize;
1975                                  if (pmv[i].x == pmv[j].x + iDiamondSize) mask &= ~1;  
1976                                  else if (pmv[i].x == pmv[j].x - iDiamondSize) mask &= ~2;          int32_t min_dx;
1977            int32_t max_dx;
1978            int32_t min_dy;
1979            int32_t max_dy;
1980    
1981            VECTOR pmv[4];
1982            int32_t psad[4];
1983            VECTOR newMV;
1984            VECTOR backupMV;
1985            VECTOR startMV;
1986    
1987    //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;
1988            const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;
1989    
1990             int32_t threshA, threshB;
1991            int32_t iFound, bPredEq;
1992            int32_t iMinSAD, iSAD;
1993    
1994            int32_t iSubBlock = (y & 1) + (y & 1) + (x & 1);
1995    
1996            MainSearch8FuncPtr MainSearchPtr;
1997    
1998            /* Init variables */
1999            startMV.x = start_x;
2000            startMV.y = start_y;
2001    
2002            /* Get maximum range */
2003            get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,
2004                              iFcode);
2005    
2006            if (!(MotionFlags & PMV_HALFPELDIAMOND8)) {
2007                    min_dx = EVEN(min_dx);
2008                    max_dx = EVEN(max_dx);
2009                    min_dy = EVEN(min_dy);
2010                    max_dy = EVEN(max_dy);
2011            }
2012    
2013            /* because we might use IF (dx>max_dx) THEN dx=max_dx; */
2014            //bPredEq = get_pmvdata(pMBs, (x >> 1), (y >> 1), iWcount, iSubBlock, pmv, psad);
2015            bPredEq = get_pmvdata2(pMBs, iWcount, 0, (x >> 1), (y >> 1), iSubBlock, pmv, psad);
2016    
2017            if ((x == 0) && (y == 0)) {
2018                    threshA = 512 / 4;
2019                    threshB = 1024 / 4;
2020    
2021            } else {
2022                    threshA = psad[0] / 4;  /* good estimate? */
2023                    threshB = threshA + 256 / 4;
2024                    if (threshA < 512 / 4)
2025                            threshA = 512 / 4;
2026                    if (threshA > 1024 / 4)
2027                            threshA = 1024 / 4;
2028                    if (threshB > 1792 / 4)
2029                            threshB = 1792 / 4;
2030            }
2031    
2032            iFound = 0;
2033    
2034    /* Step 4: Calculate SAD around the Median prediction.
2035       MinSAD=SAD
2036       If Motion Vector equal to Previous frame motion vector
2037       and MinSAD<PrevFrmSAD goto Step 10.
2038       If SAD<=256 goto Step 10.
2039    */
2040    
2041    
2042    // Prepare for main loop
2043    
2044      if (MotionFlags & PMV_USESQUARES8)
2045          MainSearchPtr = Square8_MainSearch;
2046      else
2047    
2048            if (MotionFlags & PMV_ADVANCEDDIAMOND8)
2049                    MainSearchPtr = AdvDiamond8_MainSearch;
2050            else
2051                    MainSearchPtr = Diamond8_MainSearch;
2052    
2053    
2054            *currMV = startMV;
2055    
2056            iMinSAD =
2057                    sad8(cur,
2058                             get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,
2059                                                    iEdgedWidth), iEdgedWidth);
2060            iMinSAD +=
2061                    calc_delta_8(currMV->x - center_x, currMV->y - center_y,
2062                                             (uint8_t) iFcode, iQuant);
2063    
2064            if ((iMinSAD < 256 / 4) || ((MVequal(*currMV, prevMB->mvs[iSubBlock]))
2065                                                                    && ((int32_t) iMinSAD <
2066                                                                            prevMB->sad8[iSubBlock]))) {
2067                    if (MotionFlags & PMV_QUICKSTOP16)
2068                            goto PMVfast8_Terminate_without_Refine;
2069                    if (MotionFlags & PMV_EARLYSTOP16)
2070                            goto PMVfast8_Terminate_with_Refine;
2071            }
2072    
2073    /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion
2074       vector of the median.
2075       If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2
2076    */
2077    
2078            if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[iSubBlock])))
2079                    iFound = 2;
2080    
2081    /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.
2082       Otherwise select large Diamond Search.
2083    */
2084    
2085            if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))
2086                    iDiamondSize = 1;               // 1 halfpel!
2087            else
2088                    iDiamondSize = 2;               // 2 halfpel = 1 full pixel!
2089    
2090            if (!(MotionFlags & PMV_HALFPELDIAMOND8))
2091                    iDiamondSize *= 2;
2092    
2093    
2094    /*
2095       Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.
2096       Also calculate (0,0) but do not subtract offset.
2097       Let MinSAD be the smallest SAD up to this point.
2098       If MV is (0,0) subtract offset.
2099    */
2100    
2101    // the median prediction might be even better than mv16
2102    
2103            if (!MVequal(pmv[0], startMV))
2104                    CHECK_MV8_CANDIDATE(center_x, center_y);
2105    
2106    // (0,0) if needed
2107            if (!MVzero(pmv[0]))
2108                    if (!MVzero(startMV))
2109                            CHECK_MV8_ZERO;
2110    
2111    // previous frame MV if needed
2112            if (!MVzero(prevMB->mvs[iSubBlock]))
2113                    if (!MVequal(prevMB->mvs[iSubBlock], startMV))
2114                            if (!MVequal(prevMB->mvs[iSubBlock], pmv[0]))
2115                                    CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x,
2116                                                                            prevMB->mvs[iSubBlock].y);
2117    
2118            if ((iMinSAD <= threshA) ||
2119                    (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&
2120                     ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {
2121                    if (MotionFlags & PMV_QUICKSTOP16)
2122                            goto PMVfast8_Terminate_without_Refine;
2123                    if (MotionFlags & PMV_EARLYSTOP16)
2124                            goto PMVfast8_Terminate_with_Refine;
2125            }
2126    
2127    // left neighbour, if allowed and needed
2128            if (!MVzero(pmv[1]))
2129                    if (!MVequal(pmv[1], startMV))
2130                            if (!MVequal(pmv[1], prevMB->mvs[iSubBlock]))
2131                                    if (!MVequal(pmv[1], pmv[0])) {
2132                                            if (!(MotionFlags & PMV_HALFPEL8)) {
2133                                                    pmv[1].x = EVEN(pmv[1].x);
2134                                                    pmv[1].y = EVEN(pmv[1].y);
2135                                            }
2136                                            CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);
2137                                    }
2138    // top neighbour, if allowed and needed
2139            if (!MVzero(pmv[2]))
2140                    if (!MVequal(pmv[2], startMV))
2141                            if (!MVequal(pmv[2], prevMB->mvs[iSubBlock]))
2142                                    if (!MVequal(pmv[2], pmv[0]))
2143                                            if (!MVequal(pmv[2], pmv[1])) {
2144                                                    if (!(MotionFlags & PMV_HALFPEL8)) {
2145                                                            pmv[2].x = EVEN(pmv[2].x);
2146                                                            pmv[2].y = EVEN(pmv[2].y);
2147                                                    }
2148                                                    CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);
2149    
2150    // top right neighbour, if allowed and needed
2151                                                    if (!MVzero(pmv[3]))
2152                                                            if (!MVequal(pmv[3], startMV))
2153                                                                    if (!MVequal(pmv[3], prevMB->mvs[iSubBlock]))
2154                                                                            if (!MVequal(pmv[3], pmv[0]))
2155                                                                                    if (!MVequal(pmv[3], pmv[1]))
2156                                                                                            if (!MVequal(pmv[3], pmv[2])) {
2157                                                                                                    if (!
2158                                                                                                            (MotionFlags &
2159                                                                                                             PMV_HALFPEL8)) {
2160                                                                                                            pmv[3].x = EVEN(pmv[3].x);
2161                                                                                                            pmv[3].y = EVEN(pmv[3].y);
2162                                                                                                    }
2163                                                                                                    CHECK_MV8_CANDIDATE(pmv[3].x,
2164                                                                                                                                            pmv[3].y);
2165                                                                                            }
2166                                            }
2167    
2168            if ((MVzero(*currMV)) &&
2169                    (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )
2170                    iMinSAD -= MV8_00_BIAS;
2171    
2172    
2173    /* Step 6: If MinSAD <= thresa goto Step 10.
2174       If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.
2175    */
2176    
2177            if ((iMinSAD <= threshA) ||
2178                    (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&
2179                     ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {
2180                    if (MotionFlags & PMV_QUICKSTOP16)
2181                            goto PMVfast8_Terminate_without_Refine;
2182                    if (MotionFlags & PMV_EARLYSTOP16)
2183                            goto PMVfast8_Terminate_with_Refine;
2184            }
2185    
2186    /************ (Diamond Search)  **************/
2187    /*
2188       Step 7: Perform Diamond search, with either the small or large diamond.
2189       If Found=2 only examine one Diamond pattern, and afterwards goto step 10
2190       Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.
2191       If center then goto step 10.
2192       Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.
2193       Refine by using small diamond and goto step 10.
2194    */
2195    
2196            backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */
2197    
2198    /* default: use best prediction as starting point for one call of PMVfast_MainSearch */
2199            iSAD =
2200                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,
2201                                                      currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,
2202                                                      min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,
2203                                                      iQuant, iFound);
2204    
2205            if (iSAD < iMinSAD) {
2206                    *currMV = newMV;
2207                    iMinSAD = iSAD;
2208            }
2209    
2210            if (MotionFlags & PMV_EXTSEARCH8) {
2211    /* extended: search (up to) two more times: orignal prediction and (0,0) */
2212    
2213                    if (!(MVequal(pmv[0], backupMV))) {
2214                            iSAD =
2215                                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,
2216                                                                      pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,
2217                                                                      min_dx, max_dx, min_dy, max_dy, iEdgedWidth,
2218                                                                      iDiamondSize, iFcode, iQuant, iFound);
2219    
2220                            if (iSAD < iMinSAD) {
2221                                    *currMV = newMV;
2222                                    iMinSAD = iSAD;
2223                            }
2224                    }
2225    
2226                    if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {
2227                            iSAD =
2228                                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,
2229                                                                      iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,
2230                                                                      max_dy, iEdgedWidth, iDiamondSize, iFcode,
2231                                                                      iQuant, iFound);
2232    
2233                            if (iSAD < iMinSAD) {
2234                                    *currMV = newMV;
2235                                    iMinSAD = iSAD;
2236                          }                          }
2237          }          }
         return mask;  
2238  }  }
2239    
2240  static __inline void  /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.
2241  PreparePredictionsP(VECTOR * const pmv, int x, int y, int iWcount,     By performing an optional local half-pixel search, we can refine this result even further.
2242                          int iHcount, const MACROBLOCK * const prevMB, int rrv)  */
2243    
2244      PMVfast8_Terminate_with_Refine:
2245            if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step
2246                    iMinSAD =
2247                            Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,
2248                                                            iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,
2249                                                            iFcode, iQuant, iEdgedWidth);
2250    
2251    
2252      PMVfast8_Terminate_without_Refine:
2253            currPMV->x = currMV->x - center_x;
2254            currPMV->y = currMV->y - center_y;
2255    
2256            return iMinSAD;
2257    }
2258    
2259    int32_t
2260    EPZSSearch16(const uint8_t * const pRef,
2261                             const uint8_t * const pRefH,
2262                             const uint8_t * const pRefV,
2263                             const uint8_t * const pRefHV,
2264                             const IMAGE * const pCur,
2265                             const int x,
2266                             const int y,
2267                            const int start_x,
2268                            const int start_y,
2269                            const int center_x,
2270                            const int center_y,
2271                             const uint32_t MotionFlags,
2272                             const uint32_t iQuant,
2273                             const uint32_t iFcode,
2274                             const MBParam * const pParam,
2275                             const MACROBLOCK * const pMBs,
2276                             const MACROBLOCK * const prevMBs,
2277                             VECTOR * const currMV,
2278                             VECTOR * const currPMV)
2279  {  {
2280            const uint32_t iWcount = pParam->mb_width;
2281            const uint32_t iHcount = pParam->mb_height;
2282    
2283            const int32_t iWidth = pParam->width;
2284            const int32_t iHeight = pParam->height;
2285            const int32_t iEdgedWidth = pParam->edged_width;
2286    
2287            const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;
2288    
2289            int32_t min_dx;
2290            int32_t max_dx;
2291            int32_t min_dy;
2292            int32_t max_dy;
2293    
2294            VECTOR newMV;
2295            VECTOR backupMV;
2296    
2297            VECTOR pmv[4];
2298            int32_t psad[8];
2299    
2300            static MACROBLOCK *oldMBs = NULL;
2301    
2302    //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;
2303            const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;
2304            MACROBLOCK *oldMB = NULL;
2305    
2306             int32_t thresh2;
2307            int32_t bPredEq;
2308            int32_t iMinSAD, iSAD = 9999;
2309    
2310            MainSearch16FuncPtr MainSearchPtr;
2311    
2312            if (oldMBs == NULL) {
2313                    oldMBs = (MACROBLOCK *) calloc(iWcount * iHcount, sizeof(MACROBLOCK));
2314    //      fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));
2315            }
2316            oldMB = oldMBs + x + y * iWcount;
2317    
2318    /* Get maximum range */
2319            get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,
2320                              iFcode);
2321    
2322            if (!(MotionFlags & PMV_HALFPEL16)) {
2323                    min_dx = EVEN(min_dx);
2324                    max_dx = EVEN(max_dx);
2325                    min_dy = EVEN(min_dy);
2326                    max_dy = EVEN(max_dy);
2327            }
2328            /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */
2329            //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);
2330            bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);
2331    
2332    /* Step 4: Calculate SAD around the Median prediction.
2333            MinSAD=SAD
2334            If Motion Vector equal to Previous frame motion vector
2335                    and MinSAD<PrevFrmSAD goto Step 10.
2336            If SAD<=256 goto Step 10.
2337    */
2338    
2339    // Prepare for main loop
2340    
2341            currMV->x = start_x;
2342            currMV->y = start_y;
2343    
2344            if (!(MotionFlags & PMV_HALFPEL16)) {
2345                    currMV->x = EVEN(currMV->x);
2346                    currMV->y = EVEN(currMV->y);
2347            }
2348    
2349            if (currMV->x > max_dx)
2350                    currMV->x = max_dx;
2351            if (currMV->x < min_dx)
2352                    currMV->x = min_dx;
2353            if (currMV->y > max_dy)
2354                    currMV->y = max_dy;
2355            if (currMV->y < min_dy)
2356                    currMV->y = min_dy;
2357    
2358    /***************** This is predictor SET A: only median prediction ******************/
2359    
2360            iMinSAD =
2361                    sad16(cur,
2362                              get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,
2363                                                     iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);
2364            iMinSAD +=
2365                    calc_delta_16(currMV->x - center_x, currMV->y - center_y,
2366                                              (uint8_t) iFcode, iQuant);
2367    
2368    // thresh1 is fixed to 256
2369            if ((iMinSAD < 256) ||
2370                    ((MVequal(*currMV, prevMB->mvs[0])) &&
2371                     ((int32_t) iMinSAD < prevMB->sad16))) {
2372                    if (MotionFlags & PMV_QUICKSTOP16)
2373                            goto EPZS16_Terminate_without_Refine;
2374                    if (MotionFlags & PMV_EARLYSTOP16)
2375                            goto EPZS16_Terminate_with_Refine;
2376            }
2377    
2378    /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/
2379    
2380    // previous frame MV
2381            CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);
2382    
2383    // set threshhold based on Min of Prediction and SAD of collocated block
2384    // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want
2385    
2386            if ((x == 0) && (y == 0)) {
2387                    thresh2 = 512;
2388            } else {
2389    /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */
2390    
2391                    thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;
2392            }
2393    
2394    // MV=(0,0) is often a good choice
2395    
2396            CHECK_MV16_ZERO;
2397    
2398    
2399    // left neighbour, if allowed
2400            if (x != 0) {
2401                    if (!(MotionFlags & PMV_HALFPEL16)) {
2402                            pmv[1].x = EVEN(pmv[1].x);
2403                            pmv[1].y = EVEN(pmv[1].y);
2404                    }
2405                    CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);
2406            }
2407    // top neighbour, if allowed
2408            if (y != 0) {
2409                    if (!(MotionFlags & PMV_HALFPEL16)) {
2410                            pmv[2].x = EVEN(pmv[2].x);
2411                            pmv[2].y = EVEN(pmv[2].y);
2412                    }
2413                    CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);
2414    
2415    // top right neighbour, if allowed
2416                    if ((uint32_t) x != (iWcount - 1)) {
2417                            if (!(MotionFlags & PMV_HALFPEL16)) {
2418                                    pmv[3].x = EVEN(pmv[3].x);
2419                                    pmv[3].y = EVEN(pmv[3].y);
2420                            }
2421                            CHECK_MV16_CANDIDATE(pmv[3].x, pmv[3].y);
2422                    }
2423            }
2424    
2425    /* Terminate if MinSAD <= T_2
2426       Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]
2427    */
2428    
2429            if ((iMinSAD <= thresh2)
2430                    || (MVequal(*currMV, prevMB->mvs[0]) &&
2431                            ((int32_t) iMinSAD <= prevMB->sad16))) {
2432                    if (MotionFlags & PMV_QUICKSTOP16)
2433                            goto EPZS16_Terminate_without_Refine;
2434                    if (MotionFlags & PMV_EARLYSTOP16)
2435                            goto EPZS16_Terminate_with_Refine;
2436            }
2437    
2438    /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/
2439    
2440            backupMV = prevMB->mvs[0];      // collocated MV
2441            backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x);     // acceleration X
2442            backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y);     // acceleration Y
2443    
2444            CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y);
2445    
2446    // left neighbour
2447            if (x != 0)
2448                    CHECK_MV16_CANDIDATE((prevMB - 1)->mvs[0].x, (prevMB - 1)->mvs[0].y);
2449    
2450    // top neighbour
2451            if (y != 0)
2452                    CHECK_MV16_CANDIDATE((prevMB - iWcount)->mvs[0].x,
2453                                                             (prevMB - iWcount)->mvs[0].y);
2454    
2455  //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself  // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs
         if (rrv) { iWcount /= 2; iHcount /= 2; }  
2456    
2457          if ( (y != 0) && (x < (iWcount-1)) ) {          // [5] top-right neighbour          if ((uint32_t) x != iWcount - 1)
2458                  pmv[5].x = EVEN(pmv[3].x);                  CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);
                 pmv[5].y = EVEN(pmv[3].y);  
         } else pmv[5].x = pmv[5].y = 0;  
2459    
2460          if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }// pmv[3] is left neighbour  // bottom neighbour, dito
2461          else pmv[3].x = pmv[3].y = 0;          if ((uint32_t) y != iHcount - 1)
2462                    CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,
2463                                                             (prevMB + iWcount)->mvs[0].y);
2464    
2465          if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }// [4] top neighbour  /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */
2466          else pmv[4].x = pmv[4].y = 0;          if (iMinSAD <= thresh2) {
2467                    if (MotionFlags & PMV_QUICKSTOP16)
2468                            goto EPZS16_Terminate_without_Refine;
2469                    if (MotionFlags & PMV_EARLYSTOP16)
2470                            goto EPZS16_Terminate_with_Refine;
2471            }
2472    
2473    /************ (if Diamond Search)  **************/
2474    
2475            backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */
2476    
2477            if (MotionFlags & PMV_USESQUARES16)
2478                    MainSearchPtr = Square16_MainSearch;
2479            else
2480             if (MotionFlags & PMV_ADVANCEDDIAMOND16)
2481                    MainSearchPtr = AdvDiamond16_MainSearch;
2482            else
2483                    MainSearchPtr = Diamond16_MainSearch;
2484    
2485    /* default: use best prediction as starting point for one call of PMVfast_MainSearch */
2486    
2487            iSAD =
2488                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,
2489                                                      currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,
2490                                                      min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);
2491    
2492            if (iSAD < iMinSAD) {
2493                    *currMV = newMV;
2494                    iMinSAD = iSAD;
2495            }
2496    
2497    
2498            if (MotionFlags & PMV_EXTSEARCH16) {
2499    /* extended mode: search (up to) two more times: orignal prediction and (0,0) */
2500    
2501                    if (!(MVequal(pmv[0], backupMV))) {
2502                            iSAD =
2503                                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,
2504                                                                      pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,
2505                                                                      min_dx, max_dx, min_dy, max_dy, iEdgedWidth,
2506                                                                      2, iFcode, iQuant, 0);
2507                    }
2508    
2509                    if (iSAD < iMinSAD) {
2510                            *currMV = newMV;
2511                            iMinSAD = iSAD;
2512                    }
2513    
2514                    if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {
2515                            iSAD =
2516                                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,
2517                                                                      iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,
2518                                                                      max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);
2519    
2520                            if (iSAD < iMinSAD) {
2521                                    *currMV = newMV;
2522                                    iMinSAD = iSAD;
2523                            }
2524                    }
2525            }
2526    
2527          // [1] median prediction  /***************        Choose best MV found     **************/
         pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y);  
2528    
2529          pmv[0].x = pmv[0].y = 0; // [0] is zero; not used in the loop (checked before) but needed here for make_mask    EPZS16_Terminate_with_Refine:
2530            if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step
2531                    iMinSAD =
2532                            Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,
2533                                                             iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,
2534                                                             iFcode, iQuant, iEdgedWidth);
2535    
2536          pmv[2].x = EVEN(prevMB->mvs[0].x); // [2] is last frame    EPZS16_Terminate_without_Refine:
         pmv[2].y = EVEN(prevMB->mvs[0].y);  
2537    
2538          if ((x < iWcount-1) && (y < iHcount-1)) {          *oldMB = *prevMB;
                 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;  
2539    
2540          if (rrv) {          currPMV->x = currMV->x - center_x;
2541                  int i;          currPMV->y = currMV->y - center_y;
2542                  for (i = 0; i < 7; i++) {          return iMinSAD;
                         pmv[i].x = RRV_MV_SCALEUP(pmv[i].x);  
                         pmv[i].y = RRV_MV_SCALEUP(pmv[i].y);  
                 }  
         }  
2543  }  }
2544    
2545  static void  
2546  SearchP(const IMAGE * const pRef,  int32_t
2547    EPZSSearch8(const uint8_t * const pRef,
2548                  const uint8_t * const pRefH,                  const uint8_t * const pRefH,
2549                  const uint8_t * const pRefV,                  const uint8_t * const pRefV,
2550                  const uint8_t * const pRefHV,                  const uint8_t * const pRefHV,
2551                  const IMAGE * const pCur,                  const IMAGE * const pCur,
2552                  const int x,                  const int x,
2553                  const int y,                  const int y,
2554                            const int start_x,
2555                            const int start_y,
2556                            const int center_x,
2557                            const int center_y,
2558                  const uint32_t MotionFlags,                  const uint32_t MotionFlags,
2559                  const uint32_t iQuant,                  const uint32_t iQuant,
2560                  SearchData * const Data,                          const uint32_t iFcode,
2561                  const MBParam * const pParam,                  const MBParam * const pParam,
2562                  const MACROBLOCK * const pMBs,                  const MACROBLOCK * const pMBs,
2563                  const MACROBLOCK * const prevMBs,                  const MACROBLOCK * const prevMBs,
2564                  int inter4v,                          VECTOR * const currMV,
2565                  MACROBLOCK * const pMB)                          VECTOR * const currPMV)
2566  {  {
2567    /* Please not that EPZS might not be a good choice for 8x8-block motion search ! */
2568    
2569          int i, iDirection = 255, mask, threshA;          const uint32_t iWcount = pParam->mb_width;
2570          VECTOR pmv[7];          const int32_t iWidth = pParam->width;
2571            const int32_t iHeight = pParam->height;
2572          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,          const int32_t iEdgedWidth = pParam->edged_width;
                                                 pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);  
   
         get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);  
2573    
2574          Data->temp[5] = Data->temp[6] = 0; // chroma-sad cache          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;
         i = Data->rrv ? 2 : 1;  
         Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16*i;  
         Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;  
         Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;  
2575    
2576          Data->Ref = pRef->y + (x + Data->iEdgedWidth*y) * 16*i;          int32_t iDiamondSize = 1;
         Data->RefH = pRefH + (x + Data->iEdgedWidth*y) * 16*i;  
         Data->RefV = pRefV + (x + Data->iEdgedWidth*y) * 16*i;  
         Data->RefHV = pRefHV + (x + Data->iEdgedWidth*y) * 16*i;  
         Data->RefCV = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;  
         Data->RefCU = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;  
2577    
2578          Data->lambda16 = lambda_vec16[iQuant];          int32_t min_dx;
2579          Data->lambda8 = lambda_vec8[iQuant];          int32_t max_dx;
2580          Data->qpel_precision = 0;          int32_t min_dy;
2581            int32_t max_dy;
2582    
2583          if (pMB->dquant != NO_CHANGE) inter4v = 0;          VECTOR newMV;
2584            VECTOR backupMV;
2585    
2586          for(i = 0; i < 5; i++)          VECTOR pmv[4];
2587                  Data->currentMV[i].x = Data->currentMV[i].y = 0;          int32_t psad[8];
2588    
2589          if (Data->qpel) Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);          const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);
         else Data->predMV = pmv[0];  
2590    
2591          i = d_mv_bits(0, 0, Data->predMV, Data->iFcode, 0, 0);  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;
2592          Data->iMinSAD[0] = pMB->sad16 + ((Data->lambda16 * i * pMB->sad16)>>10);          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;
         Data->iMinSAD[1] = pMB->sad8[0] + ((Data->lambda8 * i * (pMB->sad8[0]+NEIGH_8X8_BIAS)) >> 10);  
         Data->iMinSAD[2] = pMB->sad8[1];  
         Data->iMinSAD[3] = pMB->sad8[2];  
         Data->iMinSAD[4] = pMB->sad8[3];  
2593    
2594          if (x | y) {          int32_t bPredEq;
2595                  threshA = Data->temp[0]; // that's when we keep this SAD atm          int32_t iMinSAD, iSAD = 9999;
                 if (threshA < 512) threshA = 512;  
                 else if (threshA > 1024) threshA = 1024;  
         } else threshA = 512;  
2596    
2597          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,          MainSearch8FuncPtr MainSearchPtr;
                                         prevMBs + x + y * pParam->mb_width, Data->rrv);  
2598    
2599          if (!Data->rrv) {  /* Get maximum range */
2600                  if (inter4v | Data->chroma) CheckCandidate = CheckCandidate16;          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,
2601                          else CheckCandidate = CheckCandidate16no4v; //for extra speed                            iFcode);
         } else CheckCandidate = CheckCandidate32;  
2602    
2603  /* main loop. checking all predictions (but first, which is 0,0 and has been checked in MotionEstimation())*/  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */
2604    
2605          for (i = 1; i < 7; i++) {          if (!(MotionFlags & PMV_HALFPEL8)) {
2606                  if (!(mask = make_mask(pmv, i)) ) continue;                  min_dx = EVEN(min_dx);
2607                  (*CheckCandidate)(pmv[i].x, pmv[i].y, mask, &iDirection, Data);                  max_dx = EVEN(max_dx);
2608                  if (Data->iMinSAD[0] <= threshA) break;                  min_dy = EVEN(min_dy);
2609                    max_dy = EVEN(max_dy);
2610          }          }
2611            /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */
2612            //bPredEq = get_pmvdata(pMBs, x >> 1, y >> 1, iWcount, iSubBlock, pmv[0].x, pmv[0].y, psad);
2613            bPredEq = get_pmvdata2(pMBs, iWcount, 0, x >> 1, y >> 1, iSubBlock, pmv, psad);
2614    
         if ((Data->iMinSAD[0] <= threshA) ||  
                         (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&  
                         (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16)))  
                 inter4v = 0;  
         else {  
2615    
2616                  MainSearchFunc * MainSearchPtr;  /* Step 4: Calculate SAD around the Median prediction.
2617                  if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;          MinSAD=SAD
2618                  else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;          If Motion Vector equal to Previous frame motion vector
2619                          else MainSearchPtr = DiamondSearch;                  and MinSAD<PrevFrmSAD goto Step 10.
2620            If SAD<=256 goto Step 10.
2621                  (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, iDirection);  */
2622    
2623  /* extended search, diamond starting in 0,0 and in prediction.  // Prepare for main loop
         note that this search is/might be done in halfpel positions,  
         which makes it more different than the diamond above */  
2624    
                 if (MotionFlags & PMV_EXTSEARCH16) {  
                         int32_t bSAD;  
                         VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];  
                         if (Data->rrv) {  
                                 startMV.x = RRV_MV_SCALEUP(startMV.x);  
                                 startMV.y = RRV_MV_SCALEUP(startMV.y);  
                         } else  
                                 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;  
2625    
2626                                  (*CheckCandidate)(startMV.x, startMV.y, 255, &iDirection, Data);          if (!(MotionFlags & PMV_HALFPEL8)) {
2627                                  (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);                  currMV->x = EVEN(currMV->x);
2628                                  if (bSAD < Data->iMinSAD[0]) {                  currMV->y = EVEN(currMV->y);
                                         Data->currentMV[0] = backupMV;  
                                         Data->iMinSAD[0] = bSAD; }  
2629                          }                          }
2630    
2631                          backupMV = Data->currentMV[0];          if (currMV->x > max_dx)
2632                          if (MotionFlags & PMV_HALFPELREFINE16 && !Data->rrv) startMV.x = startMV.y = 1;                  currMV->x = max_dx;
2633                          else startMV.x = startMV.y = 0;          if (currMV->x < min_dx)
2634                          if (!(MVequal(startMV, backupMV))) {                  currMV->x = min_dx;
2635                                  bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;          if (currMV->y > max_dy)
2636                    currMV->y = max_dy;
2637            if (currMV->y < min_dy)
2638                    currMV->y = min_dy;
2639    
2640                                  (*CheckCandidate)(startMV.x, startMV.y, 255, &iDirection, Data);  /***************** This is predictor SET A: only median prediction ******************/
                                 (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);  
                                 if (bSAD < Data->iMinSAD[0]) {  
                                         Data->currentMV[0] = backupMV;  
                                         Data->iMinSAD[0] = bSAD; }  
                         }  
                 }  
         }  
2641    
         if (MotionFlags & PMV_HALFPELREFINE16) SubpelRefine(Data);  
2642    
2643          for(i = 0; i < 5; i++) {          iMinSAD =
2644                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // initialize qpel vectors                  sad8(cur,
2645                  Data->currentQMV[i].y = 2 * Data->currentMV[i].y;                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,
2646          }                                                  iEdgedWidth), iEdgedWidth);
2647            iMinSAD +=
2648                    calc_delta_8(currMV->x - center_x, currMV->y - center_y,
2649                                             (uint8_t) iFcode, iQuant);
2650    
         if (Data->qpel && MotionFlags & PMV_QUARTERPELREFINE16) {  
                 Data->qpel_precision = 1;  
                 get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,  
                                 pParam->width, pParam->height, Data->iFcode, 1, 0);  
2651    
2652                  SubpelRefine(Data);  // thresh1 is fixed to 256
2653            if (iMinSAD < 256 / 4) {
2654                    if (MotionFlags & PMV_QUICKSTOP8)
2655                            goto EPZS8_Terminate_without_Refine;
2656                    if (MotionFlags & PMV_EARLYSTOP8)
2657                            goto EPZS8_Terminate_with_Refine;
2658          }          }
2659    
2660          if (Data->iMinSAD[0] < (int32_t)iQuant * 30) inter4v = 0;  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/
         if (inter4v) {  
                 SearchData Data8;  
                 memcpy(&Data8, Data, sizeof(SearchData)); //quick copy of common data  
2661    
                 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);  
2662    
2663                  if (Data->chroma) {  // MV=(0,0) is often a good choice
2664                          int sumx = 0, sumy = 0;          CHECK_MV8_ZERO;
                         const int div = 1 + Data->qpel;  
                         const VECTOR * const mv = Data->qpel ? pMB->qmvs : pMB->mvs;  
2665    
2666                          for (i = 0; i < 4; i++) {  // previous frame MV
2667                                  sumx += mv[i].x / div;          CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x, prevMB->mvs[iSubBlock].y);
                                 sumy += mv[i].y / div;  
                         }  
2668    
2669                          Data->iMinSAD[1] += ChromaSAD(  (sumx >> 3) + roundtab_76[sumx & 0xf],  // left neighbour, if allowed
2670                                                                                          (sumy >> 3) + roundtab_76[sumy & 0xf], Data);          if (psad[1] != MV_MAX_ERROR) {
2671                    if (!(MotionFlags & PMV_HALFPEL8)) {
2672                            pmv[1].x = EVEN(pmv[1].x);
2673                            pmv[1].y = EVEN(pmv[1].y);
2674                  }                  }
2675                    CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);
2676          }          }
2677    // top neighbour, if allowed
2678          if (Data->rrv) {          if (psad[2] != MV_MAX_ERROR) {
2679                          Data->currentMV[0].x = RRV_MV_SCALEDOWN(Data->currentMV[0].x);                  if (!(MotionFlags & PMV_HALFPEL8)) {
2680                          Data->currentMV[0].y = RRV_MV_SCALEDOWN(Data->currentMV[0].y);                          pmv[2].x = EVEN(pmv[2].x);
2681                            pmv[2].y = EVEN(pmv[2].y);
2682          }          }
2683                    CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);
2684    
2685          if (!(inter4v) ||  // top right neighbour, if allowed
2686                  (Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +                  if (psad[3] != MV_MAX_ERROR) {
2687                          Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {                          if (!(MotionFlags & PMV_HALFPEL8)) {
2688  // INTER MODE                                  pmv[3].x = EVEN(pmv[3].x);
2689                  pMB->mode = MODE_INTER;                                  pmv[3].y = EVEN(pmv[3].y);
                 pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];  
                 pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = Data->iMinSAD[0];  
   
                 if(Data->qpel) {  
                         pMB->qmvs[0] = pMB->qmvs[1]  
                                 = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];  
                         pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;  
                         pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;  
                 } else {  
                         pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;  
                         pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;  
2690                  }                  }
2691          } else {                          CHECK_MV8_CANDIDATE(pmv[3].x, pmv[3].y);
 // 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;  
2692          }          }
2693  }  }
2694    
2695  static void  /*  // this bias is zero anyway, at the moment!
 Search8(const SearchData * const OldData,  
                 const int x, const int y,  
                 const uint32_t MotionFlags,  
                 const MBParam * const pParam,  
                 MACROBLOCK * const pMB,  
                 const MACROBLOCK * const pMBs,  
                 const int block,  
                 SearchData * const Data)  
 {  
         int i = 0;  
         Data->iMinSAD = OldData->iMinSAD + 1 + block;  
         Data->currentMV = OldData->currentMV + 1 + block;  
         Data->currentQMV = OldData->currentQMV + 1 + block;  
   
         if(Data->qpel) {  
                 Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);  
                 if (block != 0) i = d_mv_bits(  Data->currentQMV->x, Data->currentQMV->y,  
                                                                                 Data->predMV, Data->iFcode, 0, 0);  
         } else {  
                 Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);  
                 if (block != 0) i = d_mv_bits(  Data->currentMV->x, Data->currentMV->y,  
                                                                                 Data->predMV, Data->iFcode, 0, Data->rrv);  
         }  
2696    
2697          *(Data->iMinSAD) += (Data->lambda8 * i * (*Data->iMinSAD + NEIGH_8X8_BIAS))>>10;          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)
2698                    iMinSAD -= MV8_00_BIAS;
2699    
2700    */
2701    
2702          if (MotionFlags & (PMV_EXTSEARCH8|PMV_HALFPELREFINE8|PMV_QUARTERPELREFINE8)) {  /* Terminate if MinSAD <= T_2
2703                  if (Data->rrv) i = 2; else i = 1;     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]
2704    */
2705    
2706                  Data->Ref = OldData->Ref + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));          if (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */
2707                  Data->RefH = OldData->RefH + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));                  if (MotionFlags & PMV_QUICKSTOP8)
2708                  Data->RefV = OldData->RefV + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));                          goto EPZS8_Terminate_without_Refine;
2709                  Data->RefHV = OldData->RefHV + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));                  if (MotionFlags & PMV_EARLYSTOP8)
2710                            goto EPZS8_Terminate_with_Refine;
2711            }
2712    
2713                  Data->Cur = OldData->Cur + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));  /************ (Diamond Search)  **************/
                 Data->qpel_precision = 0;  
2714    
2715                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */
                                         pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);  
2716    
2717                  if (!Data->rrv) CheckCandidate = CheckCandidate8;          if (!(MotionFlags & PMV_HALFPELDIAMOND8))
2718                  else CheckCandidate = CheckCandidate16no4v;                  iDiamondSize *= 2;
2719    
2720                  if (MotionFlags & PMV_EXTSEARCH8) {  /* default: use best prediction as starting point for one call of EPZS_MainSearch */
                         int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD  
2721    
2722                          MainSearchFunc *MainSearchPtr;  // there is no EPZS^2 for inter4v at the moment
                         if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;  
                                 else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;  
                                         else MainSearchPtr = DiamondSearch;  
2723    
2724                          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);    if (MotionFlags & PMV_USESQUARES8)
2725          MainSearchPtr = Square8_MainSearch;
2726      else
2727    
2728                          if(*(Data->iMinSAD) < temp_sad) {          if (MotionFlags & PMV_ADVANCEDDIAMOND8)
2729                                          Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector                  MainSearchPtr = AdvDiamond8_MainSearch;
2730                                          Data->currentQMV->y = 2 * Data->currentMV->y;          else
2731                          }                  MainSearchPtr = Diamond8_MainSearch;
                 }  
2732    
2733                  if (MotionFlags & PMV_HALFPELREFINE8) {          iSAD =
2734                          int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,
2735                                                      currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,
2736                                                      min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,
2737                                                      iQuant, 0);
2738    
                         SubpelRefine(Data); // perform halfpel refine of current best vector  
2739    
2740                          if(*(Data->iMinSAD) < temp_sad) { // we have found a better match          if (iSAD < iMinSAD) {
2741                                  Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector                  *currMV = newMV;
2742                                  Data->currentQMV->y = 2 * Data->currentMV->y;                  iMinSAD = iSAD;
                         }  
2743                  }                  }
2744    
2745                  if (Data->qpel && MotionFlags & PMV_QUARTERPELREFINE8) {          if (MotionFlags & PMV_EXTSEARCH8) {
2746                                  Data->qpel_precision = 1;  /* extended mode: search (up to) two more times: orignal prediction and (0,0) */
                                 get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,  
                                         pParam->width, pParam->height, Data->iFcode, 1, 0);  
                                 SubpelRefine(Data);  
                 }  
         }  
2747    
2748          if (Data->rrv) {                  if (!(MVequal(pmv[0], backupMV))) {
2749                          Data->currentMV->x = RRV_MV_SCALEDOWN(Data->currentMV->x);                          iSAD =
2750                          Data->currentMV->y = RRV_MV_SCALEDOWN(Data->currentMV->y);                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,
2751          }                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,
2752                                                                      min_dx, max_dx, min_dy, max_dy, iEdgedWidth,
2753                                                                      iDiamondSize, iFcode, iQuant, 0);
2754    
2755          if(Data->qpel) {                          if (iSAD < iMinSAD) {
2756                  pMB->pmvs[block].x = Data->currentQMV->x - Data->predMV.x;                                  *currMV = newMV;
2757                  pMB->pmvs[block].y = Data->currentQMV->y - Data->predMV.y;                                  iMinSAD = iSAD;
                 pMB->qmvs[block] = *Data->currentQMV;  
         } else {  
                 pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;  
                 pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;  
2758          }          }
   
         pMB->mvs[block] = *Data->currentMV;  
         pMB->sad8[block] = 4 * *Data->iMinSAD;  
2759  }  }
2760    
2761  /* motion estimation for B-frames */                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {
2762                            iSAD =
2763                                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,
2764                                                                      iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,
2765                                                                      max_dy, iEdgedWidth, iDiamondSize, iFcode,
2766                                                                      iQuant, 0);
2767    
2768  static __inline VECTOR                          if (iSAD < iMinSAD) {
2769  ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)                                  *currMV = newMV;
2770  {                                  iMinSAD = iSAD;
2771  /* the stupidiest function ever */                          }
2772          return (mode == MODE_FORWARD ? pMB->mvs[0] : pMB->b_mvs[0]);                  }
2773  }  }
2774    
2775  static void __inline  /***************        Choose best MV found     **************/
 PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,  
                                                         const uint32_t iWcount,  
                                                         const MACROBLOCK * const pMB,  
                                                         const uint32_t mode_curr)  
 {  
   
         // [0] is prediction  
         pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);  
   
         pmv[1].x = pmv[1].y = 0; // [1] is zero  
   
         pmv[2] = ChoosePred(pMB, mode_curr);  
         pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);  
   
         if ((y != 0)&&(x != (int)(iWcount+1))) {                        // [3] top-right neighbour  
                 pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);  
                 pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);  
         } else pmv[3].x = pmv[3].y = 0;  
2776    
2777          if (y != 0) {    EPZS8_Terminate_with_Refine:
2778                  pmv[4] = ChoosePred(pMB-iWcount, mode_curr);          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step
2779                  pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);                  iMinSAD =
2780          } else pmv[4].x = pmv[4].y = 0;                          Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,
2781                                                            iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,
2782                                                            iFcode, iQuant, iEdgedWidth);
2783    
2784          if (x != 0) {    EPZS8_Terminate_without_Refine:
                 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;  
2785    
2786          if (x != 0 && y != 0) {          currPMV->x = currMV->x - center_x;
2787                  pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);          currPMV->y = currMV->y - center_y;
2788                  pmv[6].x = EVEN(pmv[6].x); pmv[6].y = EVEN(pmv[6].y);          return iMinSAD;
         } else pmv[6].x = pmv[6].y = 0;  
2789  }  }
2790    
2791    
2792  /* search backward or forward */  
2793  static void  int32_t
2794  SearchBF(       const IMAGE * const pRef,  PMVfastIntSearch16(const uint8_t * const pRef,
2795                          const uint8_t * const pRefH,                          const uint8_t * const pRefH,
2796                          const uint8_t * const pRefV,                          const uint8_t * const pRefV,
2797                          const uint8_t * const pRefHV,                          const uint8_t * const pRefHV,
2798                          const IMAGE * const pCur,                          const IMAGE * const pCur,
2799                          const int x, const int y,                                  const int x,
2800                                    const int y,
2801                                    const int start_x,              /* start should be most likely vector */
2802                                    const int start_y,
2803                                    const int center_x,             /* center is from where length of MVs is measured */
2804                                    const int center_y,
2805                          const uint32_t MotionFlags,                          const uint32_t MotionFlags,
2806                                    const uint32_t iQuant,
2807                          const uint32_t iFcode,                          const uint32_t iFcode,
2808                          const MBParam * const pParam,                          const MBParam * const pParam,
2809                          MACROBLOCK * const pMB,                                  const MACROBLOCK * const pMBs,
2810                          const VECTOR * const predMV,                                  const MACROBLOCK * const prevMBs,
2811                          int32_t * const best_sad,                                  VECTOR * const currMV,
2812                          const int32_t mode_current,                                  VECTOR * const currPMV)
                         SearchData * const Data)  
2813  {  {
2814            const uint32_t iWcount = pParam->mb_width;
2815            const int32_t iWidth = pParam->width;
2816            const int32_t iHeight = pParam->height;
2817            const int32_t iEdgedWidth = pParam->edged_width;
2818    
2819          int i, iDirection = 255, mask;          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;
2820          VECTOR pmv[7];          const VECTOR zeroMV = { 0, 0 };
         MainSearchFunc *MainSearchPtr;  
         *Data->iMinSAD = MV_MAX_ERROR;  
         Data->iFcode = iFcode;  
         Data->qpel_precision = 0;  
         Data->temp[5] = Data->temp[6] = Data->temp[7] = 256*4096; // reset chroma-sad cache  
2821    
2822          Data->Ref = pRef->y + (x + y * Data->iEdgedWidth) * 16;          int32_t iDiamondSize;
         Data->RefH = pRefH + (x + y * Data->iEdgedWidth) * 16;  
         Data->RefV = pRefV + (x + y * Data->iEdgedWidth) * 16;  
         Data->RefHV = pRefHV + (x + y * Data->iEdgedWidth) * 16;  
         Data->RefCU = pRef->u + (x + y * Data->iEdgedWidth/2) * 8;  
         Data->RefCV = pRef->v + (x + y * Data->iEdgedWidth/2) * 8;  
2823    
2824          Data->predMV = *predMV;          int32_t min_dx;
2825            int32_t max_dx;
2826            int32_t min_dy;
2827            int32_t max_dy;
2828    
2829          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,          int32_t iFound;
                                 pParam->width, pParam->height, iFcode - Data->qpel, 0, 0);  
2830    
2831          pmv[0] = Data->predMV;          VECTOR newMV;
2832          if (Data->qpel) { pmv[0].x /= 2; pmv[0].y /= 2; }          VECTOR backupMV;
2833    
2834          PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);          VECTOR pmv[4];
2835            int32_t psad[4];
2836    
2837          Data->currentMV->x = Data->currentMV->y = 0;          MainSearch16FuncPtr MainSearchPtr;
         CheckCandidate = CheckCandidate16no4v;  
2838    
2839  // main loop. checking all predictions          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;
2840          for (i = 0; i < 7; i++) {          MACROBLOCK *const pMB = pMBs + x + y * iWcount;
                 if (!(mask = make_mask(pmv, i)) ) continue;  
                 CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, Data);  
         }  
2841    
2842          if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;          int32_t threshA, threshB;
2843          else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;          int32_t bPredEq;
2844                  else MainSearchPtr = DiamondSearch;          int32_t iMinSAD, iSAD;
2845    
         (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, iDirection);  
2846    
2847          SubpelRefine(Data);  /* Get maximum range */
2848            get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,
2849                              iFcode);
2850    
2851          if (Data->qpel && *Data->iMinSAD < *best_sad + 300) {  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */
                 Data->currentQMV->x = 2*Data->currentMV->x;  
                 Data->currentQMV->y = 2*Data->currentMV->y;  
                 Data->qpel_precision = 1;  
                 get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,  
                                         pParam->width, pParam->height, iFcode, 1, 0);  
                 SubpelRefine(Data);  
         }  
2852    
2853  // three bits are needed to code backward mode. four for forward          if ((x == 0) && (y == 0)) {
2854                    threshA = 512;
2855                    threshB = 1024;
2856    
2857          if (mode_current == MODE_FORWARD) *Data->iMinSAD += 4 * Data->lambda16;                  bPredEq = 0;
2858          else *Data->iMinSAD += 3 * Data->lambda16;                  psad[0] = psad[1] = psad[2] = psad[3] = 0;
2859                    *currMV = pmv[0] = pmv[1] = pmv[2] = pmv[3] = zeroMV;
2860    
         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;  
2861                  } else {                  } else {
2862                          pMB->pmvs[0].x = Data->currentMV->x - predMV->x;  
2863                          pMB->pmvs[0].y = Data->currentMV->y - predMV->y;                  bPredEq = get_ipmvdata(pMBs, iWcount, 0, x, y, 0, pmv, psad);
2864    
2865                    threshA = psad[0];
2866                    threshB = threshA + 256;
2867                    if (threshA < 512)
2868                            threshA = 512;
2869                    if (threshA > 1024)
2870                            threshA = 1024;
2871                    if (threshB > 1792)
2872                            threshB = 1792;
2873    
2874                    *currMV = pmv[0];                       /* current best := prediction */
2875            }
2876    
2877            iFound = 0;
2878    
2879    /* Step 4: Calculate SAD around the Median prediction.
2880       MinSAD=SAD
2881       If Motion Vector equal to Previous frame motion vector
2882       and MinSAD<PrevFrmSAD goto Step 10.
2883       If SAD<=256 goto Step 10.
2884    */
2885    
2886            if (currMV->x > max_dx) {
2887                    currMV->x = EVEN(max_dx);
2888            }
2889            if (currMV->x < min_dx) {
2890                    currMV->x = EVEN(min_dx);
2891            }
2892            if (currMV->y > max_dy) {
2893                    currMV->y = EVEN(max_dy);
2894                  }                  }
2895                  if (mode_current == MODE_FORWARD) pMB->mvs[0] = *Data->currentMV;          if (currMV->y < min_dy) {
2896                  else pMB->b_mvs[0] = *Data->currentMV;                  currMV->y = EVEN(min_dy);
2897          }          }
2898    
2899          if (mode_current == MODE_FORWARD) *(Data->currentMV+2) = *Data->currentMV;          iMinSAD =
2900          else *(Data->currentMV+1) = *Data->currentMV; //we store currmv for interpolate search                  sad16(cur,
2901  }                            get_iref_mv(pRef, x, y, 16, currMV,
2902                                                     iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);
2903  static void          iMinSAD +=
2904  SkipDecisionB(const IMAGE * const pCur,                  calc_delta_16(currMV->x - center_x, currMV->y - center_y,
2905                                  const IMAGE * const f_Ref,                                            (uint8_t) iFcode, iQuant);
                                 const IMAGE * const b_Ref,  
                                 MACROBLOCK * const pMB,  
                                 const uint32_t x, const uint32_t y,  
                                 const SearchData * const Data)  
 {  
         int dx = 0, dy = 0, b_dx = 0, b_dy = 0;  
         int32_t sum;  
         const int div = 1 + Data->qpel;  
         int k;  
         const uint32_t stride = Data->iEdgedWidth/2;  
 //this is not full chroma compensation, only it's fullpel approximation. should work though  
2906    
2907          for (k = 0; k < 4; k++) {          if ((iMinSAD < 256) ||
2908                  dy += Data->directmvF[k].y / div;                  ((MVequal(*currMV, prevMB->i_mvs[0])) &&
2909                  dx += Data->directmvF[0].x / div;                   ((int32_t) iMinSAD < prevMB->i_sad16))) {
2910                  b_dy += Data->directmvB[0].y / div;                  if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode
2911                  b_dx += Data->directmvB[0].x / div;                  {
2912          }                          if (!MVzero(*currMV)) {
2913                                    iMinSAD += MV16_00_BIAS;
2914          dy = (dy >> 3) + roundtab_76[dy & 0xf];                                  CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures
2915          dx = (dx >> 3) + roundtab_76[dx & 0xf];                                  iMinSAD -= MV16_00_BIAS;
2916          b_dy = (b_dy >> 3) + roundtab_76[b_dy & 0xf];                          }
2917          b_dx = (b_dx >> 3) + roundtab_76[b_dx & 0xf];                  }
   
         sum = sad8bi(pCur->u + 8 * x + 8 * y * stride,  
                                         f_Ref->u + (y*8 + dy/2) * stride + x*8 + dx/2,  
                                         b_Ref->u + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,  
                                         stride);  
   
         if (sum >= 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) return; //no skip  
   
         sum += sad8bi(pCur->v + 8*x + 8 * y * stride,  
                                         f_Ref->v + (y*8 + dy/2) * stride + x*8 + dx/2,  
                                         b_Ref->v + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,  
                                         stride);  
2918    
2919          if (sum < 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) pMB->mode = MODE_DIRECT_NONE_MV; //skipped                  if (MotionFlags & PMV_EARLYSTOP16)
2920                            goto PMVfastInt16_Terminate_with_Refine;
2921  }  }
2922    
 static __inline uint32_t  
 SearchDirect(const IMAGE * const f_Ref,  
                                 const uint8_t * const f_RefH,  
                                 const uint8_t * const f_RefV,  
                                 const uint8_t * const f_RefHV,  
                                 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 = (x + Data->iEdgedWidth*y) * 16;  
         MainSearchFunc *MainSearchPtr;  
   
         *Data->iMinSAD = 256*4096;  
         Data->Ref = f_Ref->y + k;  
         Data->RefH = f_RefH + k;  
         Data->RefV = f_RefV + k;  
         Data->RefHV = f_RefHV + k;  
         Data->bRef = b_Ref->y + k;  
         Data->bRefH = b_RefH + k;  
         Data->bRefV = b_RefV + k;  
         Data->bRefHV = b_RefHV + k;  
         Data->RefCU = f_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;  
         Data->RefCV = f_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;  
         Data->b_RefCU = b_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;  
         Data->b_RefCV = b_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;  
   
         k = Data->qpel ? 4 : 2;  
         Data->max_dx = k * (pParam->width - x * 16);  
         Data->max_dy = k * (pParam->height - y * 16);  
         Data->min_dx = -k * (16 + x * 16);  
         Data->min_dy = -k * (16 + y * 16);  
2923    
2924          Data->referencemv = Data->qpel ? b_mb->qmvs : b_mb->mvs;  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion
2925          Data->qpel_precision = 0;     vector of the median.
2926       If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2
2927    */
2928    
2929          for (k = 0; k < 4; k++) {          if ((bPredEq) && (MVequal(pmv[0], prevMB->i_mvs[0])))
2930                  pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);                  iFound = 2;
                 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;  
2931    
2932                  if ( (pMB->b_mvs[k].x > Data->max_dx) | (pMB->b_mvs[k].x < Data->min_dx)  /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.
2933                          | (pMB->b_mvs[k].y > Data->max_dy) | (pMB->b_mvs[k].y < Data->min_dy) ) {     Otherwise select large Diamond Search.
2934    */
2935    
2936                          *best_sad = 256*4096; // in that case, we won't use direct mode          if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))
2937                          pMB->mode = MODE_DIRECT; // just to make sure it doesn't say "MODE_DIRECT_NONE_MV"                  iDiamondSize = 2;               // halfpel units!
2938                          pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;          else
2939                          return 256*4096;                  iDiamondSize = 4;               // halfpel units!
                 }  
                 if (b_mb->mode != MODE_INTER4V) {  
                         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;  
                 }  
         }  
2940    
2941          CheckCandidate = b_mb->mode == MODE_INTER4V ? CheckCandidateDirect : CheckCandidateDirectno4v;  /*
2942       Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.
2943       Also calculate (0,0) but do not subtract offset.
2944       Let MinSAD be the smallest SAD up to this point.
2945       If MV is (0,0) subtract offset.
2946    */
2947    
2948          (*CheckCandidate)(0, 0, 255, &k, Data);  // (0,0) is often a good choice
2949    
2950            if (!MVzero(pmv[0]))
2951                    CHECK_MV16_ZERO;
2952    
2953    // previous frame MV is always possible
2954    
2955            if (!MVzero(prevMB->i_mvs[0]))
2956                    if (!MVequal(prevMB->i_mvs[0], pmv[0]))
2957                            CHECK_MV16_CANDIDATE(prevMB->i_mvs[0].x, prevMB->i_mvs[0].y);
2958    
2959    // left neighbour, if allowed
2960    
2961            if (!MVzero(pmv[1]))
2962                    if (!MVequal(pmv[1], prevMB->i_mvs[0]))
2963                            if (!MVequal(pmv[1], pmv[0]))
2964                                    CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);
2965    
2966    // top neighbour, if allowed
2967            if (!MVzero(pmv[2]))
2968                    if (!MVequal(pmv[2], prevMB->i_mvs[0]))
2969                            if (!MVequal(pmv[2], pmv[0]))
2970                                    if (!MVequal(pmv[2], pmv[1]))
2971                                            CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);
2972    
2973    // top right neighbour, if allowed
2974                                            if (!MVzero(pmv[3]))
2975                                                    if (!MVequal(pmv[3], prevMB->i_mvs[0]))
2976                                                            if (!MVequal(pmv[3], pmv[0]))
2977                                                                    if (!MVequal(pmv[3], pmv[1]))
2978                                                                            if (!MVequal(pmv[3], pmv[2]))
2979                                                                                    CHECK_MV16_CANDIDATE(pmv[3].x,
2980                                                                                                                             pmv[3].y);
2981    
2982            if ((MVzero(*currMV)) &&
2983                    (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )
2984                    iMinSAD -= MV16_00_BIAS;
2985    
 // initial (fast) skip decision  
         if (*Data->iMinSAD < pMB->quant * INITIAL_SKIP_THRESH * (2 + Data->chroma?1:0)) {  
                 //possible skip  
                 if (Data->chroma) {  
                         pMB->mode = MODE_DIRECT_NONE_MV;  
                         return *Data->iMinSAD; // skip.  
                 } else {  
                         SkipDecisionB(pCur, f_Ref, b_Ref, pMB, x, y, Data);  
                         if (pMB->mode == MODE_DIRECT_NONE_MV) return *Data->iMinSAD; // skip.  
                 }  
         }  
2986    
2987          skip_sad = *Data->iMinSAD;  /* Step 6: If MinSAD <= thresa goto Step 10.
2988       If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.
2989    */
2990    
2991  //      DIRECT MODE DELTA VECTOR SEARCH.          if ((iMinSAD <= threshA) ||
2992  //      This has to be made more effective, but at the moment I'm happy it's running at all                  (MVequal(*currMV, prevMB->i_mvs[0]) &&
2993                     ((int32_t) iMinSAD < prevMB->i_sad16))) {
2994    
2995                    if (MotionFlags & PMV_EARLYSTOP16)
2996                            goto PMVfastInt16_Terminate_with_Refine;
2997            }
2998    
         if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;  
                 else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;  
                         else MainSearchPtr = DiamondSearch;  
2999    
3000          (*MainSearchPtr)(0, 0, Data, 255);  /************ (Diamond Search)  **************/
3001    /*
3002       Step 7: Perform Diamond search, with either the small or large diamond.
3003       If Found=2 only examine one Diamond pattern, and afterwards goto step 10
3004       Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.
3005       If center then goto step 10.
3006       Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.
3007       Refine by using small diamond and goto step 10.
3008    */
3009    
3010          SubpelRefine(Data);          if (MotionFlags & PMV_USESQUARES16)
3011                    MainSearchPtr = Square16_MainSearch;
3012            else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
3013                    MainSearchPtr = AdvDiamond16_MainSearch;
3014            else
3015                    MainSearchPtr = Diamond16_MainSearch;
3016    
3017          *best_sad = *Data->iMinSAD;          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */
3018    
         if (Data->qpel || b_mb->mode == MODE_INTER4V) pMB->mode = MODE_DIRECT;  
         else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation  
3019    
3020          pMB->pmvs[3] = *Data->currentMV;  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */
3021            iSAD =
3022                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,
3023                                                      currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,
3024                                                      min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,
3025                                                      iQuant, iFound);
3026    
3027          for (k = 0; k < 4; k++) {          if (iSAD < iMinSAD) {
3028                  pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;                  *currMV = newMV;
3029                  pMB->b_mvs[k].x = (     (Data->currentMV->x == 0)                  iMinSAD = iSAD;
                                                         ? 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;  
                 }  
   
                 if (b_mb->mode != MODE_INTER4V) {  
                         pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];  
                         pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];  
                         pMB->qmvs[3] = pMB->qmvs[2] = pMB->qmvs[1] = pMB->qmvs[0];  
                         pMB->b_qmvs[3] = pMB->b_qmvs[2] = pMB->b_qmvs[1] = pMB->b_qmvs[0];  
                         break;  
3030                  }                  }
         }  
         return skip_sad;  
 }  
   
 static void  
 SearchInterpolate(const IMAGE * const f_Ref,  
                                 const uint8_t * const f_RefH,  
                                 const uint8_t * const f_RefV,  
                                 const uint8_t * const f_RefHV,  
                                 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 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)  
3031    
3032  {          if (MotionFlags & PMV_EXTSEARCH16) {
3033    /* extended: search (up to) two more times: orignal prediction and (0,0) */
3034    
3035          int iDirection, i, j;                  if (!(MVequal(pmv[0], backupMV))) {
3036          SearchData bData;                          iSAD =
3037                                    (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,
3038          fData->qpel_precision = 0;                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,
3039          memcpy(&bData, fData, sizeof(SearchData)); //quick copy of common data                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,
3040          *fData->iMinSAD = 4096*256;                                                                    iDiamondSize, iFcode, iQuant, iFound);
         bData.currentMV++; bData.currentQMV++;  
         fData->iFcode = bData.bFcode = fcode; fData->bFcode = bData.iFcode = bcode;  
   
         i = (x + y * fData->iEdgedWidth) * 16;  
         bData.bRef = fData->Ref = f_Ref->y + i;  
         bData.bRefH = fData->RefH = f_RefH + i;  
         bData.bRefV = fData->RefV = f_RefV + i;  
         bData.bRefHV = fData->RefHV = f_RefHV + i;  
         bData.Ref = fData->bRef = b_Ref->y + i;  
         bData.RefH = fData->bRefH = b_RefH + i;  
         bData.RefV = fData->bRefV = b_RefV + i;  
         bData.RefHV = fData->bRefHV = b_RefHV + i;  
         bData.b_RefCU = fData->RefCU = f_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;  
         bData.b_RefCV = fData->RefCV = f_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;  
         bData.RefCU = fData->b_RefCU = b_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;  
         bData.RefCV = fData->b_RefCV = b_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;  
   
   
         bData.bpredMV = fData->predMV = *f_predMV;  
         fData->bpredMV = bData.predMV = *b_predMV;  
         fData->currentMV[0] = fData->currentMV[2];  
   
         get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode - fData->qpel, 0, 0);  
         get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode - fData->qpel, 0, 0);  
   
         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_dx;  
         if (fData->currentMV[0].y > fData->max_dy) fData->currentMV[0].y = fData->max_dy;  
         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_dx;  
         if (fData->currentMV[1].y > bData.max_dy) fData->currentMV[1].y = bData.max_dy;  
         if (fData->currentMV[1].y < bData.min_dy) fData->currentMV[1].y = bData.min_dy;  
3041    
3042          CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, 255, &iDirection, fData);                          if (iSAD < iMinSAD) {
3043                                    *currMV = newMV;
3044                                    iMinSAD = iSAD;
3045                            }
3046                    }
3047    
3048  //diamond                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {
3049          do {                          iSAD =
3050                  iDirection = 255;                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,
3051                  // forward MV moves                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,
3052                  i = fData->currentMV[0].x; j = fData->currentMV[0].y;                                                                    max_dy, iEdgedWidth, iDiamondSize, iFcode,
3053                                                                      iQuant, iFound);
3054                  CheckCandidateInt(i + 1, j, 0, &iDirection, fData);  
3055                  CheckCandidateInt(i, j + 1, 0, &iDirection, fData);                          if (iSAD < iMinSAD) {
3056                  CheckCandidateInt(i - 1, j, 0, &iDirection, fData);                                  *currMV = newMV;
3057                  CheckCandidateInt(i, j - 1, 0, &iDirection, fData);                                  iMinSAD = iSAD;
   
                 // 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));  
   
 //qpel refinement  
         if (fData->qpel) {  
                 if (*fData->iMinSAD > *best_sad + 500) return;  
                 CheckCandidate = CheckCandidateInt;  
                 fData->qpel_precision = bData.qpel_precision = 1;  
                 get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode, 1, 0);  
                 get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode, 1, 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;  
                 SubpelRefine(fData);  
                 if (*fData->iMinSAD > *best_sad + 300) return;  
                 fData->currentQMV[2] = fData->currentQMV[0];  
                 SubpelRefine(&bData);  
         }  
   
         *fData->iMinSAD += (2+3) * fData->lambda16; // two bits are needed to code interpolate mode.  
   
         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;  
3058                  }                  }
3059          }          }
3060  }  }
3061    
3062    /*
3063       Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.
3064    */
3065    
3066    PMVfastInt16_Terminate_with_Refine:
3067    
3068            pMB->i_mvs[0] = pMB->i_mvs[1] = pMB->i_mvs[2] = pMB->i_mvs[3] = pMB->i_mv16 = *currMV;
3069            pMB->i_sad8[0] = pMB->i_sad8[1] = pMB->i_sad8[2] = pMB->i_sad8[3] = pMB->i_sad16 = iMinSAD;
3070    
3071            if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step
3072                    iMinSAD =
3073                            Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,
3074                                                             iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,
3075                                                             iFcode, iQuant, iEdgedWidth);
3076    
3077            pmv[0] = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          // get _REAL_ prediction (halfpel possible)
3078    
3079    PMVfastInt16_Terminate_without_Refine:
3080            currPMV->x = currMV->x - center_x;
3081            currPMV->y = currMV->y - center_y;
3082            return iMinSAD;
3083    }
3084    
3085    
3086    
3087    /* ***********************************************************
3088            bvop motion estimation
3089    ***************************************************************/
3090    
3091  void  void
3092  MotionEstimationBVOP(MBParam * const pParam,  MotionEstimationBVOP(MBParam * const pParam,
3093                                           FRAMEINFO * const frame,                                           FRAMEINFO * const frame,
# Line 1790  Line 3100 
3100                                           const IMAGE * const f_refV,                                           const IMAGE * const f_refV,
3101                                           const IMAGE * const f_refHV,                                           const IMAGE * const f_refHV,
3102                                           // backward (future) reference                                           // backward (future) reference
3103                                           const FRAMEINFO * const b_reference,                                           const MACROBLOCK * const b_mbs,
3104                                           const IMAGE * const b_ref,                                           const IMAGE * const b_ref,
3105                                           const IMAGE * const b_refH,                                           const IMAGE * const b_refH,
3106                                           const IMAGE * const b_refV,                                           const IMAGE * const b_refV,
3107                                           const IMAGE * const b_refHV)                                           const IMAGE * const b_refHV)
3108  {  {
3109          uint32_t i, j;          const int mb_width = pParam->mb_width;
3110          int32_t best_sad;          const int mb_height = pParam->mb_height;
3111          uint32_t skip_sad;          const int edged_width = pParam->edged_width;
         int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;  
         const MACROBLOCK * const b_mbs = b_reference->mbs;  
   
         VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/  
   
         const int32_t TRB = time_pp - time_bp;  
         const int32_t TRD = time_pp;  
3112    
3113  // some pre-inintialized data for the rest of the search          const int32_t iWidth = pParam->width;
3114            const int32_t iHeight = pParam->height;
3115    
3116          SearchData Data;          int i, j, k;
         int32_t iMinSAD;  
         VECTOR currentMV[3];  
         VECTOR currentQMV[3];  
         int32_t temp[8];  
         memset(&Data, 0, sizeof(SearchData));  
         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;  
         Data.rounding = 0;  
         Data.chroma = frame->motion_flags & PMV_CHROMA8;  
         Data.temp = temp;  
3117    
3118          Data.RefQ = f_refV->u; // a good place, also used in MC (for similar purpose)          static const VECTOR zeroMV={0,0};
         // 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;  
                                 }  
   
                         Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;  
                         Data.CurU = frame->image.u + (j * Data.iEdgedWidth/2 + i) * 8;  
                         Data.CurV = frame->image.v + (j * Data.iEdgedWidth/2 + i) * 8;  
                         pMB->quant = frame->quant;  
   
 /* direct search comes first, because it (1) checks for SKIP-mode  
         and (2) sets very good predictions for forward and backward search */  
                         skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,  
                                                                         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, 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);  
3119    
3120                          // backward search          int f_sad16;    /* forward (as usual) search */
3121                          SearchBF(b_ref, b_refH->y, b_refV->y, b_refHV->y,          int b_sad16;    /* backward (only in b-frames) search */
3122                                                  &frame->image, i, j,          int i_sad16;    /* interpolated (both direction, b-frames only) */
3123                                                  frame->motion_flags,          int d_sad16;    /* direct mode (assume almost linear motion) */
                                                 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, f_refH->y, f_refV->y, f_refHV->y,  
                                                 b_ref, 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);  
   
 // final skip decision  
                         if ( (skip_sad < frame->quant * MAX_SAD00_FOR_SKIP * 2)  
                                         && ((100*best_sad)/(skip_sad+1) > FINAL_SKIP_THRESH) )  
                                 SkipDecisionB(&frame->image, f_ref, b_ref, pMB, i, j, &Data);  
3124    
3125                          switch (pMB->mode) {          int best_sad;
                                 case MODE_FORWARD:  
                                         f_count++;  
                                         f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];  
                                         break;  
                                 case MODE_BACKWARD:  
                                         b_count++;  
                                         b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];  
                                         break;  
                                 case MODE_INTERPOLATE:  
                                         i_count++;  
                                         f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];  
                                         b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];  
                                         break;  
                                 case MODE_DIRECT:  
                                 case MODE_DIRECT_NO4V:  
                                         d_count++;  
                                 default:  
                                         break;  
                         }  
                 }  
         }  
 }  
3126    
3127  static __inline void          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
3128  MEanalyzeMB (   const uint8_t * const pRef,          VECTOR f_interpolMV, b_interpolMV;
3129                                  const uint8_t * const pCur,          VECTOR pmv_dontcare;
                                 const int x,  
                                 const int y,  
                                 const MBParam * const pParam,  
                                 MACROBLOCK * const pMBs,  
                                 SearchData * const Data)  
 {  
3130    
3131          int i, mask;          int min_dx, max_dx, min_dy, max_dy;
3132          VECTOR pmv[3];          int f_min_dx, f_max_dx, f_min_dy, f_max_dy;
3133          MACROBLOCK * pMB = &pMBs[x + y * pParam->mb_width];          int b_min_dx, b_max_dx, b_min_dy, b_max_dy;
3134    
3135            int f_count=0;
3136            int b_count=0;
3137            int i_count=0;
3138            int d_count=0;
3139    
3140          for (i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;          const int64_t TRB = (int32_t)time_pp - (int32_t)time_bp;
3141        const int64_t TRD = (int32_t)time_pp;
3142    
3143          //median is only used as prediction. it doesn't have to be real          // fprintf(stderr,"TRB = %lld  TRD = %lld  time_bp =%d time_pp =%d\n\n",TRB,TRD,time_bp,time_pp);
3144          if (x == 1 && y == 1) Data->predMV.x = Data->predMV.y = 0;          // note: i==horizontal, j==vertical
3145          else          for (j = 0; j < mb_height; j++) {
                 if (x == 1) //left macroblock does not have any vector now  
                         Data->predMV = (pMB - pParam->mb_width)->mvs[0]; // top instead of median  
                 else if (y == 1) // top macroblock doesn'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  
3146    
3147          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,                  f_predMV = zeroMV;      /* prediction is reset at left boundary */
3148                                  pParam->width, pParam->height, Data->iFcode - pParam->m_quarterpel, 0, Data->rrv);                  b_predMV = zeroMV;
3149    
3150          Data->Cur = pCur + (x + y * pParam->edged_width) * 16;                  for (i = 0; i < mb_width; i++) {
3151          Data->Ref = pRef + (x + y * pParam->edged_width) * 16;                          MACROBLOCK *mb = &frame->mbs[i + j * mb_width];
3152                            const MACROBLOCK *f_mb = &f_mbs[i + j * mb_width];
3153                            const MACROBLOCK *b_mb = &b_mbs[i + j * mb_width];
3154    
3155          pmv[1].x = EVEN(pMB->mvs[0].x);                          mb->deltamv=zeroMV;
         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;  
3156    
3157          CheckCandidate32I(0, 0, 255, &i, Data);  /* special case, if collocated block is SKIPed: encoding is forward (0,0), cpb=0 without further ado */
3158    
3159          if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP * 4) {                          if (b_mb->mode == MODE_INTER && b_mb->cbp == 0 &&
3160                                    b_mb->mvs[0].x == 0 && b_mb->mvs[0].y == 0) {
3161                                    mb->mode = MODE_NOT_CODED;
3162                                    mb->b_mvs[0] = mb->mvs[0] = zeroMV;
3163                                    continue;
3164                            }
3165    
3166                  if (!(mask = make_mask(pmv, 1)))                          if (b_mb->mode == MODE_INTER4V)
3167                          CheckCandidate32I(pmv[1].x, pmv[1].y, mask, &i, Data);                          {
3168                  if (!(mask = make_mask(pmv, 2)))                                  d_sad16 = 0;
3169                          CheckCandidate32I(pmv[2].x, pmv[2].y, mask, &i, Data);                          /* same method of scaling as in decoder.c, so we copy from there */
3170                        for (k = 0; k < 4; k++) {
3171    
3172                  if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP * 4) // diamond only if needed                                          mb->directmv[k] = b_mb->mvs[k];
                         DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, i);  
3173    
3174                  for (i = 0; i < 4; i++) {                                          mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);
3175                          MACROBLOCK * MB = &pMBs[x + (i&1) + (y+(i>>1)) * pParam->mb_width];                      mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)
3176                          MB->mvs[0] = MB->mvs[1] = MB->mvs[2] = MB->mvs[3] = Data->currentMV[i];                                                                                  ? ((TRB - TRD) * mb->directmv[k].x) / TRD
3177                          MB->mode = MODE_INTER;                                              : mb->mvs[k].x - mb->directmv[k].x);
3178                          MB->sad16 = Data->iMinSAD[i+1];  
3179                  }                      mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);
3180                            mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)
3181                                                                                    ? ((TRB - TRD) * mb->directmv[k].y) / TRD
3182                                                : mb->mvs[k].y - mb->directmv[k].y);
3183    
3184                                            d_sad16 +=
3185                                                    sad8bi(frame->image.y + (2*i+(k&1))*8 + (2*j+(k>>1))*8*edged_width,
3186                                                      get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
3187                                                                    (2*i+(k&1)), (2*j+(k>>1)), 8, &mb->mvs[k], edged_width),
3188                                                      get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
3189                                                                    (2*i+(k&1)), (2*j+(k>>1)), 8, &mb->b_mvs[k], edged_width),
3190                                                      edged_width);
3191          }          }
3192  }  }
   
 #define INTRA_BIAS              2500  
 #define INTRA_THRESH    1500  
 #define INTER_THRESH    1400  
   
 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 of 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;  
   
         int32_t iMinSAD[5], temp[5];  
         VECTOR currentMV[5];  
         SearchData Data;  
         Data.iEdgedWidth = pParam->edged_width;  
         Data.currentMV = currentMV;  
         Data.iMinSAD = iMinSAD;  
         Data.iFcode = Current->fcode;  
         Data.rrv = Current->global_flags & XVID_REDUCED;  
         Data.temp = temp;  
         CheckCandidate = CheckCandidate32I;  
   
         if (intraCount != 0 && intraCount < 10) // we're right after an I frame  
                 IntraThresh += 4 * (intraCount - 10) * (intraCount - 10);  
3193          else          else
3194                  if ( 5*(maxIntra - intraCount) < maxIntra) // we're close to maximum. 2 sec when max is 10 sec                          {
3195                          IntraThresh -= (IntraThresh * (maxIntra - 5*(maxIntra - intraCount)))/maxIntra;                                  mb->directmv[3] = mb->directmv[2] = mb->directmv[1] =
3196                                            mb->directmv[0] = b_mb->mvs[0];
         InterThresh += 400 * (1 - bCount);  
         if (InterThresh < 300) InterThresh = 300;  
3197    
3198          if (sadInit) (*sadInit) ();                                  mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);
3199                        mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)
3200                                                                            ? ((TRB - TRD) * mb->directmv[0].x) / TRD
3201                                        : mb->mvs[0].x - mb->directmv[0].x);
3202    
3203                        mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);
3204                    mb->b_mvs[0].y = (int32_t) ((mb->directmv[0].y == 0)
3205                                                                            ? ((TRB - TRD) * mb->directmv[0].y) / TRD
3206                                        : mb->mvs[0].y - mb->directmv[0].y);
3207    
3208                                    d_sad16 = sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,
3209                                                      get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
3210                                                                    i, j, 16, &mb->mvs[0], edged_width),
3211                                                      get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
3212                                                                    i, j, 16, &mb->b_mvs[0], edged_width),
3213                                                      edged_width);
3214    
3215          for (y = 1; y < pParam->mb_height-1; y += 2) {              }
3216                  for (x = 1; x < pParam->mb_width-1; x += 2) {                      d_sad16 += calc_delta_16(mb->deltamv.x, mb->deltamv.y, 1, frame->quant);
                         int i;  
3217    
3218                          if (bCount == 0) pMBs[x + y * pParam->mb_width].mvs[0] = zeroMV;                          // forward search
3219                            f_sad16 = SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
3220                                                    &frame->image, i, j,
3221                                                    mb->mvs[0].x, mb->mvs[0].y,                     /* start point f_directMV */
3222                                                    f_predMV.x, f_predMV.y,                         /* center is f-prediction */
3223                                                    frame->motion_flags,
3224                                                    frame->quant, frame->fcode, pParam,
3225                                                    f_mbs, f_mbs,
3226                                                    &mb->mvs[0], &pmv_dontcare);
3227    
                         MEanalyzeMB(pRef->y, pCurrent->y, x, y, pParam, pMBs, &Data);  
3228    
3229                          for (i = 0; i < 4; i++) {                          // backward search
3230                                  int dev;                          b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
3231                                  MACROBLOCK *pMB = &pMBs[x+(i&1) + (y+(i>>1)) * pParam->mb_width];                                                  &frame->image, i, j,
3232                                  if (pMB->sad16 > IntraThresh) {                                                  mb->b_mvs[0].x, mb->b_mvs[0].y,         /* start point b_directMV */
3233                                          dev = dev16(pCurrent->y + (x + (i&1) + (y + (i>>1)) * pParam->edged_width) * 16,                                                  b_predMV.x, b_predMV.y,                         /* center is b-prediction */
3234                                                                          pParam->edged_width);                                                  frame->motion_flags,
3235                                          if (dev + IntraThresh < pMB->sad16) {                                                  frame->quant, frame->bcode, pParam,
3236                                                  pMB->mode = MODE_INTRA;                                                  b_mbs, b_mbs,
3237                                                  if (++intra > (pParam->mb_height-2)*(pParam->mb_width-2)/2) return I_VOP;                                                  &mb->b_mvs[0], &pmv_dontcare);
3238                                          }  
3239                                  }                          i_sad16 =
3240                                  sSAD += pMB->sad16;                                  sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,
3241                          }                                                    get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
3242                  }                                                                  i, j, 16, &mb->mvs[0], edged_width),
3243                                                      get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
3244                                                                    i, j, 16, &mb->b_mvs[0], edged_width),
3245                                                      edged_width);
3246                        i_sad16 += calc_delta_16(mb->mvs[0].x-f_predMV.x, mb->mvs[0].y-f_predMV.y,
3247                                                                    frame->fcode, frame->quant);
3248                        i_sad16 += calc_delta_16(mb->b_mvs[0].x-b_predMV.x, mb->b_mvs[0].y-b_predMV.y,
3249                                                                    frame->bcode, frame->quant);
3250    
3251                            get_range(&f_min_dx, &f_max_dx, &f_min_dy, &f_max_dy, i, j, 16, iWidth, iHeight,
3252                              frame->fcode);
3253                            get_range(&b_min_dx, &b_max_dx, &b_min_dy, &b_max_dy, i, j, 16, iWidth, iHeight,
3254                              frame->bcode);
3255    
3256    /* Interpolated MC motion vector search, this is tedious and more complicated because there are
3257       two values for everything, always one for backward and one for forward ME. Still, we don't gain
3258       much from this search, maybe it should simply be skipped and simply current i_sad16 value used
3259       as "optimal". */
3260    
3261                            i_sad16 = Diamond16_InterpolMainSearch(
3262                                                    f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
3263                                                    frame->image.y + i * 16 + j * 16 * edged_width,
3264                                                    b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
3265                                                    i, j,
3266                                                    mb->mvs[0].x, mb->mvs[0].y,
3267                                                    mb->b_mvs[0].x, mb->b_mvs[0].y,
3268                                                    i_sad16,
3269                                                    &f_interpolMV, &b_interpolMV,
3270                                                    f_predMV.x, f_predMV.y, b_predMV.x, b_predMV.y,
3271                                                    f_min_dx, f_max_dx, f_min_dy, f_max_dy,
3272                                                    b_min_dx, b_max_dx, b_min_dy, b_max_dy,
3273                                                    edged_width,  2,
3274                                                    frame->fcode, frame->bcode,frame->quant,0);
3275    
3276                            i_sad16 = Diamond16_InterpolMainSearch(
3277                                                    f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
3278                                                    frame->image.y + i * 16 + j * 16 * edged_width,
3279                                                    b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
3280                                                    i, j,
3281                                                    f_interpolMV.x, f_interpolMV.y,
3282                                                    b_interpolMV.x, b_interpolMV.y,
3283                                                    i_sad16,
3284                                                    &f_interpolMV, &b_interpolMV,
3285                                                    f_predMV.x, f_predMV.y, b_predMV.x, b_predMV.y,
3286                                                    f_min_dx, f_max_dx, f_min_dy, f_max_dy,
3287                                                    b_min_dx, b_max_dx, b_min_dy, b_max_dy,
3288                                                    edged_width,  1,
3289                                                    frame->fcode, frame->bcode,frame->quant,0);             // equiv to halfpel refine
3290    
3291    
3292    /*  DIRECT MODE DELTA VECTOR SEARCH.
3293        This has to be made more effective, but at the moment I'm happy it's running at all */
3294    
3295    /* There are two range restrictions for direct mode: deltaMV is limited to [-32,31] in halfpel units, and
3296       absolute vector must not lie outside of image dimensions. Constraint one is dealt with by CHECK_MV16_DIRECT
3297       and for constraint two we need distance to boundary. This is done by get_range very large fcode (hack!) */
3298    
3299                            get_range(&min_dx, &max_dx, &min_dy, &max_dy, i, j, 16, iWidth, iHeight, 19);
3300    
3301                            d_sad16 = Diamond16_DirectMainSearch(
3302                                                    f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
3303                                                    frame->image.y + i*16 + j*16*edged_width,
3304                                                    b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
3305                                                    i, j,
3306                                                    TRB,TRD,
3307                                                    0,0,
3308                                                    d_sad16,
3309                                                    &mb->deltamv,
3310                                                    mb->directmv, // this has to be pre-initialized with b_mb->mvs[]
3311                                            min_dx, max_dx, min_dy, max_dy,
3312                                                    edged_width, 2, frame->quant, 0);
3313    
3314                            d_sad16 = Diamond16_DirectMainSearch(
3315                                                    f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
3316                                                    frame->image.y + i*16 + j*16*edged_width,
3317                                                    b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
3318                                                    i, j,
3319                                                    TRB,TRD,
3320                                                    mb->deltamv.x, mb->deltamv.y,
3321                                                    d_sad16,
3322                                                    &mb->deltamv,
3323                                                    mb->directmv, // this has to be pre-initialized with b_mb->mvs[]
3324                                            min_dx, max_dx, min_dy, max_dy,
3325                                                    edged_width, 1, frame->quant, 0);               // equiv to halfpel refine
3326    
3327    
3328    //                      i_sad16 = 65535;                /* remove the comment to disable any of the MODEs */
3329    //                      f_sad16 = 65535;
3330    //                      b_sad16 = 65535;
3331    //                      d_sad16 = 65535;
3332    
3333                            if (f_sad16 < b_sad16) {
3334                                    best_sad = f_sad16;
3335                                    mb->mode = MODE_FORWARD;
3336                            } else {
3337                                    best_sad = b_sad16;
3338                                    mb->mode = MODE_BACKWARD;
3339          }          }
         sSAD /= (pParam->mb_height-2)*(pParam->mb_width-2);  
 //      if (sSAD > IntraThresh + INTRA_BIAS) return I_VOP;  
         if (sSAD > InterThresh ) return P_VOP;  
         emms();  
         return B_VOP;  
3340    
3341                            if (i_sad16 < best_sad) {
3342                                    best_sad = i_sad16;
3343                                    mb->mode = MODE_INTERPOLATE;
3344  }  }
3345    
3346                            if (d_sad16 < best_sad) {
3347    
3348  static WARPPOINTS                                  if (b_mb->mode == MODE_INTER4V)
 GlobalMotionEst(const MACROBLOCK * const pMBs,  
                                 const MBParam * const pParam,  
                                 const FRAMEINFO * const current,  
                                 const FRAMEINFO * const reference,  
                                 const IMAGE * const pRefH,  
                                 const IMAGE * const pRefV,  
                                 const IMAGE * const pRefHV      )  
3349  {  {
3350    
3351          const int deltax=8;             // upper bound for difference between a MV and it's neighbour MVs                                  /* how to calc vectors is defined in standard. mvs[] and b_mvs[] are only for motion compensation */
3352          const int deltay=8;                                  /* for the bitstream, the value mb->deltamv is read directly */
         const int grad=512;             // lower bound for deviation in MB  
   
         WARPPOINTS gmc;  
   
         uint32_t mx, my;  
   
         int MBh = pParam->mb_height;  
         int MBw = pParam->mb_width;  
3353    
3354          int *MBmask= calloc(MBh*MBw,sizeof(int));                              for (k = 0; k < 4; k++) {
         double DtimesF[4] = { 0.,0., 0., 0. };  
         double sol[4] = { 0., 0., 0., 0. };  
         double a,b,c,n,denom;  
         double meanx,meany;  
         int num,oldnum;  
   
         if (!MBmask) { fprintf(stderr,"Mem error\n"); return gmc;}  
   
 // filter mask of all blocks  
   
         for (my = 1; my < MBh-1; my++)  
         for (mx = 1; mx < MBw-1; mx++)  
         {  
                 const int mbnum = mx + my * MBw;  
                 const MACROBLOCK *pMB = &pMBs[mbnum];  
                 const VECTOR mv = pMB->mvs[0];  
   
                 if (pMB->mode == MODE_INTRA || pMB->mode == MODE_NOT_CODED)  
                         continue;  
3355    
3356                  if ( ( (ABS(mv.x -   (pMB-1)->mvs[0].x) < deltax) && (ABS(mv.y -   (pMB-1)->mvs[0].y) < deltay) )                                                  mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);
3357                  &&   ( (ABS(mv.x -   (pMB+1)->mvs[0].x) < deltax) && (ABS(mv.y -   (pMB+1)->mvs[0].y) < deltay) )                              mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)
3358                  &&   ( (ABS(mv.x - (pMB-MBw)->mvs[0].x) < deltax) && (ABS(mv.y - (pMB-MBw)->mvs[0].y) < deltay) )                                                                                          ? ((TRB - TRD) * mb->directmv[k].x) / TRD
3359                  &&   ( (ABS(mv.x - (pMB+MBw)->mvs[0].x) < deltax) && (ABS(mv.y - (pMB+MBw)->mvs[0].y) < deltay) ) )                                                      : mb->mvs[k].x - mb->directmv[k].x);
3360                          MBmask[mbnum]=1;  
3361                                mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);
3362                            mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)
3363                                                                                            ? ((TRB - TRD) * mb->directmv[k].y) / TRD
3364                                                : mb->mvs[k].y - mb->directmv[k].y);
3365          }          }
   
         for (my = 1; my < MBh-1; my++)  
         for (mx = 1; mx < MBw-1; mx++)  
         {  
                 const uint8_t *const pCur = current->image.y + 16*my*pParam->edged_width + 16*mx;  
   
                 const int mbnum = mx + my * MBw;  
                 if (!MBmask[mbnum])  
                         continue;  
   
                 if (sad16 ( pCur, pCur+1 , pParam->edged_width, 65536) <= grad )  
                         MBmask[mbnum] = 0;  
                 if (sad16 ( pCur, pCur+pParam->edged_width, pParam->edged_width, 65536) <= grad )  
                         MBmask[mbnum] = 0;  
   
3366          }          }
3367                                    else
         emms();  
   
         do {            /* until convergence */  
   
         a = b = c = n = 0;  
         DtimesF[0] = DtimesF[1] = DtimesF[2] = DtimesF[3] = 0.;  
         for (my = 0; my < MBh; my++)  
                 for (mx = 0; mx < MBw; mx++)  
3368                  {                  {
3369                          const int mbnum = mx + my * MBw;                                          mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);
                         const MACROBLOCK *pMB = &pMBs[mbnum];  
                         const VECTOR mv = pMB->mvs[0];  
3370    
3371                          if (!MBmask[mbnum])                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)
3372                                  continue;                                                                                  ? ((TRB - TRD) * mb->directmv[0].x) / TRD
3373                                            : mb->mvs[0].x - mb->directmv[0].x);
3374    
3375                          n++;                              mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);
                         a += 16*mx+8;  
                         b += 16*my+8;  
                         c += (16*mx+8)*(16*mx+8)+(16*my+8)*(16*my+8);  
   
                         DtimesF[0] += (double)mv.x;  
                         DtimesF[1] += (double)mv.x*(16*mx+8) + (double)mv.y*(16*my+8);  
                         DtimesF[2] += (double)mv.x*(16*my+8) - (double)mv.y*(16*mx+8);  
                         DtimesF[3] += (double)mv.y;  
                 }  
   
         denom = a*a+b*b-c*n;  
   
 /* Solve the system:     sol = (D'*E*D)^{-1} D'*E*F   */  
 /* D'*E*F has been calculated in the same loop as matrix */  
   
         sol[0] = -c*DtimesF[0] + a*DtimesF[1] + b*DtimesF[2];  
         sol[1] =  a*DtimesF[0] - n*DtimesF[1]                + b*DtimesF[3];  
         sol[2] =  b*DtimesF[0]                - n*DtimesF[2] - a*DtimesF[3];  
         sol[3] =                 b*DtimesF[1] - a*DtimesF[2] - c*DtimesF[3];  
   
         sol[0] /= denom;  
         sol[1] /= denom;  
         sol[2] /= denom;  
         sol[3] /= denom;  
   
         meanx = meany = 0.;  
         oldnum = 0;  
         for (my = 0; my < MBh; my++)  
                 for (mx = 0; mx < MBw; mx++)  
                 {  
                         const int mbnum = mx + my * MBw;  
                         const MACROBLOCK *pMB = &pMBs[mbnum];  
                         const VECTOR mv = pMB->mvs[0];  
3376    
3377                          if (!MBmask[mbnum])                          mb->b_mvs[0].y = (int32_t) ((mb->deltamv.y == 0)
3378                                  continue;                                                                                  ? ((TRB - TRD) * mb->directmv[0].y) / TRD
3379                                                : mb->mvs[0].y - mb->directmv[0].y);
3380    
3381                          oldnum++;                                          mb->mvs[3] = mb->mvs[2] = mb->mvs[1] = mb->mvs[0];
3382                          meanx += ABS(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - mv.x );                                          mb->b_mvs[3] = mb->b_mvs[2] = mb->b_mvs[1] = mb->b_mvs[0];
                         meany += ABS(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - mv.y );  
3383                  }                  }
3384    
3385          if (4*meanx > oldnum)   /* better fit than 0.25 is useless */                                  best_sad = d_sad16;
3386                  meanx /= oldnum;                                  mb->mode = MODE_DIRECT;
         else  
                 meanx = 0.25;  
   
         if (4*meany > oldnum)  
                 meany /= oldnum;  
         else  
                 meany = 0.25;  
   
 /*      fprintf(stderr,"sol = (%8.5f, %8.5f, %8.5f, %8.5f)\n",sol[0],sol[1],sol[2],sol[3]);  
         fprintf(stderr,"meanx = %8.5f  meany = %8.5f   %d\n",meanx,meany, oldnum);  
 */  
         num = 0;  
         for (my = 0; my < MBh; my++)  
                 for (mx = 0; mx < MBw; mx++)  
                 {  
                         const int mbnum = mx + my * MBw;  
                         const MACROBLOCK *pMB = &pMBs[mbnum];  
                         const VECTOR mv = pMB->mvs[0];  
   
                         if (!MBmask[mbnum])  
                                 continue;  
   
                         if  ( ( ABS(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - mv.x ) > meanx )  
                            || ( ABS(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - mv.y ) > meany ) )  
                                 MBmask[mbnum]=0;  
                         else  
                                 num++;  
3387                  }                  }
3388    
3389          } while ( (oldnum != num) && (num>=4) );                          switch (mb->mode)
   
         if (num < 4)  
3390          {          {
3391                  gmc.duv[0].x= gmc.duv[0].y= gmc.duv[1].x= gmc.duv[1].y= gmc.duv[2].x= gmc.duv[2].y=0;                                  case MODE_FORWARD:
3392          } else {                                          f_count++;
3393                                            f_predMV = mb->mvs[0];
3394                  gmc.duv[0].x=(int)(sol[0]+0.5);                                          break;
3395                  gmc.duv[0].y=(int)(sol[3]+0.5);                                  case MODE_BACKWARD:
3396                                            b_count++;
3397                                            b_predMV = mb->b_mvs[0];
3398    
3399                  gmc.duv[1].x=(int)(sol[1]*pParam->width+0.5);                                          break;
3400                  gmc.duv[1].y=(int)(-sol[2]*pParam->width+0.5);                                  case MODE_INTERPOLATE:
3401                                            i_count++;
3402                                            mb->mvs[0] = f_interpolMV;
3403                                            mb->b_mvs[0] = b_interpolMV;
3404                                            f_predMV = mb->mvs[0];
3405                                            b_predMV = mb->b_mvs[0];
3406                                            break;
3407                                    case MODE_DIRECT:
3408                                            d_count++;
3409                                            break;
3410                                    default:
3411                                            break;
3412                            }
3413    
                 gmc.duv[2].x=0;  
                 gmc.duv[2].y=0;  
3414          }          }
3415  //      fprintf(stderr,"wp1 = ( %4d, %4d)  wp2 = ( %4d, %4d) \n", gmc.duv[0].x, gmc.duv[0].y, gmc.duv[1].x, gmc.duv[1].y);          }
3416    
3417          free(MBmask);  #ifdef _DEBUG_BFRAME_STAT
3418            fprintf(stderr,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d\n",
3419                                    f_count,b_count,i_count,d_count);
3420    #endif
3421    
         return gmc;  
3422  }  }

Legend:
Removed from v.1.44.2.50  
changed lines
  Added in v.1.45

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