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

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

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