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

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

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