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

Legend:
Removed from v.1.44.2.52  
changed lines
  Added in v.1.53

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