[svn] / branches / dev-api-3 / xvidcore / src / motion / motion_est.c Repository:
ViewVC logotype

Diff of /branches/dev-api-3/xvidcore/src/motion/motion_est.c

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

revision 392, Wed Sep 4 18:44:41 2002 UTC revision 753, Wed Jan 1 12:50:44 2003 UTC
# Line 28  Line 28 
28   *   *
29   *************************************************************************/   *************************************************************************/
30    
 /**************************************************************************  
  *  
  *  Modifications:  
  *  
  *      01.05.2002      updated MotionEstimationBVOP  
  *      25.04.2002 partial prevMB conversion  
  *  22.04.2002 remove some compile warning by chenm001 <chenm001@163.com>  
  *  14.04.2002 added MotionEstimationBVOP()  
  *  02.04.2002 add EPZS(^2) as ME algorithm, use PMV_USESQUARES to choose between  
  *             EPZS and EPZS^2  
  *  08.02.2002 split up PMVfast into three routines: PMVFast, PMVFast_MainLoop  
  *             PMVFast_Refine to support multiple searches with different start points  
  *  07.01.2002 uv-block-based interpolation  
  *  06.01.2002 INTER/INTRA-decision is now done before any SEARCH8 (speedup)  
  *             changed INTER_BIAS to 150 (as suggested by suxen_drol)  
  *             removed halfpel refinement step in PMVfastSearch8 + quality=5  
  *             added new quality mode = 6 which performs halfpel refinement  
  *             filesize difference between quality 5 and 6 is smaller than 1%  
  *             (Isibaar)  
  *  31.12.2001 PMVfastSearch16 and PMVfastSearch8 (gruel)  
  *  30.12.2001 get_range/MotionSearchX simplified; blue/green bug fix  
  *  22.12.2001 commented best_point==99 check  
  *  19.12.2001 modified get_range (purple bug fix)  
  *  15.12.2001 moved pmv displacement from mbprediction  
  *  02.12.2001 motion estimation/compensation split (Isibaar)  
  *  16.11.2001 rewrote/tweaked search algorithms; pross@cs.rmit.edu.au  
  *  10.11.2001 support for sad16/sad8 functions  
  *  28.08.2001 reactivated MODE_INTER4V for EXT_MODE  
  *  24.08.2001 removed MODE_INTER4V_Q, disabled MODE_INTER4V for EXT_MODE  
  *  22.08.2001 added MODE_INTER4V_Q  
  *  20.08.2001 added pragma to get rid of internal compiler error with VC6  
  *             idea by Cyril. Thanks.  
  *  
  *  Michael Militzer <isibaar@videocoding.de>  
  *  
  **************************************************************************/  
   
31  #include <assert.h>  #include <assert.h>
32  #include <stdio.h>  #include <stdio.h>
33  #include <stdlib.h>  #include <stdlib.h>
34    #include <string.h>     // memcpy
35    
36  #include "../encoder.h"  #include "../encoder.h"
37  #include "../utils/mbfunctions.h"  #include "../utils/mbfunctions.h"
38  #include "../prediction/mbprediction.h"  #include "../prediction/mbprediction.h"
39  #include "../global.h"  #include "../global.h"
40  #include "../utils/timer.h"  #include "../utils/timer.h"
41    #include "../image/interpolate8x8.h"
42    #include "motion_est.h"
43  #include "motion.h"  #include "motion.h"
44  #include "sad.h"  #include "sad.h"
45    #include "../utils/emms.h"
46    
47    #define INITIAL_SKIP_THRESH     (10)
48    #define FINAL_SKIP_THRESH       (50)
49    #define MAX_SAD00_FOR_SKIP      (20)
50    #define MAX_CHROMA_SAD_FOR_SKIP (22)
51    
52    #define CHECK_CANDIDATE(X,Y,D) { \
53    (*CheckCandidate)((const int)(X),(const int)(Y), (D), &iDirection, data ); }
54    
55    static __inline int
56    d_mv_bits(int x, int y, const VECTOR pred, const uint32_t iFcode, const int qpel, const int rrv)
57    {
58            int xb, yb;
59            if (qpel) { x *= 2; y *= 2;}
60            else if (rrv) { x = RRV_MV_SCALEDOWN(x); y = RRV_MV_SCALEDOWN(y); }
61            x -= pred.x;
62            y -= pred.y;
63    
64            if (x) {
65                    if (x < 0) x = -x;
66                    x += (1 << (iFcode - 1)) - 1;
67                    x >>= (iFcode - 1);
68                    if (x > 32) x = 32;
69                    xb = mvtab[x] + iFcode;
70            } else xb = 1;
71    
72            if (y) {
73                    if (y < 0) y = -y;
74                    y += (1 << (iFcode - 1)) - 1;
75                    y >>= (iFcode - 1);
76                    if (y > 32) y = 32;
77                    yb = mvtab[y] + iFcode;
78            } else yb = 1;
79            return xb + yb;
80    }
81    
82    static int32_t
83    ChromaSAD(int dx, int dy, const SearchData * const data)
84    {
85            int sad;
86            const uint32_t stride = data->iEdgedWidth/2;
87    
88            if (dx == data->temp[5] && dy == data->temp[6]) return data->temp[7]; //it has been checked recently
89            data->temp[5]  = dx; data->temp[6] = dy; // backup
90    
91            switch (((dx & 1) << 1) | (dy & 1))     {
92                    case 0:
93                            dx = dx / 2; dy = dy / 2;
94                            sad = sad8(data->CurU, data->RefCU + dy * stride + dx, stride);
95                            sad += sad8(data->CurV, data->RefCV + dy * stride + dx, stride);
96                            break;
97                    case 1:
98                            dx = dx / 2; dy = (dy - 1) / 2;
99                            sad = sad8bi(data->CurU, data->RefCU + dy * stride + dx, data->RefCU + (dy+1) * stride + dx, stride);
100                            sad += sad8bi(data->CurV, data->RefCV + dy * stride + dx, data->RefCV + (dy+1) * stride + dx, stride);
101                            break;
102                    case 2:
103                            dx = (dx - 1) / 2; dy = dy / 2;
104                            sad = sad8bi(data->CurU, data->RefCU + dy * stride + dx, data->RefCU + dy * stride + dx+1, stride);
105                            sad += sad8bi(data->CurV, data->RefCV + dy * stride + dx, data->RefCV + dy * stride + dx+1, stride);
106                            break;
107                    default:
108                            dx = (dx - 1) / 2; dy = (dy - 1) / 2;
109                            interpolate8x8_halfpel_hv(data->RefQ, data->RefCU + dy * stride + dx, stride, data->rounding);
110                            sad = sad8(data->CurU, data->RefQ, stride);
111    
112                            interpolate8x8_halfpel_hv(data->RefQ, data->RefCV + dy * stride + dx, stride, data->rounding);
113                            sad += sad8(data->CurV, data->RefQ, stride);
114                            break;
115            }
116            data->temp[7] = sad; //backup, part 2
117            return sad;
118    }
119    
120    static __inline const uint8_t *
121    GetReferenceB(const int x, const int y, const int dir, const SearchData * const data)
122    {
123    //      dir : 0 = forward, 1 = backward
124            switch ( (dir << 2) | ((x&1)<<1) | (y&1) ) {
125                    case 0 : return data->Ref + x/2 + (y/2)*(data->iEdgedWidth);
126                    case 1 : return data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth);
127                    case 2 : return data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth);
128                    case 3 : return data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth);
129                    case 4 : return data->bRef + x/2 + (y/2)*(data->iEdgedWidth);
130                    case 5 : return data->bRefV + x/2 + ((y-1)/2)*(data->iEdgedWidth);
131                    case 6 : return data->bRefH + (x-1)/2 + (y/2)*(data->iEdgedWidth);
132                    default : return data->bRefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth);
133            }
134    }
135    
136    // this is a simpler copy of GetReferenceB, but as it's __inline anyway, we can keep the two separate
137    static __inline const uint8_t *
138    GetReference(const int x, const int y, const SearchData * const data)
139    {
140            switch ( ((x&1)<<1) | (y&1) ) {
141                    case 0 : return data->Ref + x/2 + (y/2)*(data->iEdgedWidth);
142                    case 1 : return data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth);
143                    case 2 : return data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth);
144                    default : return data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth);
145            }
146    }
147    
148  static int32_t lambda_vec16[32] =       /* rounded values for lambda param for weight of motion bits as in modified H.26L */  static uint8_t *
149  { 0, (int) (1.00235 + 0.5), (int) (1.15582 + 0.5), (int) (1.31976 + 0.5),  Interpolate8x8qpel(const int x, const int y, const int block, const int dir, const SearchData * const data)
150                  (int) (1.49591 + 0.5), (int) (1.68601 + 0.5),  {
151          (int) (1.89187 + 0.5), (int) (2.11542 + 0.5), (int) (2.35878 + 0.5),  // create or find a qpel-precision reference picture; return pointer to it
152                  (int) (2.62429 + 0.5), (int) (2.91455 + 0.5),          uint8_t * Reference = (uint8_t *)data->RefQ + 16*dir;
153          (int) (3.23253 + 0.5), (int) (3.58158 + 0.5), (int) (3.96555 + 0.5),          const int32_t iEdgedWidth = data->iEdgedWidth;
154                  (int) (4.38887 + 0.5), (int) (4.85673 + 0.5),          const uint32_t rounding = data->rounding;
155          (int) (5.37519 + 0.5), (int) (5.95144 + 0.5), (int) (6.59408 + 0.5),          const int halfpel_x = x/2;
156                  (int) (7.31349 + 0.5), (int) (8.12242 + 0.5),          const int halfpel_y = y/2;
157          (int) (9.03669 + 0.5), (int) (10.0763 + 0.5), (int) (11.2669 + 0.5),          const uint8_t *ref1, *ref2, *ref3, *ref4;
                 (int) (12.6426 + 0.5), (int) (14.2493 + 0.5),  
         (int) (16.1512 + 0.5), (int) (18.442 + 0.5), (int) (21.2656 + 0.5),  
                 (int) (24.8580 + 0.5), (int) (29.6436 + 0.5),  
         (int) (36.4949 + 0.5)  
 };  
   
 static int32_t *lambda_vec8 = lambda_vec16;     /* same table for INTER and INTER4V for now */  
158    
159            ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
160            ref1 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
161            switch( ((x&1)<<1) + (y&1) ) {
162            case 0: // pure halfpel position
163                    return (uint8_t *) ref1;
164                    break;
165    
166            case 1: // x halfpel, y qpel - top or bottom during qpel refinement
167                    ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
168                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
169                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
170                    break;
171    
172  // mv.length table          case 2: // x qpel, y halfpel - left or right during qpel refinement
173  static const uint32_t mvtab[33] = {                  ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
174          1, 2, 3, 4, 6, 7, 7, 7,                  ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
175          9, 9, 9, 10, 10, 10, 10, 10,                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
176          10, 10, 10, 10, 10, 10, 10, 10,                  break;
         10, 11, 11, 11, 11, 11, 11, 12, 12  
 };  
177    
178            default: // x and y in qpel resolution - the "corners" (top left/right and
179                             // bottom left/right) during qpel refinement
180                    ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
181                    ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
182                    ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);
183                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
184                    ref3 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
185                    ref4 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
186                    interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
187                    break;
188            }
189            return Reference;
190    }
191    
192  static __inline uint32_t  static uint8_t *
193  mv_bits(int32_t component,  Interpolate16x16qpel(const int x, const int y, const int dir, const SearchData * const data)
                 const uint32_t iFcode)  
194  {  {
195          if (component == 0)  // create or find a qpel-precision reference picture; return pointer to it
196                  return 1;          uint8_t * Reference = (uint8_t *)data->RefQ + 16*dir;
197            const int32_t iEdgedWidth = data->iEdgedWidth;
198            const uint32_t rounding = data->rounding;
199            const int halfpel_x = x/2;
200            const int halfpel_y = y/2;
201            const uint8_t *ref1, *ref2, *ref3, *ref4;
202    
203          if (component < 0)          ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
204                  component = -component;          switch( ((x&1)<<1) + (y&1) ) {
205            case 0: // pure halfpel position
206                    return (uint8_t *) ref1;
207            case 1: // x halfpel, y qpel - top or bottom during qpel refinement
208                    ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
209                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
210                    interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
211                    interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
212                    interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
213                    break;
214    
215          if (iFcode == 1) {          case 2: // x qpel, y halfpel - left or right during qpel refinement
216                  if (component > 32)                  ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
217                          component = 32;                  interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
218                    interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
219                    interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
220                    interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
221                    break;
222    
223                  return mvtab[component] + 1;          default: // x and y in qpel resolution - the "corners" (top left/right and
224                             // bottom left/right) during qpel refinement
225                    ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
226                    ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
227                    ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);
228                    interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
229                    interpolate8x8_avg4(Reference+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, rounding);
230                    interpolate8x8_avg4(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, rounding);
231                    interpolate8x8_avg4(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, rounding);
232                    break;
233            }
234            return Reference;
235          }          }
236    
237          component += (1 << (iFcode - 1)) - 1;  /* CHECK_CANDIATE FUNCTIONS START */
         component >>= (iFcode - 1);  
238    
239          if (component > 32)  static void
240                  component = 32;  CheckCandidate16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
241    {
242            int t, xc, yc;
243            const uint8_t * Reference;
244            VECTOR * current;
245    
246            if (( x > data->max_dx) || ( x < data->min_dx)
247                    || ( y > data->max_dy) || (y < data->min_dy)) return;
248    
249          return mvtab[component] + 1 + iFcode - 1;          if (data->qpel_precision) { // x and y are in 1/4 precision
250                    Reference = Interpolate16x16qpel(x, y, 0, data);
251                    xc = x/2; yc = y/2; //for chroma sad
252                    current = data->currentQMV;
253            } else {
254                    Reference = GetReference(x, y, data);
255                    current = data->currentMV;
256                    xc = x; yc = y;
257  }  }
258            t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel && !data->qpel_precision, 0);
259    
260            data->temp[0] = sad16v(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
261    
262  static __inline uint32_t          data->temp[0] += (data->lambda16 * t * data->temp[0])/1000;
263  calc_delta_16(const int32_t dx,          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))/100;
                           const int32_t dy,  
                           const uint32_t iFcode,  
                           const uint32_t iQuant)  
 {  
         return NEIGH_TEND_16X16 * lambda_vec16[iQuant] * (mv_bits(dx, iFcode) +  
                                                                                                           mv_bits(dy, iFcode));  
 }  
264    
265  static __inline uint32_t          if (data->chroma) data->temp[0] += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
266  calc_delta_8(const int32_t dx,                                                                                                          (yc >> 1) + roundtab_79[yc & 0x3], data);
                          const int32_t dy,  
                          const uint32_t iFcode,  
                          const uint32_t iQuant)  
 {  
         return NEIGH_TEND_8X8 * lambda_vec8[iQuant] * (mv_bits(dx, iFcode) +  
                                                                                                    mv_bits(dy, iFcode));  
 }  
267    
268  bool          if (data->temp[0] < data->iMinSAD[0]) {
269  MotionEstimation(MBParam * const pParam,                  data->iMinSAD[0] = data->temp[0];
270                                   FRAMEINFO * const current,                  current[0].x = x; current[0].y = y;
271                                   FRAMEINFO * const reference,                  *dir = Direction; }
                                  const IMAGE * const pRefH,  
                                  const IMAGE * const pRefV,  
                                  const IMAGE * const pRefHV,  
                                  const uint32_t iLimit)  
 {  
         const uint32_t iWcount = pParam->mb_width;  
         const uint32_t iHcount = pParam->mb_height;  
         MACROBLOCK *const pMBs = current->mbs;  
         MACROBLOCK *const prevMBs = reference->mbs;  
         const IMAGE *const pCurrent = &current->image;  
         const IMAGE *const pRef = &reference->image;  
272    
273          static const VECTOR zeroMV = { 0, 0 };          if (data->temp[1] < data->iMinSAD[1]) {
274          VECTOR predMV;                  data->iMinSAD[1] = data->temp[1]; current[1].x = x; current[1].y= y; }
275            if (data->temp[2] < data->iMinSAD[2]) {
276                    data->iMinSAD[2] = data->temp[2]; current[2].x = x; current[2].y = y; }
277            if (data->temp[3] < data->iMinSAD[3]) {
278                    data->iMinSAD[3] = data->temp[3]; current[3].x = x; current[3].y = y; }
279            if (data->temp[4] < data->iMinSAD[4]) {
280                    data->iMinSAD[4] = data->temp[4]; current[4].x = x; current[4].y = y; }
281    
282          int32_t x, y;  }
         int32_t iIntra = 0;  
         VECTOR pmv;  
283    
284          if (sadInit)  static void
285                  (*sadInit) ();  CheckCandidate32(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
286    {
287            int t;
288            const uint8_t * Reference;
289    
290          for (y = 0; y < iHcount; y++)   {          if ( (!(x&1) && x !=0) || (!(y&1) && y !=0) || //non-zero integer value
291                  for (x = 0; x < iWcount; x ++)  {                  ( x > data->max_dx) || ( x < data->min_dx)
292                    || ( y > data->max_dy) || (y < data->min_dy)) return;
293    
294                          MACROBLOCK *const pMB = &pMBs[x + y * iWcount];          Reference = GetReference(x, y, data);
295            t = d_mv_bits(x, y, data->predMV, data->iFcode, 0, 1);
296    
297                          if (pMB->mode == MODE_NOT_CODED)          data->temp[0] = sad32v_c(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
                                 continue;  
298    
299                          predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          data->temp[0] += (data->lambda16 * t * data->temp[0])/1000;
300            data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))/100;
301    
302                          pMB->sad16 =          if (data->temp[0] < data->iMinSAD[0]) {
303                                  SEARCH16(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent,                  data->iMinSAD[0] = data->temp[0];
304                                                   x, y, predMV.x, predMV.y, predMV.x, predMV.y,                  data->currentMV[0].x = x; data->currentMV[0].y = y;
305                                                   current->motion_flags, current->quant,                  *dir = Direction; }
                                                  current->fcode, pParam, pMBs, prevMBs, &pMB->mv16,  
                                                  &pMB->pmvs[0]);  
306    
307                          if (0 < (pMB->sad16 - MV16_INTER_BIAS)) {          if (data->temp[1] < data->iMinSAD[1]) {
308                                  int32_t deviation;                  data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
309            if (data->temp[2] < data->iMinSAD[2]) {
310                    data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
311            if (data->temp[3] < data->iMinSAD[3]) {
312                    data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
313            if (data->temp[4] < data->iMinSAD[4]) {
314                    data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
315    }
316    
317                                  deviation =  static void
318                                          dev16(pCurrent->y + x * 16 + y * 16 * pParam->edged_width,  CheckCandidate16no4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
319                                                    pParam->edged_width);  {
320            int32_t sad;
321            const uint8_t * Reference;
322            int t;
323            VECTOR * current;
324    
325                                  if (deviation < (pMB->sad16 - MV16_INTER_BIAS)) {          if (( x > data->max_dx) || ( x < data->min_dx)
326                                          pMB->mode = MODE_INTRA;                  || ( y > data->max_dy) || (y < data->min_dy)) return;
                                         pMB->mv16 = pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =  
                                                 pMB->mvs[3] = zeroMV;  
                                         pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =  
                                                 pMB->sad8[3] = 0;  
327    
328                                          iIntra++;          if (data->rrv)
329                                          if (iIntra >= iLimit)                  if ( (!(x&1) && x !=0) || (!(y&1) && y !=0) ) return; //non-zero integer value
                                                 return 1;  
330    
331                                          continue;          if (data->qpel_precision) { // x and y are in 1/4 precision
332                                  }                  Reference = Interpolate16x16qpel(x, y, 0, data);
333                    current = data->currentQMV;
334            } else {
335                    Reference = GetReference(x, y, data);
336                    current = data->currentMV;
337                          }                          }
338            t = d_mv_bits(x, y, data->predMV, data->iFcode,
339                                            data->qpel && !data->qpel_precision, data->rrv);
340    
341                          pmv = pMB->pmvs[0];          sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
342                          if (current->global_flags & XVID_INTER4V)          sad += (data->lambda16 * t * sad)/1000;
                                 if ((!(current->global_flags & XVID_LUMIMASKING) ||  
                                          pMB->dquant == NO_CHANGE)) {  
                                         int32_t sad8 = IMV16X16 * current->quant;  
   
                                         if (sad8 < pMB->sad16) {  
                                                 sad8 += pMB->sad8[0] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x, 2 * y,  
                                                                         pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,  
                                                                         current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[0],  
                                                                         &pMB->pmvs[0]);  
                                         }  
                                         if (sad8 < pMB->sad16) {  
   
                                                 predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 1);  
                                                 sad8 += pMB->sad8[1] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x + 1, 2 * y,  
                                                                         pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,  
                                                                         current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[1],  
                                                                         &pMB->pmvs[1]);  
                                         }  
                                         if (sad8 < pMB->sad16) {  
                                                 predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 2);  
                                                 sad8 += pMB->sad8[2] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x, 2 * y + 1,  
                                                                         pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,  
                                                                         current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs, &pMB->mvs[2],  
                                                                         &pMB->pmvs[2]);  
                                         }  
                                         if (sad8 < pMB->sad16) {  
                                                 predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 3);  
                                                 sad8 += pMB->sad8[3] =  
                                                         SEARCH8(pRef->y, pRefH->y, pRefV->y, pRefHV->y,  
                                                                         pCurrent, 2 * x + 1, 2 * y + 1,  
                                                                         pMB->mv16.x, pMB->mv16.y, predMV.x, predMV.y,  
                                                                         current->motion_flags,  
                                                                         current->quant, current->fcode, pParam,  
                                                                         pMBs, prevMBs,  
                                                                         &pMB->mvs[3],  
                                                                         &pMB->pmvs[3]);  
                                         }  
   
                                         /* decide: MODE_INTER or MODE_INTER4V  
                                            mpeg4:   if (sad8 < pMB->sad16 - nb/2+1) use_inter4v  
                                          */  
343    
344                                          if (sad8 < pMB->sad16) {          if (sad < *(data->iMinSAD)) {
345                                                  pMB->mode = MODE_INTER4V;                  *(data->iMinSAD) = sad;
346                                                  pMB->sad8[0] *= 4;                  current->x = x; current->y = y;
347                                                  pMB->sad8[1] *= 4;                  *dir = Direction; }
348                                                  pMB->sad8[2] *= 4;  }
349                                                  pMB->sad8[3] *= 4;  
350                                                  continue;  static void
351                                          }  CheckCandidate32I(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
352    {
353    // maximum speed - for P/B/I decision
354    
355            if (( x > data->max_dx) || ( x < data->min_dx)
356                    || ( y > data->max_dy) || (y < data->min_dy)) return;
357    
358            data->temp[0] = sad32v_c(data->Cur, data->Ref + x/2 + (y/2)*(data->iEdgedWidth),
359                                                            data->iEdgedWidth, data->temp+1);
360            if (data->temp[0] < *(data->iMinSAD)) {
361                    *(data->iMinSAD) = data->temp[0];
362                    data->currentMV[0].x = x; data->currentMV[0].y = y;
363                    *dir = Direction; }
364            if (data->temp[1] < data->iMinSAD[1]) {
365                    data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
366            if (data->temp[2] < data->iMinSAD[2]) {
367                    data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
368            if (data->temp[3] < data->iMinSAD[3]) {
369                    data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
370            if (data->temp[4] < data->iMinSAD[4]) {
371                    data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
372    
373                                  }                                  }
374    
375                          pMB->mode = MODE_INTER;  static void
376                          pMB->pmvs[0] = pmv;     /* pMB->pmvs[1] = pMB->pmvs[2] = pMB->pmvs[3]  are not needed for INTER */  CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)
377                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mv16;  {
378                          pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] =          int32_t sad;
379                                  pMB->sad16;          int xb, yb, t;
380                          }          const uint8_t *ReferenceF, *ReferenceB;
381            VECTOR *current;
382    
383            if (( xf > data->max_dx) || ( xf < data->min_dx)
384                    || ( yf > data->max_dy) || (yf < data->min_dy)) return;
385    
386            if (data->qpel_precision) {
387                    ReferenceF = Interpolate16x16qpel(xf, yf, 0, data);
388                    xb = data->currentQMV[1].x; yb = data->currentQMV[1].y;
389                    current = data->currentQMV;
390                    ReferenceB = Interpolate16x16qpel(xb, yb, 1, data);
391            } else {
392                    ReferenceF = GetReference(xf, yf, data);
393                    xb = data->currentMV[1].x; yb = data->currentMV[1].y;
394                    ReferenceB = GetReferenceB(xb, yb, 1, data);
395                    current = data->currentMV;
396                          }                          }
397    
398          return 0;          t = d_mv_bits(xf, yf, data->predMV, data->iFcode, data->qpel && !data->qpel_precision, 0)
399  }                   + d_mv_bits(xb, yb, data->bpredMV, data->iFcode, data->qpel && !data->qpel_precision, 0);
400    
401            sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
402            sad += (data->lambda16 * t * sad)/1000;
403    
404  #define CHECK_MV16_ZERO {\          if (sad < *(data->iMinSAD)) {
405    if ( (0 <= max_dx) && (0 >= min_dx) \                  *(data->iMinSAD) = sad;
406      && (0 <= max_dy) && (0 >= min_dy) ) \                  current->x = xf; current->y = yf;
407    { \                  *dir = Direction; }
408      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0, 0 , iEdgedWidth), iEdgedWidth, MV_MAX_ERROR); \  }
     iSAD += calc_delta_16(-center_x, -center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=0; currMV->y=0; }  }     \  
 }  
   
 #define NOCHECK_MV16_CANDIDATE(X,Y) { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \  
 }  
   
 #define CHECK_MV16_CANDIDATE(X,Y) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_CANDIDATE_DIR(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \  
 }  
   
 #define CHECK_MV16_CANDIDATE_FOUND(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \  
     iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
 }  
   
   
 #define CHECK_MV8_ZERO {\  
   iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, 0, 0 , iEdgedWidth), iEdgedWidth); \  
   iSAD += calc_delta_8(-center_x, -center_y, (uint8_t)iFcode, iQuant);\  
   if (iSAD < iMinSAD) \  
   { iMinSAD=iSAD; currMV->x=0; currMV->y=0; } \  
 }  
   
 #define NOCHECK_MV8_CANDIDATE(X,Y) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } \  
 }  
   
 #define CHECK_MV8_CANDIDATE(X,Y) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV8_CANDIDATE_DIR(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \  
 }  
   
 #define CHECK_MV8_CANDIDATE_FOUND(X,Y,D) { \  
   if ( ((X) <= max_dx) && ((X) >= min_dx) \  
     && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  
   { \  
     iSAD = sad8( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 8, (X), (Y), iEdgedWidth),iEdgedWidth); \  
     iSAD += calc_delta_8((X)-center_x, (Y)-center_y, (uint8_t)iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); iFound=0; } } \  
 }  
   
 /* too slow and not fully functional at the moment */  
 /*  
 int32_t ZeroSearch16(  
                                         const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const IMAGE * const pCur,  
                                         const int x, const int y,  
                                         const uint32_t MotionFlags,  
                                         const uint32_t iQuant,  
                                         const uint32_t iFcode,  
                                         MBParam * const pParam,  
                                         const MACROBLOCK * const pMBs,  
                                         const MACROBLOCK * const prevMBs,  
                                         VECTOR * const currMV,  
                                         VECTOR * const currPMV)  
 {  
         const int32_t iEdgedWidth = pParam->edged_width;  
         const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;  
         int32_t iSAD;  
         VECTOR pred;  
409    
410    static void
411    CheckCandidateDirect(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
412    {
413            int32_t sad = 0;
414            int k;
415            const uint8_t *ReferenceF;
416            const uint8_t *ReferenceB;
417            VECTOR mvs, b_mvs;
418            const VECTOR zeroMV={0,0};
419    
420          pred = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
421    
422          iSAD = sad16( cur,          for (k = 0; k < 4; k++) {
423                  get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, 0,0, iEdgedWidth),                  mvs.x = data->directmvF[k].x + x;
424                  iEdgedWidth, MV_MAX_ERROR);                  b_mvs.x = ((x == 0) ?
425          if (iSAD <= iQuant * 96)                          data->directmvB[k].x
426                  iSAD -= MV16_00_BIAS;                          : mvs.x - data->referencemv[k].x);
427    
428          currMV->x = 0;                  mvs.y = data->directmvF[k].y + y;
429          currMV->y = 0;                  b_mvs.y = ((y == 0) ?
430          currPMV->x = -pred.x;                          data->directmvB[k].y
431          currPMV->y = -pred.y;                          : mvs.y - data->referencemv[k].y);
432    
433          return iSAD;                  if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
434                            || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
435                            || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
436                            || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
437    
438                    if (!data->qpel) {
439                            mvs.x *= 2; mvs.y *= 2;
440                            b_mvs.x *= 2; b_mvs.y *= 2; //we move to qpel precision anyway
441  }  }
442  */                  ReferenceF = Interpolate8x8qpel(mvs.x, mvs.y, k, 0, data);
443                    ReferenceB = Interpolate8x8qpel(b_mvs.x, b_mvs.y, k, 1, data);
 int32_t  
 Diamond16_MainSearch(const uint8_t * const pRef,  
                                          const uint8_t * const pRefH,  
                                          const uint8_t * const pRefV,  
                                          const uint8_t * const pRefHV,  
                                          const uint8_t * const cur,  
                                          const int x,  
                                          const int y,  
                                    const int start_x,  
                                    const int start_y,  
                                    int iMinSAD,  
                                    VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                          const int32_t min_dx,  
                                          const int32_t max_dx,  
                                          const int32_t min_dy,  
                                          const int32_t max_dy,  
                                          const int32_t iEdgedWidth,  
                                          const int32_t iDiamondSize,  
                                          const int32_t iFcode,  
                                          const int32_t iQuant,  
                                          int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iDirectionBackup;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
444    
445  /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */                  sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
446                                                    ReferenceF, ReferenceB,
447                                                    data->iEdgedWidth);
448                    if (sad > *(data->iMinSAD)) return;
449            }
450    
451          CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);          sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)/1000;
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
452    
453          if (iDirection) {          if (sad < *(data->iMinSAD)) {
454                  while (!iFound) {                  *(data->iMinSAD) = sad;
455                          iFound = 1;                  data->currentMV->x = x; data->currentMV->y = y;
456                          backupMV = *currMV;                  *dir = Direction; }
                         iDirectionBackup = iDirection;  
   
                         if (iDirectionBackup != 2)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                    backupMV.y, 1);  
                         if (iDirectionBackup != 1)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                    backupMV.y, 2);  
                         if (iDirectionBackup != 4)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,  
                                                                                    backupMV.y - iDiamondSize, 3);  
                         if (iDirectionBackup != 3)  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x,  
                                                                                    backupMV.y + iDiamondSize, 4);  
                 }  
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
         }  
         return iMinSAD;  
457  }  }
458    
459  int32_t  static void
460  Square16_MainSearch(const uint8_t * const pRef,  CheckCandidateDirectno4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x,  
                                         const int y,  
                                    const int start_x,  
                                    const int start_y,  
                                    int iMinSAD,  
                                    VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
461  {  {
462  /* Do a square search around given starting point, return SAD of best */          int32_t sad;
463            const uint8_t *ReferenceF;
464          int32_t iDirection = 0;          const uint8_t *ReferenceB;
465          int32_t iSAD;          VECTOR mvs, b_mvs;
466          VECTOR backupMV;          const VECTOR zeroMV = {0,0};
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
467    
468  /* It's one search with full square pattern, and new parts for all following diamonds */          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;
469    
470  /*   new direction are extra, so 1-4 is normal diamond          mvs.x = data->directmvF[0].x + x;
471        537          b_mvs.x = ((x == 0) ?
472        1*2                  data->directmvB[0].x
473        648                  : mvs.x - data->referencemv[0].x);
 */  
   
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
   
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 5);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 6);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 7);  
         CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 8);  
474    
475            mvs.y = data->directmvF[0].y + y;
476            b_mvs.y = ((y == 0) ?
477                    data->directmvB[0].y
478                    : mvs.y - data->referencemv[0].y);
479    
480          if (iDirection) {          if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
481                  while (!iFound) {                  || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
482                          iFound = 1;                  || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
483                          backupMV = *currMV;                  || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
484    
485                          switch (iDirection) {          if (!data->qpel) {
486                          case 1:                          mvs.x *= 2; mvs.y *= 2;
487                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                          b_mvs.x *= 2; b_mvs.y *= 2; //we move to qpel precision anyway
488                                                                                     backupMV.y, 1);          }
489                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          ReferenceF = Interpolate16x16qpel(mvs.x, mvs.y, 0, data);
490                                                                                   backupMV.y - iDiamondSize, 5);          ReferenceB = Interpolate16x16qpel(b_mvs.x, b_mvs.y, 1, data);
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
                         case 2:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
491    
492                          case 3:          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
493                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,          sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)/1000;
                                                                                  4);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
494    
495                          case 4:          if (sad < *(data->iMinSAD)) {
496                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,                  *(data->iMinSAD) = sad;
497                                                                                   3);                  data->currentMV->x = x; data->currentMV->y = y;
498                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  *dir = Direction; }
499                                                                                   backupMV.y - iDiamondSize, 5);  }
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 break;  
   
                         case 5:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
   
                         case 6:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
   
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
500    
501                                  break;  static void
502    CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
503    {
504            int32_t sad; int t;
505            const uint8_t * Reference;
506    
507                          case 7:          if (( x > data->max_dx) || ( x < data->min_dx)
508                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,                  || ( y > data->max_dy) || (y < data->min_dy)) return;
                                                                                    backupMV.y, 1);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
509    
510                          case 8:          if (data->qpel) Reference = Interpolate16x16qpel(x, y, 0, data);
511                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,          else Reference =  GetReference(x, y, data);
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         default:  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
   
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV16_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         }  
                 }  
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
         }  
         return iMinSAD;  
 }  
512    
513            sad = sad8(data->Cur, Reference, data->iEdgedWidth);
514            t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel && !data->qpel_precision, 0);
515    
516  int32_t          sad += (data->lambda8 * t * (sad+NEIGH_8X8_BIAS))/100;
 Full16_MainSearch(const uint8_t * const pRef,  
                                   const uint8_t * const pRefH,  
                                   const uint8_t * const pRefV,  
                                   const uint8_t * const pRefHV,  
                                   const uint8_t * const cur,  
                                   const int x,  
                                   const int y,  
                                    const int start_x,  
                                    const int start_y,  
                                    int iMinSAD,  
                                    VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                   const int32_t min_dx,  
                                   const int32_t max_dx,  
                                   const int32_t min_dy,  
                                   const int32_t max_dy,  
                                   const int32_t iEdgedWidth,  
                                   const int32_t iDiamondSize,  
                                   const int32_t iFcode,  
                                   const int32_t iQuant,  
                                   int iFound)  
 {  
         int32_t iSAD;  
         int32_t dx, dy;  
         VECTOR backupMV;  
517    
518          backupMV.x = start_x;          if (sad < *(data->iMinSAD)) {
519          backupMV.y = start_y;                  *(data->iMinSAD) = sad;
520                    data->currentMV->x = x; data->currentMV->y = y;
521                    *dir = Direction; }
522    }
523    
524          for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  /* CHECK_CANDIATE FUNCTIONS END */
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV16_CANDIDATE(dx, dy);  
525    
526          return iMinSAD;  /* MAINSEARCH FUNCTIONS START */
 }  
527    
528  int32_t  static void
529  AdvDiamond16_MainSearch(const uint8_t * const pRef,  AdvDiamondSearch(int x, int y, const SearchData * const data, int bDirection)
                                                 const uint8_t * const pRefH,  
                                                 const uint8_t * const pRefV,  
                                                 const uint8_t * const pRefHV,  
                                                 const uint8_t * const cur,  
                                                 const int x,  
                                                 const int y,  
                                            int start_x,  
                                            int start_y,  
                                            int iMinSAD,  
                                            VECTOR * const currMV,  
                                            const int center_x,  
                                            const int center_y,  
                                                 const int32_t min_dx,  
                                                 const int32_t max_dx,  
                                                 const int32_t min_dy,  
                                                 const int32_t max_dy,  
                                                 const int32_t iEdgedWidth,  
                                                 const int32_t iDiamondSize,  
                                                 const int32_t iFcode,  
                                                 const int32_t iQuant,  
                                                 int iDirection)  
530  {  {
531    
         int32_t iSAD;  
   
532  /* 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) */
533    
534          if (iDirection) {          int iDirection;
                 CHECK_MV16_CANDIDATE(start_x - iDiamondSize, start_y);  
                 CHECK_MV16_CANDIDATE(start_x + iDiamondSize, start_y);  
                 CHECK_MV16_CANDIDATE(start_x, start_y - iDiamondSize);  
                 CHECK_MV16_CANDIDATE(start_x, start_y + iDiamondSize);  
         } else {  
                 int bDirection = 1 + 2 + 4 + 8;  
535    
536                  do {          for(;;) { //forever
537                          iDirection = 0;                          iDirection = 0;
538                          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)                  if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
539                                  CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);                  if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
540                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
541                          if (bDirection & 2)                  if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
                                 CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
   
                         if (bDirection & 4)  
                                 CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);  
   
                         if (bDirection & 8)  
                                 CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);  
542    
543                          /* now we're doing diagonal checks near our candidate */                          /* now we're doing diagonal checks near our candidate */
544    
545                          if (iDirection)         //checking if anything found                  if (iDirection) {               //checking if anything found
                         {  
546                                  bDirection = iDirection;                                  bDirection = iDirection;
547                                  iDirection = 0;                                  iDirection = 0;
548                                  start_x = currMV->x;                          x = data->currentMV->x; y = data->currentMV->y;
549                                  start_y = currMV->y;                          if (bDirection & 3) {   //our candidate is left or right
550                                  if (bDirection & 3)     //our candidate is left or right                                  CHECK_CANDIDATE(x, y + iDiamondSize, 8);
551                                  {                                  CHECK_CANDIDATE(x, y - iDiamondSize, 4);
552                                          CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);                          } else {                        // what remains here is up or down
553                                          CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y, 2);
554                                  } else                  // what remains here is up or down                                  CHECK_CANDIDATE(x - iDiamondSize, y, 1);
                                 {  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);  
555                                  }                                  }
556    
557                                  if (iDirection) {                                  if (iDirection) {
558                                          bDirection += iDirection;                                          bDirection += iDirection;
559                                          start_x = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
                                         start_y = currMV->y;  
560                                  }                                  }
561                          } else                          //about to quit, eh? not so fast....                  } else {                                //about to quit, eh? not so fast....
                         {  
562                                  switch (bDirection) {                                  switch (bDirection) {
563                                  case 2:                                  case 2:
564                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
565                                                                                           start_y - iDiamondSize, 2 + 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
566                                          break;                                          break;
567                                  case 1:                                  case 1:
568                                    CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
569                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
570                                          break;                                          break;
571                                  case 2 + 4:                                  case 2 + 4:
572                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
573                                                                                           start_y - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
574                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
575                                          break;                                          break;
576                                  case 4:                                  case 4:
577                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
578                                                                                           start_y - iDiamondSize, 2 + 4);                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y - iDiamondSize, 1 + 4);  
579                                          break;                                          break;
580                                  case 8:                                  case 8:
581                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
582                                                                                           start_y + iDiamondSize, 2 + 8);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
583                                          break;                                          break;
584                                  case 1 + 4:                                  case 1 + 4:
585                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
586                                                                                           start_y + iDiamondSize, 1 + 8);                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
587                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
588                                          break;                                          break;
589                                  case 2 + 8:                                  case 2 + 8:
590                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
591                                                                                           start_y - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
592                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
593                                          break;                                          break;
594                                  case 1 + 8:                                  case 1 + 8:
595                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
596                                                                                           start_y - iDiamondSize, 2 + 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
597                                          CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
                                                                                          start_y + iDiamondSize, 2 + 8);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
598                                          break;                                          break;
599                                  default:                //1+2+4+8 == we didn't find anything at all                                  default:                //1+2+4+8 == we didn't find anything at all
600                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
601                                                                                           start_y - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
602                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
603                                                                                           start_y + iDiamondSize, 1 + 8);                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                          start_y + iDiamondSize, 2 + 8);  
604                                          break;                                          break;
605                                  }                                  }
606                                  if (!iDirection)                          if (!iDirection) break;         //ok, the end. really
                                         break;          //ok, the end. really  
                                 else {  
607                                          bDirection = iDirection;                                          bDirection = iDirection;
608                                          start_x = currMV->x;                          x = data->currentMV->x; y = data->currentMV->y;
                                         start_y = currMV->y;  
                                 }  
609                          }                          }
610                  }                  }
                 while (1);                              //forever  
         }  
         return iMinSAD;  
611  }  }
612    
613  #define CHECK_MV16_F_INTERPOL(X,Y) { \  static void
614    if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \  SquareSearch(int x, int y, const SearchData * const data, int bDirection)
615      && ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \  {
616    { \          int iDirection;
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, b_currMV->x, b_currMV->y, iEdgedWidth),   \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16((X) - f_center_x, (Y) - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16(b_currMV->x - b_center_x, b_currMV->y - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; f_currMV->x=(X); f_currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_F_INTERPOL_FOUND(X,Y) { \  
   if ( ((X) <= f_max_dx) && ((X) >= f_min_dx) \  
     && ((Y) <= f_max_dy) && ((Y) >= f_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, b_currMV->x, b_currMV->y, iEdgedWidth),   \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16((X) - f_center_x, (Y) - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16(b_currMV->x - b_center_x, b_currMV->y - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; f_currMV->x=(X); f_currMV->y=(Y); iFound=0;} } \  
 }  
   
 #define CHECK_MV16_B_INTERPOL(X,Y) { \  
   if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \  
     && ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth),   \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16((X) - b_center_x, (Y) - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; b_currMV->x=(X); b_currMV->y=(Y); } } \  
 }  
   
 #define CHECK_MV16_B_INTERPOL_FOUND(X,Y) { \  
   if ( ((X) <= b_max_dx) && ((X) >= b_min_dx) \  
     && ((Y) <= b_max_dy) && ((Y) >= b_min_dy) ) \  
   { \  
     iSAD = sad16bi( cur, \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, x, y, 16, f_currMV->x, f_currMV->y, iEdgedWidth),   \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, x, y, 16, X, Y, iEdgedWidth),       \  
                         iEdgedWidth); \  
     iSAD += calc_delta_16(f_currMV->x - f_center_x, f_currMV->y - f_center_y, (uint8_t)f_iFcode, iQuant);\  
     iSAD += calc_delta_16((X) - b_center_x, (Y) - b_center_y, (uint8_t)b_iFcode, iQuant);\  
     if (iSAD < iMinSAD) \  
     {  iMinSAD=iSAD; b_currMV->x=(X); b_currMV->y=(Y); iFound=0;} } \  
 }  
   
 int32_t  
 Diamond16_InterpolMainSearch(  
                                         const uint8_t * const f_pRef,  
                                          const uint8_t * const f_pRefH,  
                                          const uint8_t * const f_pRefV,  
                                          const uint8_t * const f_pRefHV,  
   
                                          const uint8_t * const cur,  
   
                                         const uint8_t * const b_pRef,  
                                          const uint8_t * const b_pRefH,  
                                          const uint8_t * const b_pRefV,  
                                          const uint8_t * const b_pRefHV,  
617    
618                                           const int x,          do {
619                                           const int y,                  iDirection = 0;
620                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);
621                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);
622                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);
623                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128);
624                    if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64);
625                    if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128);
626                    if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128);
627                    if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128);
628    
629                                     const int f_start_x,                  bDirection = iDirection;
630                                     const int f_start_y,                  x = data->currentMV->x; y = data->currentMV->y;
631                                     const int b_start_x,          } while (iDirection);
632                                     const int b_start_y,  }
   
                                    int iMinSAD,  
                                    VECTOR * const f_currMV,  
                                    VECTOR * const b_currMV,  
   
                                    const int f_center_x,  
                                    const int f_center_y,  
                                    const int b_center_x,  
                                    const int b_center_y,  
   
                                     const int32_t f_min_dx,  
                                         const int32_t f_max_dx,  
                                         const int32_t f_min_dy,  
                                         const int32_t f_max_dy,  
   
                                     const int32_t b_min_dx,  
                                         const int32_t b_max_dx,  
                                         const int32_t b_min_dy,  
                                         const int32_t b_max_dy,  
   
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
   
                                         const int32_t f_iFcode,  
                                         const int32_t b_iFcode,  
   
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iSAD;  
   
         VECTOR f_backupMV;  
         VECTOR b_backupMV;  
   
         f_currMV->x = f_start_x;  
         f_currMV->y = f_start_y;  
         b_currMV->x = b_start_x;  
         b_currMV->y = b_start_y;  
   
         do  
         {  
                 iFound = 1;  
   
                 f_backupMV = *f_currMV;  
   
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x - iDiamondSize, f_backupMV.y);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x + iDiamondSize, f_backupMV.y);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y - iDiamondSize);  
                 CHECK_MV16_F_INTERPOL_FOUND(f_backupMV.x, f_backupMV.y + iDiamondSize);  
   
                 b_backupMV = *b_currMV;  
   
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x - iDiamondSize, b_backupMV.y);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x + iDiamondSize, b_backupMV.y);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y - iDiamondSize);  
                 CHECK_MV16_B_INTERPOL_FOUND(b_backupMV.x, b_backupMV.y + iDiamondSize);  
   
         } while (!iFound);  
   
         return iMinSAD;  
 }  
   
 /* Sorry, these MACROS really got too large... I'll turn them into function soon! */  
   
 #define CHECK_MV16_DIRECT_FOUND(X,Y) \  
         if ( (X)>=(-32) && (X)<=(31) && ((Y)>=-32) && ((Y)<=31) ) \  
         { int k;\  
         VECTOR mvs,b_mvs;       \  
         iSAD = 0;\  
         for (k = 0; k < 4; k++) {       \  
                                         mvs.x = (int32_t) ((TRB * directmv[k].x) / TRD + (X));          \  
                     b_mvs.x = (int32_t) (((X) == 0)                                                     \  
                                                                                 ? ((TRB - TRD) * directmv[k].x) / TRD   \  
                                             : mvs.x - directmv[k].x);                           \  
                                                                                                                                                                 \  
                     mvs.y = (int32_t) ((TRB * directmv[k].y) / TRD + (Y));              \  
                         b_mvs.y = (int32_t) (((Y) == 0)                                                         \  
                                                                                 ? ((TRB - TRD) * directmv[k].y) / TRD   \  
                                             : mvs.y - directmv[k].y);                           \  
                                                                                                                                                                 \  
   if ( (mvs.x <= max_dx) && (mvs.x >= min_dx) \  
     && (mvs.y <= max_dy) && (mvs.y >= min_dy)  \  
         && (b_mvs.x <= max_dx) && (b_mvs.x >= min_dx)  \  
     && (b_mvs.y <= max_dy) && (b_mvs.y >= min_dy) ) { \  
             iSAD += sad8bi( cur + 8*(k&1) + 8*(k>>1)*iEdgedWidth,                                                                                                       \  
                         get_ref(f_pRef, f_pRefH, f_pRefV, f_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \  
                                         mvs.x, mvs.y, iEdgedWidth),                                                             \  
                         get_ref(b_pRef, b_pRefH, b_pRefV, b_pRefHV, 2*x+(k&1), 2*y+(k>>1), 8, \  
                                         b_mvs.x, b_mvs.y, iEdgedWidth),                                                         \  
                         iEdgedWidth); \  
                 }       \  
         else    \  
                 iSAD = 65535;   \  
         } \  
         iSAD += calc_delta_16((X),(Y), 1, iQuant);\  
         if (iSAD < iMinSAD) \  
             {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iFound=0; } \  
 }  
   
   
   
 int32_t  
 Diamond16_DirectMainSearch(  
                                         const uint8_t * const f_pRef,  
                                         const uint8_t * const f_pRefH,  
                                         const uint8_t * const f_pRefV,  
                                         const uint8_t * const f_pRefHV,  
   
                                         const uint8_t * const cur,  
   
                                         const uint8_t * const b_pRef,  
                                         const uint8_t * const b_pRefH,  
                                         const uint8_t * const b_pRefV,  
                                         const uint8_t * const b_pRefHV,  
633    
634                                          const int x,  static void
635                                          const int y,  DiamondSearch(int x, int y, const SearchData * const data, int bDirection)
636    {
637    
638                                          const int TRB,  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
                                         const int TRD,  
639    
640                                      const int start_x,          int iDirection;
                                     const int start_y,  
641    
642                                      int iMinSAD,          do {
643                                      VECTOR * const currMV,                  iDirection = 0;
644                                          const VECTOR * const directmv,                  if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
645                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
646                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
647                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
648    
649                                      const int32_t min_dx,                  /* now we're doing diagonal checks near our candidate */
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
650    
651                                          const int32_t iEdgedWidth,                  if (iDirection) {               //checking if anything found
652                                          const int32_t iDiamondSize,                          bDirection = iDirection;
653                            iDirection = 0;
654                            x = data->currentMV->x; y = data->currentMV->y;
655                            if (bDirection & 3) {   //our candidate is left or right
656                                    CHECK_CANDIDATE(x, y + iDiamondSize, 8);
657                                    CHECK_CANDIDATE(x, y - iDiamondSize, 4);
658                            } else {                        // what remains here is up or down
659                                    CHECK_CANDIDATE(x + iDiamondSize, y, 2);
660                                    CHECK_CANDIDATE(x - iDiamondSize, y, 1);
661                            }
662                            bDirection += iDirection;
663                            x = data->currentMV->x; y = data->currentMV->y;
664                    }
665            }
666            while (iDirection);
667    }
668    
669                                          const int32_t iQuant,  /* MAINSEARCH FUNCTIONS END */
                                         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
670    
671          int32_t iSAD;  /* HALFPELREFINE COULD BE A MAINSEARCH FUNCTION, BUT THERE IS NO NEED FOR IT */
672    
673    static void
674    SubpelRefine(const SearchData * const data)
675    {
676    /* Do a half-pel or q-pel refinement */
677          VECTOR backupMV;          VECTOR backupMV;
678            int iDirection; //not needed
679    
680          currMV->x = start_x;          if (data->qpel_precision)
681          currMV->y = start_y;                  backupMV = *(data->currentQMV);
682            else backupMV = *(data->currentMV);
683    
684            CHECK_CANDIDATE(backupMV.x, backupMV.y - 1, 0);
685            CHECK_CANDIDATE(backupMV.x + 1, backupMV.y - 1, 0);
686            CHECK_CANDIDATE(backupMV.x + 1, backupMV.y, 0);
687            CHECK_CANDIDATE(backupMV.x + 1, backupMV.y + 1, 0);
688            CHECK_CANDIDATE(backupMV.x, backupMV.y + 1, 0);
689            CHECK_CANDIDATE(backupMV.x - 1, backupMV.y + 1, 0);
690            CHECK_CANDIDATE(backupMV.x - 1, backupMV.y, 0);
691            CHECK_CANDIDATE(backupMV.x - 1, backupMV.y - 1, 0);
692    }
693    
694  /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  static __inline int
695    SkipDecisionP(const IMAGE * current, const IMAGE * reference,
696                                                            const int x, const int y,
697                                                            const uint32_t iEdgedWidth, const uint32_t iQuant, int rrv)
698    
         do  
699          {          {
700                  iFound = 1;  /*      keep repeating checks for all b-frames before this P frame,
701            to make sure that SKIP is possible (todo)
702                  backupMV = *currMV;          how: if skip is not possible set sad00 to a very high value */
703            if(rrv) {
704                    uint32_t sadC = sad16(current->u + x*16 + y*(iEdgedWidth/2)*16,
705                                                    reference->u + x*16 + y*(iEdgedWidth/2)*16, iEdgedWidth/2, 256*4096);
706                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
707                    sadC += sad16(current->v + (x + y*(iEdgedWidth/2))*16,
708                                                    reference->v + (x + y*(iEdgedWidth/2))*16, iEdgedWidth/2, 256*4096);
709                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
710                    return 1;
711            } else {
712                    uint32_t sadC = sad8(current->u + x*8 + y*(iEdgedWidth/2)*8,
713                                                    reference->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2);
714                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
715                    sadC += sad8(current->v + (x + y*(iEdgedWidth/2))*8,
716                                                    reference->v + (x + y*(iEdgedWidth/2))*8, iEdgedWidth/2);
717                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
718                    return 1;
719            }
720    }
721    
722                  CHECK_MV16_DIRECT_FOUND(backupMV.x - iDiamondSize, backupMV.y);  static __inline void
723                  CHECK_MV16_DIRECT_FOUND(backupMV.x + iDiamondSize, backupMV.y);  SkipMacroblockP(MACROBLOCK *pMB, const int32_t sad)
724                  CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y - iDiamondSize);  {
725                  CHECK_MV16_DIRECT_FOUND(backupMV.x, backupMV.y + iDiamondSize);          pMB->mode = MODE_NOT_CODED;
726            pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = 0;
727            pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = 0;
728    
729          } while (!iFound);          pMB->qmvs[0].x = pMB->qmvs[1].x = pMB->qmvs[2].x = pMB->qmvs[3].x = 0;
730            pMB->qmvs[0].y = pMB->qmvs[1].y = pMB->qmvs[2].y = pMB->qmvs[3].y = 0;
731    
732          return iMinSAD;          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
733  }  }
734    
735    bool
736  int32_t  MotionEstimation(MBParam * const pParam,
737  AdvDiamond8_MainSearch(const uint8_t * const pRef,                                   FRAMEINFO * const current,
738                                             const uint8_t * const pRefH,                                   FRAMEINFO * const reference,
739                                             const uint8_t * const pRefV,                                   const IMAGE * const pRefH,
740                                             const uint8_t * const pRefHV,                                   const IMAGE * const pRefV,
741                                             const uint8_t * const cur,                                   const IMAGE * const pRefHV,
742                                             const int x,                                   const uint32_t iLimit)
                                            const int y,  
                                            int start_x,  
                                            int start_y,  
                                            int iMinSAD,  
                                            VECTOR * const currMV,  
                                            const int center_x,  
                                            const int center_y,  
                                            const int32_t min_dx,  
                                            const int32_t max_dx,  
                                            const int32_t min_dy,  
                                            const int32_t max_dy,  
                                            const int32_t iEdgedWidth,  
                                            const int32_t iDiamondSize,  
                                            const int32_t iFcode,  
                                            const int32_t iQuant,  
                                            int iDirection)  
743  {  {
744            MACROBLOCK *const pMBs = current->mbs;
745            const IMAGE *const pCurrent = &current->image;
746            const IMAGE *const pRef = &reference->image;
747    
748          int32_t iSAD;          const VECTOR zeroMV = { 0, 0 };
749    
750  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */          uint32_t mb_width = pParam->mb_width;
751            uint32_t mb_height = pParam->mb_height;
752    
753          if (iDirection) {          uint32_t x, y;
754                  CHECK_MV8_CANDIDATE(start_x - iDiamondSize, start_y);          uint32_t iIntra = 0;
755                  CHECK_MV8_CANDIDATE(start_x + iDiamondSize, start_y);          int32_t InterBias, quant = current->quant, sad00;
756                  CHECK_MV8_CANDIDATE(start_x, start_y - iDiamondSize);          uint8_t *qimage;
757                  CHECK_MV8_CANDIDATE(start_x, start_y + iDiamondSize);  
758            // some pre-initialized thingies for SearchP
759            int32_t temp[8];
760            VECTOR currentMV[5];
761            VECTOR currentQMV[5];
762            int32_t iMinSAD[5];
763            SearchData Data;
764            memset(&Data, 0, sizeof(SearchData));
765            Data.iEdgedWidth = pParam->edged_width;
766            Data.currentMV = currentMV;
767            Data.currentQMV = currentQMV;
768            Data.iMinSAD = iMinSAD;
769            Data.temp = temp;
770            Data.iFcode = current->fcode;
771            Data.rounding = pParam->m_rounding_type;
772            Data.qpel = pParam->m_quarterpel;
773            Data.chroma = current->global_flags & XVID_ME_COLOUR;
774            Data.rrv = current->global_flags & XVID_REDUCED;
775    
776            if ((current->global_flags & XVID_REDUCED)) {
777                    mb_width = (pParam->width + 31) / 32;
778                    mb_height = (pParam->height + 31) / 32;
779                    Data.qpel = Data.chroma = 0;
780            }
781    
782            if((qimage = (uint8_t *) malloc(32 * pParam->edged_width)) == NULL)
783                    return 1; // allocate some mem for qpel interpolated blocks
784                                      // somehow this is dirty since I think we shouldn't use malloc outside
785                                      // encoder_create() - so please fix me!
786            Data.RefQ = qimage;
787            if (sadInit) (*sadInit) ();
788    
789            for (y = 0; y < mb_height; y++) {
790                    for (x = 0; x < mb_width; x++)  {
791                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
792    
793                            if (Data.rrv) pMB->sad16 =
794                                    sad32v_c(pCurrent->y + (x + y * pParam->edged_width) * 32,
795                                                            pRef->y + (x + y * pParam->edged_width) * 32,
796                                                            pParam->edged_width, pMB->sad8 );
797    
798                            else pMB->sad16 =
799                                    sad16v(pCurrent->y + (x + y * pParam->edged_width) * 16,
800                                                            pRef->y + (x + y * pParam->edged_width) * 16,
801                                                            pParam->edged_width, pMB->sad8 );
802    
803                            if (Data.chroma) {
804                                    pMB->sad16 += sad8(pCurrent->u + x*8 + y*(pParam->edged_width/2)*8,
805                                                                    pRef->u + x*8 + y*(pParam->edged_width/2)*8, pParam->edged_width/2);
806    
807                                    pMB->sad16 += sad8(pCurrent->v + (x + y*(pParam->edged_width/2))*8,
808                                                                    pRef->v + (x + y*(pParam->edged_width/2))*8, pParam->edged_width/2);
809                            }
810    
811                            sad00 = pMB->sad16; //if no gmc; else sad00 = (..)
812    
813                            if (!(current->global_flags & XVID_LUMIMASKING)) {
814                                    pMB->dquant = NO_CHANGE;
815                                    pMB->quant = current->quant;
816          } else {          } else {
817                  int bDirection = 1 + 2 + 4 + 8;                                  if (pMB->dquant != NO_CHANGE) {
818                                            quant += DQtab[pMB->dquant];
819                                            if (quant > 31) quant = 31;
820                                            else if (quant < 1) quant = 1;
821                                    }
822                                    pMB->quant = quant;
823                            }
824    
825                  do {  //initial skip decision
826                          iDirection = 0;  /* no early skip for GMC (global vector = skip vector is unknown!)  */
827                          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)                          if (current->coding_type == P_VOP)      { /* no fast SKIP for S(GMC)-VOPs */
828                                  CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);                                  if (pMB->dquant == NO_CHANGE && sad00 < pMB->quant * INITIAL_SKIP_THRESH  * (Data.rrv ? 4:1) )
829                                            if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, pParam->edged_width, pMB->quant, Data.rrv)) {
830                                                    SkipMacroblockP(pMB, sad00);
831                                                    continue;
832                                            }
833                            }
834    
835                          if (bDirection & 2)                          SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
836                                  CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);                                                  y, current->motion_flags, pMB->quant,
837                                                    &Data, pParam, pMBs, reference->mbs,
838                                                    current->global_flags & XVID_INTER4V, pMB);
839    
840    /* final skip decision, a.k.a. "the vector you found, really that good?" */
841                            if (current->coding_type == P_VOP)      {
842                                    if ( (pMB->dquant == NO_CHANGE) && (sad00 < pMB->quant * MAX_SAD00_FOR_SKIP)
843                                            && ((100*pMB->sad16)/(sad00+1) > FINAL_SKIP_THRESH * (Data.rrv ? 4:1)) )
844                                            if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, pParam->edged_width, pMB->quant, Data.rrv)) {
845                                                    SkipMacroblockP(pMB, sad00);
846                                                    continue;
847                                            }
848                            }
849    
850                          if (bDirection & 4)  /* finally, intra decision */
                                 CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);  
851    
852                          if (bDirection & 8)                          InterBias = MV16_INTER_BIAS;
853                                  CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);                          if (pMB->quant > 8)  InterBias += 100 * (pMB->quant - 8); // to make high quants work
854                            if (y != 0)
855                                    if ((pMB - pParam->mb_width)->mode == MODE_INTRA ) InterBias -= 80;
856                            if (x != 0)
857                                    if ((pMB - 1)->mode == MODE_INTRA ) InterBias -= 80;
858    
859                          /* now we're doing diagonal checks near our candidate */                          if (Data.chroma) InterBias += 50; // to compensate bigger SAD
860                            if (Data.rrv) InterBias *= 4; //??
861    
862                          if (iDirection)         //checking if anything found                          if (InterBias < pMB->sad16)  {
863                          {                                  int32_t deviation;
864                                  bDirection = iDirection;                                  if (Data.rrv) {
865                                  iDirection = 0;                                          deviation = dev16(pCurrent->y + (x + y * pParam->edged_width) * 32,
866                                  start_x = currMV->x;                                                                                  pParam->edged_width)
867                                  start_y = currMV->y;                                                  + dev16(pCurrent->y + (x + y * pParam->edged_width) * 32 + 16,
868                                  if (bDirection & 3)     //our candidate is left or right                                                                                  pParam->edged_width)
869                                  {                                                  + dev16(pCurrent->y + (x + y * pParam->edged_width) * 32 + 16 * pParam->edged_width,
870                                          CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);                                                                                  pParam->edged_width)
871                                          CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);                                                  + dev16(pCurrent->y + (x + y * pParam->edged_width) * 32 + 16 * (pParam->edged_width+1),
872                                  } else                  // what remains here is up or down                                                                                  pParam->edged_width);
873                                  {                                  } else
874                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize, start_y, 2);                                          deviation = dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,
875                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);                                                    pParam->edged_width);
                                 }  
876    
877                                  if (iDirection) {                                          if (deviation < (pMB->sad16 - InterBias)) {
878                                          bDirection += iDirection;                                          if (++iIntra >= iLimit) { free(qimage); return 1; }
879                                          start_x = currMV->x;                                          pMB->mode = MODE_INTRA;
880                                          start_y = currMV->y;                                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =
881                                                            pMB->mvs[3] = zeroMV;
882                                            pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] =
883                                                            pMB->qmvs[3] = zeroMV;
884                                            pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =
885                                                    pMB->sad8[3] = 0;
886                                  }                                  }
                         } else                          //about to quit, eh? not so fast....  
                         {  
                                 switch (bDirection) {  
                                 case 2:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 2 + 4:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 4:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         break;  
                                 case 8:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         break;  
                                 case 1 + 4:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         break;  
                                 case 2 + 8:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 case 1 + 8:  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         break;  
                                 default:                //1+2+4+8 == we didn't find anything at all  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                         start_y + iDiamondSize, 1 + 8);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y - iDiamondSize, 2 + 4);  
                                         CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,  
                                                                                         start_y + iDiamondSize, 2 + 8);  
                                         break;  
                                 }  
                                 if (!(iDirection))  
                                         break;          //ok, the end. really  
                                 else {  
                                         bDirection = iDirection;  
                                         start_x = currMV->x;  
                                         start_y = currMV->y;  
                                 }  
                         }  
                 }  
                 while (1);                              //forever  
         }  
         return iMinSAD;  
 }  
   
   
 int32_t  
 Full8_MainSearch(const uint8_t * const pRef,  
                                  const uint8_t * const pRefH,  
                                  const uint8_t * const pRefV,  
                                  const uint8_t * const pRefHV,  
                                  const uint8_t * const cur,  
                                  const int x,  
                                  const int y,  
                            const int start_x,  
                            const int start_y,  
                            int iMinSAD,  
                            VECTOR * const currMV,  
                            const int center_x,  
                            const int center_y,  
                                  const int32_t min_dx,  
                                  const int32_t max_dx,  
                                  const int32_t min_dy,  
                                  const int32_t max_dy,  
                                  const int32_t iEdgedWidth,  
                                  const int32_t iDiamondSize,  
                                  const int32_t iFcode,  
                                  const int32_t iQuant,  
                                  int iFound)  
 {  
         int32_t iSAD;  
         int32_t dx, dy;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV8_CANDIDATE(dx, dy);  
   
         return iMinSAD;  
 }  
   
 Halfpel8_RefineFuncPtr Halfpel8_Refine;  
   
 int32_t  
 Halfpel16_Refine(const uint8_t * const pRef,  
                                  const uint8_t * const pRefH,  
                                  const uint8_t * const pRefV,  
                                  const uint8_t * const pRefHV,  
                                  const uint8_t * const cur,  
                                  const int x,  
                                  const int y,  
                                  VECTOR * const currMV,  
                                  int32_t iMinSAD,  
                            const int center_x,  
                            const int center_y,  
                                  const int32_t min_dx,  
                                  const int32_t max_dx,  
                                  const int32_t min_dy,  
                                  const int32_t max_dy,  
                                  const int32_t iFcode,  
                                  const int32_t iQuant,  
                                  const int32_t iEdgedWidth)  
 {  
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
   
         int32_t iSAD;  
         VECTOR backupMV = *currMV;  
   
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y - 1);  
         CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y - 1);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y - 1);  
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y + 1);  
         CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y + 1);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y + 1);  
   
         return iMinSAD;  
 }  
   
 #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)  
   
   
   
 int32_t  
 PMVfastSearch16(const uint8_t * const pRef,  
                                 const uint8_t * const pRefH,  
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const IMAGE * const pCur,  
                                 const int x,  
                                 const int y,  
                                 const int start_x,      /* start is searched first, so it should contain the most */  
                                 const int start_y,  /* likely motion vector for this block */  
                                 const int center_x,     /* center is from where length of MVs is measured */  
                                 const int center_y,  
                                 const uint32_t MotionFlags,  
                                 const uint32_t iQuant,  
                                 const uint32_t iFcode,  
                                 const MBParam * const pParam,  
                                 const MACROBLOCK * const pMBs,  
                                 const MACROBLOCK * const prevMBs,  
                                 VECTOR * const currMV,  
                                 VECTOR * const currPMV)  
 {  
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
   
         const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;  
   
         int32_t iDiamondSize;  
   
         int32_t min_dx;  
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
   
         int32_t iFound;  
   
         VECTOR newMV;  
         VECTOR backupMV;                        /* just for PMVFAST */  
   
         VECTOR pmv[4];  
         int32_t psad[4];  
   
         MainSearch16FuncPtr MainSearchPtr;  
   
         const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;  
   
         int32_t threshA, threshB;  
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD;  
   
 /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
   
 /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  
   
         if (!(MotionFlags & PMV_HALFPEL16)) {  
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
         }  
   
         /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
         //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);  
   
         if ((x == 0) && (y == 0)) {  
                 threshA = 512;  
                 threshB = 1024;  
         } else {  
                 threshA = psad[0];  
                 threshB = threshA + 256;  
                 if (threshA < 512)  
                         threshA = 512;  
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
         }  
   
         iFound = 0;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
   
         currMV->x = start_x;  
         currMV->y = start_y;  
   
         if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */  
                 currMV->x = EVEN(currMV->x);  
                 currMV->y = EVEN(currMV->y);  
         }  
   
         if (currMV->x > max_dx) {  
                 currMV->x = max_dx;  
         }  
         if (currMV->x < min_dx) {  
                 currMV->x = min_dx;  
         }  
         if (currMV->y > max_dy) {  
                 currMV->y = max_dy;  
         }  
         if (currMV->y < min_dy) {  
                 currMV->y = min_dy;  
         }  
   
         iMinSAD =  
                 sad16(cur,  
                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode  
                 {  
                         if (!MVzero(*currMV)) {  
                                 iMinSAD += MV16_00_BIAS;  
                                 CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures  
                                 iMinSAD -= MV16_00_BIAS;  
                         }  
                 }  
   
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
         }  
   
   
 /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  
    vector of the median.  
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
   
         if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[0])))  
                 iFound = 2;  
   
 /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.  
    Otherwise select large Diamond Search.  
 */  
   
         if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))  
                 iDiamondSize = 1;               // halfpel!  
         else  
                 iDiamondSize = 2;               // halfpel!  
   
         if (!(MotionFlags & PMV_HALFPELDIAMOND16))  
                 iDiamondSize *= 2;  
   
 /*  
    Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  
    Also calculate (0,0) but do not subtract offset.  
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset.  
 */  
   
 // (0,0) is always possible  
   
         if (!MVzero(pmv[0]))  
                 CHECK_MV16_ZERO;  
   
 // previous frame MV is always possible  
   
         if (!MVzero(prevMB->mvs[0]))  
                 if (!MVequal(prevMB->mvs[0], pmv[0]))  
                         CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);  
   
 // left neighbour, if allowed  
   
         if (!MVzero(pmv[1]))  
                 if (!MVequal(pmv[1], prevMB->mvs[0]))  
                         if (!MVequal(pmv[1], pmv[0])) {  
                                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                                         pmv[1].x = EVEN(pmv[1].x);  
                                         pmv[1].y = EVEN(pmv[1].y);  
                                 }  
   
                                 CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
                         }  
 // top neighbour, if allowed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], prevMB->mvs[0]))  
                         if (!MVequal(pmv[2], pmv[0]))  
                                 if (!MVequal(pmv[2], pmv[1])) {  
                                         if (!(MotionFlags & PMV_HALFPEL16)) {  
                                                 pmv[2].x = EVEN(pmv[2].x);  
                                                 pmv[2].y = EVEN(pmv[2].y);  
                                         }  
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed  
                                         if (!MVzero(pmv[3]))  
                                                 if (!MVequal(pmv[3], prevMB->mvs[0]))  
                                                         if (!MVequal(pmv[3], pmv[0]))  
                                                                 if (!MVequal(pmv[3], pmv[1]))  
                                                                         if (!MVequal(pmv[3], pmv[2])) {  
                                                                                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                                                                                         pmv[3].x = EVEN(pmv[3].x);  
                                                                                         pmv[3].y = EVEN(pmv[3].y);  
                                                                                 }  
                                                                                 CHECK_MV16_CANDIDATE(pmv[3].x,  
                                                                                                                          pmv[3].y);  
                                                                         }  
                                 }  
   
         if ((MVzero(*currMV)) &&  
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV16_00_BIAS;  
   
   
 /* Step 6: If MinSAD <= thresa goto Step 10.  
    If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
 */  
   
         if ((iMinSAD <= threshA) ||  
                 (MVequal(*currMV, prevMB->mvs[0]) &&  
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
         }  
   
   
 /************ (Diamond Search)  **************/  
 /*  
    Step 7: Perform Diamond search, with either the small or large diamond.  
    If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
    Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
    If center then goto step 10.  
    Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
    Refine by using small diamond and goto step 10.  
 */  
   
         if (MotionFlags & PMV_USESQUARES16)  
                 MainSearchPtr = Square16_MainSearch;  
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
   
         backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  
   
   
 /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                   currMV->x, currMV->y, iMinSAD, &newMV, center_x, center_y,  
                                                   min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
   
         if (MotionFlags & PMV_EXTSEARCH16) {  
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
   
                 if (!(MVequal(pmv[0], backupMV))) {  
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                                   center_x, center_y, iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
                 }  
   
                 if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {  
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy,  
                                                                   iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
                 }  
         }  
   
 /*  
    Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  
 */  
   
   PMVfast16_Terminate_with_Refine:  
         if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step  
                 iMinSAD =  
                         Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
   
   PMVfast16_Terminate_without_Refine:  
         currPMV->x = currMV->x - center_x;  
         currPMV->y = currMV->y - center_y;  
         return iMinSAD;  
 }  
   
   
   
   
   
   
 int32_t  
 Diamond8_MainSearch(const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x,  
                                         const int y,  
                                         int32_t start_x,  
                                         int32_t start_y,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a diamond search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iDirectionBackup;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
   
         CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
   
         if (iDirection) {  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;     // since iDirection!=0, this is well defined!  
                         iDirectionBackup = iDirection;  
   
                         if (iDirectionBackup != 2)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                   backupMV.y, 1);  
                         if (iDirectionBackup != 1)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                   backupMV.y, 2);  
                         if (iDirectionBackup != 4)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y - iDiamondSize, 3);  
                         if (iDirectionBackup != 3)  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x,  
                                                                                   backupMV.y + iDiamondSize, 4);  
                 }  
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
         }  
         return iMinSAD;  
 }  
   
   
   
   
 int32_t  
 Square8_MainSearch(const uint8_t * const pRef,  
                                         const uint8_t * const pRefH,  
                                         const uint8_t * const pRefV,  
                                         const uint8_t * const pRefHV,  
                                         const uint8_t * const cur,  
                                         const int x,  
                                         const int y,  
                                         int32_t start_x,  
                                         int32_t start_y,  
                                         int32_t iMinSAD,  
                                         VECTOR * const currMV,  
                                    const int center_x,  
                                    const int center_y,  
                                         const int32_t min_dx,  
                                         const int32_t max_dx,  
                                         const int32_t min_dy,  
                                         const int32_t max_dy,  
                                         const int32_t iEdgedWidth,  
                                         const int32_t iDiamondSize,  
                                         const int32_t iFcode,  
                                         const int32_t iQuant,  
                                         int iFound)  
 {  
 /* Do a square search around given starting point, return SAD of best */  
   
         int32_t iDirection = 0;  
         int32_t iSAD;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
 /* It's one search with full square pattern, and new parts for all following diamonds */  
   
 /*   new direction are extra, so 1-4 is normal diamond  
       537  
       1*2  
       648  
 */  
   
         CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);  
   
         CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 5);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 6);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y - iDiamondSize, 7);  
         CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize,  
                                                          backupMV.y + iDiamondSize, 8);  
   
   
         if (iDirection) {  
                 while (!iFound) {  
                         iFound = 1;  
                         backupMV = *currMV;  
   
                         switch (iDirection) {  
                         case 1:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                    backupMV.y, 1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
                         case 2:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
   
                         case 3:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
   
                         case 4:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 break;  
   
                         case 5:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 break;  
   
                         case 6:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
   
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
   
                                 break;  
   
                         case 7:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                    backupMV.y, 1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
   
                         case 8:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         default:  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize, backupMV.y,  
                                                                                  1);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize, backupMV.y,  
                                                                                  2);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y - iDiamondSize,  
                                                                                  3);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x, backupMV.y + iDiamondSize,  
                                                                                  4);  
   
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 5);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x - iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 6);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y - iDiamondSize, 7);  
                                 CHECK_MV8_CANDIDATE_FOUND(backupMV.x + iDiamondSize,  
                                                                                  backupMV.y + iDiamondSize, 8);  
                                 break;  
                         }  
                 }  
         } else {  
                 currMV->x = start_x;  
                 currMV->y = start_y;  
         }  
         return iMinSAD;  
 }  
   
   
   
   
   
 int32_t  
 Halfpel8_Refine_c(const uint8_t * const pRef,  
                                 const uint8_t * const pRefH,  
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const uint8_t * const cur,  
                                 const int x,  
                                 const int y,  
                                 VECTOR * const currMV,  
                                 int32_t iMinSAD,  
                            const int center_x,  
                            const int center_y,  
                                 const int32_t min_dx,  
                                 const int32_t max_dx,  
                                 const int32_t min_dy,  
                                 const int32_t max_dy,  
                                 const int32_t iFcode,  
                                 const int32_t iQuant,  
                                 const int32_t iEdgedWidth)  
 {  
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
   
         int32_t iSAD;  
         VECTOR backupMV = *currMV;  
   
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y - 1);  
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y);  
         CHECK_MV8_CANDIDATE(backupMV.x - 1, backupMV.y + 1);  
         CHECK_MV8_CANDIDATE(backupMV.x, backupMV.y + 1);  
         CHECK_MV8_CANDIDATE(backupMV.x + 1, backupMV.y + 1);  
   
         return iMinSAD;  
 }  
   
   
 #define PMV_HALFPEL8 (PMV_HALFPELDIAMOND8|PMV_HALFPELREFINE8)  
   
 int32_t  
 PMVfastSearch8(const uint8_t * const pRef,  
                            const uint8_t * const pRefH,  
                            const uint8_t * const pRefV,  
                            const uint8_t * const pRefHV,  
                            const IMAGE * const pCur,  
                            const int x,  
                            const int y,  
                            const int start_x,  
                            const int start_y,  
                                 const int center_x,  
                                 const int center_y,  
                            const uint32_t MotionFlags,  
                            const uint32_t iQuant,  
                            const uint32_t iFcode,  
                            const MBParam * const pParam,  
                            const MACROBLOCK * const pMBs,  
                            const MACROBLOCK * const prevMBs,  
                            VECTOR * const currMV,  
                            VECTOR * const currPMV)  
 {  
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
   
         const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;  
   
         int32_t iDiamondSize;  
   
         int32_t min_dx;  
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
   
         VECTOR pmv[4];  
         int32_t psad[4];  
         VECTOR newMV;  
         VECTOR backupMV;  
         VECTOR startMV;  
   
 //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;  
         const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;  
   
          int32_t threshA, threshB;  
         int32_t iFound, bPredEq;  
         int32_t iMinSAD, iSAD;  
   
         int32_t iSubBlock = (y & 1) + (y & 1) + (x & 1);  
   
         MainSearch8FuncPtr MainSearchPtr;  
   
         /* Init variables */  
         startMV.x = start_x;  
         startMV.y = start_y;  
   
         /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,  
                           iFcode);  
   
         if (!(MotionFlags & PMV_HALFPELDIAMOND8)) {  
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
         }  
   
         /* because we might use IF (dx>max_dx) THEN dx=max_dx; */  
         //bPredEq = get_pmvdata(pMBs, (x >> 1), (y >> 1), iWcount, iSubBlock, pmv, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, (x >> 1), (y >> 1), iSubBlock, pmv, psad);  
   
         if ((x == 0) && (y == 0)) {  
                 threshA = 512 / 4;  
                 threshB = 1024 / 4;  
   
         } else {  
                 threshA = psad[0] / 4;  /* good estimate? */  
                 threshB = threshA + 256 / 4;  
                 if (threshA < 512 / 4)  
                         threshA = 512 / 4;  
                 if (threshA > 1024 / 4)  
                         threshA = 1024 / 4;  
                 if (threshB > 1792 / 4)  
                         threshB = 1792 / 4;  
         }  
   
         iFound = 0;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
   
   
 // Prepare for main loop  
   
   if (MotionFlags & PMV_USESQUARES8)  
       MainSearchPtr = Square8_MainSearch;  
   else  
   
         if (MotionFlags & PMV_ADVANCEDDIAMOND8)  
                 MainSearchPtr = AdvDiamond8_MainSearch;  
         else  
                 MainSearchPtr = Diamond8_MainSearch;  
   
   
         *currMV = startMV;  
   
         iMinSAD =  
                 sad8(cur,  
                          get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  
                                                 iEdgedWidth), iEdgedWidth);  
         iMinSAD +=  
                 calc_delta_8(currMV->x - center_x, currMV->y - center_y,  
                                          (uint8_t) iFcode, iQuant);  
   
         if ((iMinSAD < 256 / 4) || ((MVequal(*currMV, prevMB->mvs[iSubBlock]))  
                                                                 && ((int32_t) iMinSAD <  
                                                                         prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  
    vector of the median.  
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
   
         if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[iSubBlock])))  
                 iFound = 2;  
   
 /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.  
    Otherwise select large Diamond Search.  
 */  
   
         if ((!MVzero(pmv[0])) || (threshB < 1536 / 4) || (bPredEq))  
                 iDiamondSize = 1;               // 1 halfpel!  
         else  
                 iDiamondSize = 2;               // 2 halfpel = 1 full pixel!  
   
         if (!(MotionFlags & PMV_HALFPELDIAMOND8))  
                 iDiamondSize *= 2;  
   
   
 /*  
    Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  
    Also calculate (0,0) but do not subtract offset.  
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset.  
 */  
   
 // the median prediction might be even better than mv16  
   
         if (!MVequal(pmv[0], startMV))  
                 CHECK_MV8_CANDIDATE(center_x, center_y);  
   
 // (0,0) if needed  
         if (!MVzero(pmv[0]))  
                 if (!MVzero(startMV))  
                         CHECK_MV8_ZERO;  
   
 // previous frame MV if needed  
         if (!MVzero(prevMB->mvs[iSubBlock]))  
                 if (!MVequal(prevMB->mvs[iSubBlock], startMV))  
                         if (!MVequal(prevMB->mvs[iSubBlock], pmv[0]))  
                                 CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x,  
                                                                         prevMB->mvs[iSubBlock].y);  
   
         if ((iMinSAD <= threshA) ||  
                 (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&  
                  ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 // left neighbour, if allowed and needed  
         if (!MVzero(pmv[1]))  
                 if (!MVequal(pmv[1], startMV))  
                         if (!MVequal(pmv[1], prevMB->mvs[iSubBlock]))  
                                 if (!MVequal(pmv[1], pmv[0])) {  
                                         if (!(MotionFlags & PMV_HALFPEL8)) {  
                                                 pmv[1].x = EVEN(pmv[1].x);  
                                                 pmv[1].y = EVEN(pmv[1].y);  
                                         }  
                                         CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);  
                                 }  
 // top neighbour, if allowed and needed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], startMV))  
                         if (!MVequal(pmv[2], prevMB->mvs[iSubBlock]))  
                                 if (!MVequal(pmv[2], pmv[0]))  
                                         if (!MVequal(pmv[2], pmv[1])) {  
                                                 if (!(MotionFlags & PMV_HALFPEL8)) {  
                                                         pmv[2].x = EVEN(pmv[2].x);  
                                                         pmv[2].y = EVEN(pmv[2].y);  
                                                 }  
                                                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed and needed  
                                                 if (!MVzero(pmv[3]))  
                                                         if (!MVequal(pmv[3], startMV))  
                                                                 if (!MVequal(pmv[3], prevMB->mvs[iSubBlock]))  
                                                                         if (!MVequal(pmv[3], pmv[0]))  
                                                                                 if (!MVequal(pmv[3], pmv[1]))  
                                                                                         if (!MVequal(pmv[3], pmv[2])) {  
                                                                                                 if (!  
                                                                                                         (MotionFlags &  
                                                                                                          PMV_HALFPEL8)) {  
                                                                                                         pmv[3].x = EVEN(pmv[3].x);  
                                                                                                         pmv[3].y = EVEN(pmv[3].y);  
                                                                                                 }  
                                                                                                 CHECK_MV8_CANDIDATE(pmv[3].x,  
                                                                                                                                         pmv[3].y);  
                                                                                         }  
                                         }  
   
         if ((MVzero(*currMV)) &&  
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV8_00_BIAS;  
   
   
 /* Step 6: If MinSAD <= thresa goto Step 10.  
    If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
 */  
   
         if ((iMinSAD <= threshA) ||  
                 (MVequal(*currMV, prevMB->mvs[iSubBlock]) &&  
                  ((int32_t) iMinSAD < prevMB->sad8[iSubBlock]))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast8_Terminate_with_Refine;  
         }  
   
 /************ (Diamond Search)  **************/  
 /*  
    Step 7: Perform Diamond search, with either the small or large diamond.  
    If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
    Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
    If center then goto step 10.  
    Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
    Refine by using small diamond and goto step 10.  
 */  
   
         backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  
   
 /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  
         iSAD =  
                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,  
                                                   currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
   
         if (MotionFlags & PMV_EXTSEARCH8) {  
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
   
                 if (!(MVequal(pmv[0], backupMV))) {  
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
                 }  
   
                 if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {  
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
                         }  
                 }  
         }  
   
 /* Step 10: The motion vector is chosen according to the block corresponding to MinSAD.  
    By performing an optional local half-pixel search, we can refine this result even further.  
 */  
   
   PMVfast8_Terminate_with_Refine:  
         if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step  
                 iMinSAD =  
                         Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                         iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                         iFcode, iQuant, iEdgedWidth);  
   
   
   PMVfast8_Terminate_without_Refine:  
         currPMV->x = currMV->x - center_x;  
         currPMV->y = currMV->y - center_y;  
   
         return iMinSAD;  
 }  
   
 int32_t  
 EPZSSearch16(const uint8_t * const pRef,  
                          const uint8_t * const pRefH,  
                          const uint8_t * const pRefV,  
                          const uint8_t * const pRefHV,  
                          const IMAGE * const pCur,  
                          const int x,  
                          const int y,  
                         const int start_x,  
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
                          const uint32_t MotionFlags,  
                          const uint32_t iQuant,  
                          const uint32_t iFcode,  
                          const MBParam * const pParam,  
                          const MACROBLOCK * const pMBs,  
                          const MACROBLOCK * const prevMBs,  
                          VECTOR * const currMV,  
                          VECTOR * const currPMV)  
 {  
         const uint32_t iWcount = pParam->mb_width;  
         const uint32_t iHcount = pParam->mb_height;  
   
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
   
         const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;  
   
         int32_t min_dx;  
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
   
         VECTOR newMV;  
         VECTOR backupMV;  
   
         VECTOR pmv[4];  
         int32_t psad[8];  
   
         static MACROBLOCK *oldMBs = NULL;  
   
 //  const MACROBLOCK * const pMB = pMBs + x + y * iWcount;  
         const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;  
         MACROBLOCK *oldMB = NULL;  
   
          int32_t thresh2;  
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD = 9999;  
   
         MainSearch16FuncPtr MainSearchPtr;  
   
         if (oldMBs == NULL) {  
                 oldMBs = (MACROBLOCK *) calloc(iWcount * iHcount, sizeof(MACROBLOCK));  
 //      fprintf(stderr,"allocated %d bytes for oldMBs\n",iWcount*iHcount*sizeof(MACROBLOCK));  
         }  
         oldMB = oldMBs + x + y * iWcount;  
   
 /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
   
         if (!(MotionFlags & PMV_HALFPEL16)) {  
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
         }  
         /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
         //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);  
   
 /* Step 4: Calculate SAD around the Median prediction.  
         MinSAD=SAD  
         If Motion Vector equal to Previous frame motion vector  
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
 */  
   
 // Prepare for main loop  
   
         currMV->x = start_x;  
         currMV->y = start_y;  
   
         if (!(MotionFlags & PMV_HALFPEL16)) {  
                 currMV->x = EVEN(currMV->x);  
                 currMV->y = EVEN(currMV->y);  
         }  
   
         if (currMV->x > max_dx)  
                 currMV->x = max_dx;  
         if (currMV->x < min_dx)  
                 currMV->x = min_dx;  
         if (currMV->y > max_dy)  
                 currMV->y = max_dy;  
         if (currMV->y < min_dy)  
                 currMV->y = min_dy;  
   
 /***************** This is predictor SET A: only median prediction ******************/  
   
         iMinSAD =  
                 sad16(cur,  
                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
   
 // thresh1 is fixed to 256  
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
         }  
   
 /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/  
   
 // previous frame MV  
         CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);  
   
 // set threshhold based on Min of Prediction and SAD of collocated block  
 // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want  
   
         if ((x == 0) && (y == 0)) {  
                 thresh2 = 512;  
         } else {  
 /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */  
   
                 thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;  
         }  
   
 // MV=(0,0) is often a good choice  
   
         CHECK_MV16_ZERO;  
   
   
 // left neighbour, if allowed  
         if (x != 0) {  
                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                         pmv[1].x = EVEN(pmv[1].x);  
                         pmv[1].y = EVEN(pmv[1].y);  
                 }  
                 CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
         }  
 // top neighbour, if allowed  
         if (y != 0) {  
                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                         pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
                 }  
                 CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed  
                 if ((uint32_t) x != (iWcount - 1)) {  
                         if (!(MotionFlags & PMV_HALFPEL16)) {  
                                 pmv[3].x = EVEN(pmv[3].x);  
                                 pmv[3].y = EVEN(pmv[3].y);  
887                          }                          }
                         CHECK_MV16_CANDIDATE(pmv[3].x, pmv[3].y);  
888                  }                  }
889          }          }
890            free(qimage);
891    
892  /* Terminate if MinSAD <= T_2          if (current->coding_type == S_VOP)      /* first GMC step only for S(GMC)-VOPs */
893     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]                  current->GMC_MV = GlobalMotionEst( pMBs, pParam, current->fcode );
894  */          else
895                    current->GMC_MV = zeroMV;
         if ((iMinSAD <= thresh2)  
                 || (MVequal(*currMV, prevMB->mvs[0]) &&  
                         ((int32_t) iMinSAD <= prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
         }  
   
 /***** predictor SET C: acceleration MV (new!), neighbours in prev. frame(new!) ****/  
   
         backupMV = prevMB->mvs[0];      // collocated MV  
         backupMV.x += (prevMB->mvs[0].x - oldMB->mvs[0].x);     // acceleration X  
         backupMV.y += (prevMB->mvs[0].y - oldMB->mvs[0].y);     // acceleration Y  
   
         CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y);  
   
 // left neighbour  
         if (x != 0)  
                 CHECK_MV16_CANDIDATE((prevMB - 1)->mvs[0].x, (prevMB - 1)->mvs[0].y);  
   
 // top neighbour  
         if (y != 0)  
                 CHECK_MV16_CANDIDATE((prevMB - iWcount)->mvs[0].x,  
                                                          (prevMB - iWcount)->mvs[0].y);  
896    
897  // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs          return 0;
898    }
899    
         if ((uint32_t) x != iWcount - 1)  
                 CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);  
900    
901  // bottom neighbour, dito  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)
         if ((uint32_t) y != iHcount - 1)  
                 CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,  
                                                          (prevMB + iWcount)->mvs[0].y);  
902    
903  /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */  static __inline int
904          if (iMinSAD <= thresh2) {  make_mask(const VECTOR * const pmv, const int i)
905                  if (MotionFlags & PMV_QUICKSTOP16)  {
906                          goto EPZS16_Terminate_without_Refine;          int mask = 255, j;
907                  if (MotionFlags & PMV_EARLYSTOP16)          for (j = 0; j < i; j++) {
908                          goto EPZS16_Terminate_with_Refine;                  if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already
909                    if (pmv[i].x == pmv[j].x) {
910                            if (pmv[i].y == pmv[j].y + iDiamondSize) { mask &= ~4; continue; }
911                            if (pmv[i].y == pmv[j].y - iDiamondSize) { mask &= ~8; continue; }
912                    } else
913                            if (pmv[i].y == pmv[j].y) {
914                                    if (pmv[i].x == pmv[j].x + iDiamondSize) { mask &= ~1; continue; }
915                                    if (pmv[i].x == pmv[j].x - iDiamondSize) { mask &= ~2; continue; }
916                            }
917            }
918            return mask;
919          }          }
920    
921  /************ (if Diamond Search)  **************/  static __inline void
922    PreparePredictionsP(VECTOR * const pmv, int x, int y, int iWcount,
923          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                          int iHcount, const MACROBLOCK * const prevMB, int rrv)
924    {
925    
926          if (MotionFlags & PMV_USESQUARES16)  //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself
927                  MainSearchPtr = Square16_MainSearch;          if (rrv) { iWcount /= 2; iHcount /= 2; }
         else  
          if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
928    
929  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          if ( (y != 0) && (x < (iWcount-1)) ) {          // [5] top-right neighbour
930                    pmv[5].x = EVEN(pmv[3].x);
931                    pmv[5].y = EVEN(pmv[3].y);
932            } else pmv[5].x = pmv[5].y = 0;
933    
934          iSAD =          if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }// pmv[3] is left neighbour
935                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,          else pmv[3].x = pmv[3].y = 0;
                                                   currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);  
   
         if (iSAD < iMinSAD) {  
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
936    
937            if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }// [4] top neighbour
938        else pmv[4].x = pmv[4].y = 0;
939    
940          if (MotionFlags & PMV_EXTSEARCH16) {          // [1] median prediction
941  /* extended mode: search (up to) two more times: orignal prediction and (0,0) */          if (rrv) { //median is in halfzero-precision
942                    pmv[1].x = RRV_MV_SCALEUP(pmv[0].x);
943                    pmv[1].y = RRV_MV_SCALEUP(pmv[0].y);
944            } else { pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y); }
945    
946                  if (!(MVequal(pmv[0], backupMV))) {          pmv[0].x = pmv[0].y = 0; // [0] is zero; not used in the loop (checked before) but needed here for make_mask
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   2, iFcode, iQuant, 0);  
                 }  
947    
948                  if (iSAD < iMinSAD) {          pmv[2].x = EVEN(prevMB->mvs[0].x); // [2] is last frame
949                          *currMV = newMV;          pmv[2].y = EVEN(prevMB->mvs[0].y);
                         iMinSAD = iSAD;  
                 }  
950    
951                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          if ((x < iWcount-1) && (y < iHcount-1)) {
952                          iSAD =                  pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); //[6] right-down neighbour in last frame
953                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                  pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
954                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,          } else pmv[6].x = pmv[6].y = 0;
                                                                   max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);  
955    
956                          if (iSAD < iMinSAD) {          if (rrv) {
957                                  *currMV = newMV;                  int i;
958                                  iMinSAD = iSAD;                  for (i = 0; i < 7; i++) {
959                          }                          pmv[i].x = RRV_MV_SCALEDOWN(pmv[i].x);
960                            pmv[i].x = RRV_MV_SCALEUP(pmv[i].x); // a trick
961                  }                  }
962          }          }
   
 /***************        Choose best MV found     **************/  
   
   EPZS16_Terminate_with_Refine:  
         if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step  
                 iMinSAD =  
                         Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                          iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                          iFcode, iQuant, iEdgedWidth);  
   
   EPZS16_Terminate_without_Refine:  
   
         *oldMB = *prevMB;  
   
         currPMV->x = currMV->x - center_x;  
         currPMV->y = currMV->y - center_y;  
         return iMinSAD;  
963  }  }
964    
965    static void
966  int32_t  SearchP(const IMAGE * const pRef,
 EPZSSearch8(const uint8_t * const pRef,  
967                          const uint8_t * const pRefH,                          const uint8_t * const pRefH,
968                          const uint8_t * const pRefV,                          const uint8_t * const pRefV,
969                          const uint8_t * const pRefHV,                          const uint8_t * const pRefHV,
970                          const IMAGE * const pCur,                          const IMAGE * const pCur,
971                          const int x,                          const int x,
972                          const int y,                          const int y,
                         const int start_x,  
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
973                          const uint32_t MotionFlags,                          const uint32_t MotionFlags,
974                          const uint32_t iQuant,                          const uint32_t iQuant,
975                          const uint32_t iFcode,                  SearchData * const Data,
976                          const MBParam * const pParam,                          const MBParam * const pParam,
977                          const MACROBLOCK * const pMBs,                          const MACROBLOCK * const pMBs,
978                          const MACROBLOCK * const prevMBs,                          const MACROBLOCK * const prevMBs,
979                          VECTOR * const currMV,                  int inter4v,
980                          VECTOR * const currPMV)                  MACROBLOCK * const pMB)
981  {  {
 /* Please not that EPZS might not be a good choice for 8x8-block motion search ! */  
   
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
   
         const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;  
982    
983          int32_t iDiamondSize = 1;          int i, iDirection = 255, mask, threshA;
984            VECTOR pmv[7];
985    
986          int32_t min_dx;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
987          int32_t max_dx;                                                  pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
         int32_t min_dy;  
         int32_t max_dy;  
988    
989          VECTOR newMV;          get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);  //has to be changed to get_pmv(2)()
         VECTOR backupMV;  
   
         VECTOR pmv[4];  
         int32_t psad[8];  
990    
991          const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);          Data->temp[5] = Data->temp[7] = 256*4096; // to reset chroma-sad cache
992            if (Data->rrv) i = 2; else i = 1;
993            Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16*i;
994            Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
995            Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
996    
997  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          Data->Ref = pRef->y + (x + Data->iEdgedWidth*y) * 16*i;
998          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;          Data->RefH = pRefH + (x + Data->iEdgedWidth*y) * 16*i;
999            Data->RefV = pRefV + (x + Data->iEdgedWidth*y) * 16*i;
1000            Data->RefHV = pRefHV + (x + Data->iEdgedWidth*y) * 16*i;
1001            Data->RefCV = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1002            Data->RefCU = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1003    
1004          int32_t bPredEq;          Data->lambda16 = lambda_vec16[iQuant];
1005          int32_t iMinSAD, iSAD = 9999;          Data->lambda8 = lambda_vec8[iQuant];
1006            Data->qpel_precision = 0;
1007    
1008          MainSearch8FuncPtr MainSearchPtr;          if (pMB->dquant != NO_CHANGE) inter4v = 0;
1009    
1010  /* Get maximum range */          for(i = 0;  i < 5; i++)
1011          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,                  Data->currentMV[i].x = Data->currentMV[i].y = 0;
                           iFcode);  
1012    
1013  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          if (pParam->m_quarterpel) Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1014            else Data->predMV = pmv[0];
1015    
1016          if (!(MotionFlags & PMV_HALFPEL8)) {          i = d_mv_bits(0, 0, Data->predMV, Data->iFcode, 0, 0);
1017                  min_dx = EVEN(min_dx);          Data->iMinSAD[0] = pMB->sad16 + (Data->lambda16 * i * pMB->sad16)/1000;
1018                  max_dx = EVEN(max_dx);          Data->iMinSAD[1] = pMB->sad8[0] + (Data->lambda8 * i * (pMB->sad8[0]+NEIGH_8X8_BIAS))/100;
1019                  min_dy = EVEN(min_dy);          Data->iMinSAD[2] = pMB->sad8[1];
1020                  max_dy = EVEN(max_dy);          Data->iMinSAD[3] = pMB->sad8[2];
1021          }          Data->iMinSAD[4] = pMB->sad8[3];
         /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
         //bPredEq = get_pmvdata(pMBs, x >> 1, y >> 1, iWcount, iSubBlock, pmv[0].x, pmv[0].y, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, x >> 1, y >> 1, iSubBlock, pmv, psad);  
1022    
1023            if ((x == 0) && (y == 0)) threshA = 512;
1024            else {
1025                    threshA = Data->temp[0]; // that's when we keep this SAD atm
1026                    if (threshA < 512) threshA = 512;
1027                    if (threshA > 1024) threshA = 1024; }
1028    
1029  /* Step 4: Calculate SAD around the Median prediction.          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
1030          MinSAD=SAD                                          prevMBs + x + y * pParam->mb_width, Data->rrv);
         If Motion Vector equal to Previous frame motion vector  
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
 */  
1031    
1032  // Prepare for main loop          if (Data->rrv) CheckCandidate = CheckCandidate32;
1033            else if (inter4v || Data->chroma) CheckCandidate = CheckCandidate16;
1034                    else CheckCandidate = CheckCandidate16no4v; //for extra speed
1035    
1036    /* main loop. checking all predictions */
1037    
1038          if (!(MotionFlags & PMV_HALFPEL8)) {          for (i = 1; i < 7; i++) {
1039                  currMV->x = EVEN(currMV->x);                  if (!(mask = make_mask(pmv, i)) ) continue;
1040                  currMV->y = EVEN(currMV->y);                  (*CheckCandidate)(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1041                    if (Data->iMinSAD[0] <= threshA) break;
1042          }          }
1043    
1044          if (currMV->x > max_dx)          if ((Data->iMinSAD[0] <= threshA) ||
1045                  currMV->x = max_dx;                          (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
1046          if (currMV->x < min_dx)                          (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16))) {
1047                  currMV->x = min_dx;                  inter4v = 0;
1048          if (currMV->y > max_dy)          } else {
                 currMV->y = max_dy;  
         if (currMV->y < min_dy)  
                 currMV->y = min_dy;  
   
 /***************** This is predictor SET A: only median prediction ******************/  
   
   
         iMinSAD =  
                 sad8(cur,  
                          get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 8, currMV,  
                                                 iEdgedWidth), iEdgedWidth);  
         iMinSAD +=  
                 calc_delta_8(currMV->x - center_x, currMV->y - center_y,  
                                          (uint8_t) iFcode, iQuant);  
1049    
1050                    MainSearchFunc * MainSearchPtr;
1051                    if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1052                    else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1053                            else MainSearchPtr = DiamondSearch;
1054    
1055                    (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
1056    
1057    /* extended search, diamond starting in 0,0 and in prediction.
1058            note that this search is/might be done in halfpel positions,
1059            which makes it more different than the diamond above */
1060    
1061  // thresh1 is fixed to 256                  if (MotionFlags & PMV_EXTSEARCH16) {
1062          if (iMinSAD < 256 / 4) {                          int32_t bSAD;
1063                  if (MotionFlags & PMV_QUICKSTOP8)                          VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
1064                          goto EPZS8_Terminate_without_Refine;                          if (Data->rrv) {
1065                  if (MotionFlags & PMV_EARLYSTOP8)                                  startMV.x = RRV_MV_SCALEUP(startMV.x);
1066                          goto EPZS8_Terminate_with_Refine;                                  startMV.y = RRV_MV_SCALEUP(startMV.y);
1067                            } else
1068                                    if (!(MotionFlags & PMV_HALFPELREFINE16)) // who's gonna use extsearch and no halfpel?
1069                                            startMV.x = EVEN(startMV.x); startMV.y = EVEN(startMV.y);
1070                            if (!(MVequal(startMV, backupMV))) {
1071                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1072    
1073                                    (*CheckCandidate)(startMV.x, startMV.y, 255, &iDirection, Data);
1074                                    (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
1075                                    if (bSAD < Data->iMinSAD[0]) {
1076                                            Data->currentMV[0] = backupMV;
1077                                            Data->iMinSAD[0] = bSAD; }
1078                            }
1079    
1080                            backupMV = Data->currentMV[0];
1081                            if (!MotionFlags & PMV_HALFPELREFINE16 || Data->rrv) startMV.x = startMV.y = 0;
1082                            else startMV.x = startMV.y = 1;
1083                            if (!(MVequal(startMV, backupMV))) {
1084                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1085    
1086                                    (*CheckCandidate)(startMV.x, startMV.y, 255, &iDirection, Data);
1087                                    (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
1088                                    if (bSAD < Data->iMinSAD[0]) {
1089                                            Data->currentMV[0] = backupMV;
1090                                            Data->iMinSAD[0] = bSAD; }
1091                            }
1092                    }
1093            }
1094    
1095            if (MotionFlags & PMV_HALFPELREFINE16) SubpelRefine(Data);
1096    
1097            for(i = 0; i < 5; i++) {
1098                    Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // initialize qpel vectors
1099                    Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
1100            }
1101    
1102            if((Data->qpel) && (MotionFlags & PMV_QUARTERPELREFINE16)) {
1103    
1104                    Data->qpel_precision = 1;
1105                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1106                                    pParam->width, pParam->height, Data->iFcode, 1, 0);
1107    
1108                    SubpelRefine(Data);
1109            }
1110    
1111            if (Data->iMinSAD[0] < (int32_t)iQuant * 30 ) inter4v = 0;
1112            if (inter4v) {
1113                    SearchData Data8;
1114                    Data8.iFcode = Data->iFcode;
1115                    Data8.lambda8 = Data->lambda8;
1116                    Data8.iEdgedWidth = Data->iEdgedWidth;
1117                    Data8.RefQ = Data->RefQ;
1118                    Data8.qpel = Data->qpel;
1119                    Data8.rrv = Data->rrv;
1120                    Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
1121                    Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
1122                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
1123                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
1124    
1125                    if (Data->chroma) {
1126                            int sumx, sumy;
1127    
1128                            if(pParam->m_quarterpel) {
1129                                    sumx = pMB->qmvs[0].x/2 + pMB->qmvs[1].x/2 + pMB->qmvs[2].x/2 + pMB->qmvs[3].x/2;
1130                                    sumy = pMB->qmvs[0].y/2 + pMB->qmvs[1].y/2 + pMB->qmvs[2].y/2 + pMB->qmvs[3].y/2;
1131                            } else {
1132                                    sumx = pMB->mvs[0].x + pMB->mvs[1].x + pMB->mvs[2].x + pMB->mvs[3].x;
1133                                    sumy = pMB->mvs[0].y + pMB->mvs[1].y + pMB->mvs[2].y + pMB->mvs[3].y;
1134          }          }
1135    
1136  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/                          Data->iMinSAD[1] += ChromaSAD(  (sumx >> 3) + roundtab_76[sumx & 0xf],
1137                                                                                            (sumy >> 3) + roundtab_76[sumy & 0xf], Data);
1138                    }
1139            }
1140    
1141            if (Data->rrv) {
1142                            Data->currentMV[0].x = RRV_MV_SCALEDOWN(Data->currentMV[0].x);
1143                            Data->currentMV[0].y = RRV_MV_SCALEDOWN(Data->currentMV[0].y);
1144            }
1145    
1146  // MV=(0,0) is often a good choice          if (!(inter4v) ||
1147          CHECK_MV8_ZERO;                  (Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
1148                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {
1149    // INTER MODE
1150                    pMB->mode = MODE_INTER;
1151                    pMB->mvs[0] = pMB->mvs[1]
1152                            = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
1153    
1154  // previous frame MV                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
1155          CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x, prevMB->mvs[iSubBlock].y);                          pMB->sad8[2] = pMB->sad8[3] =  Data->iMinSAD[0];
1156    
1157  // left neighbour, if allowed                  if(pParam->m_quarterpel) {
1158          if (psad[1] != MV_MAX_ERROR) {                          pMB->qmvs[0] = pMB->qmvs[1]
1159                  if (!(MotionFlags & PMV_HALFPEL8)) {                                  = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1160                          pmv[1].x = EVEN(pmv[1].x);                          pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1161                          pmv[1].y = EVEN(pmv[1].y);                          pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;
1162                    } else {
1163                            pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1164                            pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
1165                  }                  }
1166                  CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);          } else {
1167    // INTER4V MODE; all other things are already set in Search8
1168                    pMB->mode = MODE_INTER4V;
1169                    pMB->sad16 = Data->iMinSAD[1] + Data->iMinSAD[2] +
1170                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * iQuant;
1171          }          }
 // top neighbour, if allowed  
         if (psad[2] != MV_MAX_ERROR) {  
                 if (!(MotionFlags & PMV_HALFPEL8)) {  
                         pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
1172                  }                  }
                 CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);  
1173    
1174  // top right neighbour, if allowed  static void
1175                  if (psad[3] != MV_MAX_ERROR) {  Search8(const SearchData * const OldData,
1176                          if (!(MotionFlags & PMV_HALFPEL8)) {                  const int x, const int y,
1177                                  pmv[3].x = EVEN(pmv[3].x);                  const uint32_t MotionFlags,
1178                                  pmv[3].y = EVEN(pmv[3].y);                  const MBParam * const pParam,
1179                          }                  MACROBLOCK * const pMB,
1180                          CHECK_MV8_CANDIDATE(pmv[3].x, pmv[3].y);                  const MACROBLOCK * const pMBs,
1181                    const int block,
1182                    SearchData * const Data)
1183    {
1184            int i = 0;
1185            Data->iMinSAD = OldData->iMinSAD + 1 + block;
1186            Data->currentMV = OldData->currentMV + 1 + block;
1187            Data->currentQMV = OldData->currentQMV + 1 + block;
1188    
1189            if(pParam->m_quarterpel) {
1190                    Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1191                    if (block != 0) i = d_mv_bits(  Data->currentQMV->x, Data->currentQMV->y,
1192                                                                                    Data->predMV, Data->iFcode, 0, 0);
1193    
1194            } else {
1195                    Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1196                    if (block != 0) {
1197                            if (block != 0) i = d_mv_bits(  Data->currentMV->x, Data->currentMV->y,
1198                                                                                            Data->predMV, Data->iFcode, 0, Data->rrv);
1199                  }                  }
1200          }          }
1201    
1202  /*  // this bias is zero anyway, at the moment!          *(Data->iMinSAD) += (Data->lambda8 * i * (*Data->iMinSAD + NEIGH_8X8_BIAS))/100;
   
         if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)  
                 iMinSAD -= MV8_00_BIAS;  
1203    
1204  */          if (MotionFlags & (PMV_EXTSEARCH8|PMV_HALFPELREFINE8)) {
1205                    if (Data->rrv) i = 2; else i = 1;
1206    
1207  /* Terminate if MinSAD <= T_2                  Data->Ref = OldData->Ref + i*8 * ((block&1) + pParam->edged_width*(block>>1));
1208     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]                  Data->RefH = OldData->RefH + i*8 * ((block&1) + pParam->edged_width*(block>>1));
1209  */                  Data->RefV = OldData->RefV + i*8 * ((block&1) + pParam->edged_width*(block>>1));
1210                    Data->RefHV = OldData->RefHV + i*8 * ((block&1) + pParam->edged_width*(block>>1));
         if (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */  
                 if (MotionFlags & PMV_QUICKSTOP8)  
                         goto EPZS8_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP8)  
                         goto EPZS8_Terminate_with_Refine;  
         }  
1211    
1212  /************ (Diamond Search)  **************/                  Data->Cur = OldData->Cur + i*8 * ((block&1) + pParam->edged_width*(block>>1));
1213                    Data->qpel_precision = 0;
1214    
1215          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1216                                            pParam->width, pParam->height, OldData->iFcode - Data->qpel, 0, Data->rrv);
1217    
1218          if (!(MotionFlags & PMV_HALFPELDIAMOND8))                  if (Data->rrv) CheckCandidate = CheckCandidate16no4v;
1219                  iDiamondSize *= 2;                  else CheckCandidate = CheckCandidate8;
1220    
1221  /* default: use best prediction as starting point for one call of EPZS_MainSearch */                  if (MotionFlags & PMV_EXTSEARCH8) {
1222                            int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
1223    
1224  // there is no EPZS^2 for inter4v at the moment                          MainSearchFunc *MainSearchPtr;
1225                            if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
1226                                    else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1227                                            else MainSearchPtr = DiamondSearch;
1228    
1229    if (MotionFlags & PMV_USESQUARES8)                          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);
       MainSearchPtr = Square8_MainSearch;  
   else  
1230    
1231          if (MotionFlags & PMV_ADVANCEDDIAMOND8)                          if(*(Data->iMinSAD) < temp_sad) {
1232                  MainSearchPtr = AdvDiamond8_MainSearch;                                          Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1233          else                                          Data->currentQMV->y = 2 * Data->currentMV->y;
1234                  MainSearchPtr = Diamond8_MainSearch;                          }
1235                    }
1236    
1237          iSAD =                  if (MotionFlags & PMV_HALFPELREFINE8) {
1238                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,                          int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
                                                   currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, 0);  
1239    
1240                            SubpelRefine(Data); // perform halfpel refine of current best vector
1241    
1242          if (iSAD < iMinSAD) {                          if(*(Data->iMinSAD) < temp_sad) { // we have found a better match
1243                  *currMV = newMV;                                  Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1244                  iMinSAD = iSAD;                                  Data->currentQMV->y = 2 * Data->currentMV->y;
1245                            }
1246          }          }
1247    
1248          if (MotionFlags & PMV_EXTSEARCH8) {                  if(Data->qpel) {
1249  /* extended mode: search (up to) two more times: orignal prediction and (0,0) */                          if((!(Data->currentQMV->x & 1)) && (!(Data->currentQMV->y & 1)) &&
1250                                    (MotionFlags & PMV_QUARTERPELREFINE8)) {
1251                  if (!(MVequal(pmv[0], backupMV))) {                          Data->qpel_precision = 1;
1252                          iSAD =                          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1253                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,                                  pParam->width, pParam->height, OldData->iFcode, 1, 0);
1254                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,                          SubpelRefine(Data);
1255                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,                          }
                                                                   iDiamondSize, iFcode, iQuant, 0);  
   
                         if (iSAD < iMinSAD) {  
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
1256                          }                          }
1257                  }                  }
1258    
1259                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          if (Data->rrv) {
1260                          iSAD =                          Data->currentMV->x = RRV_MV_SCALEDOWN(Data->currentMV->x);
1261                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                          Data->currentMV->y = RRV_MV_SCALEDOWN(Data->currentMV->y);
1262                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,          }
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, 0);  
1263    
1264                          if (iSAD < iMinSAD) {          if(Data->qpel) {
1265                                  *currMV = newMV;                  pMB->pmvs[block].x = Data->currentQMV->x - Data->predMV.x;
1266                                  iMinSAD = iSAD;                  pMB->pmvs[block].y = Data->currentQMV->y - Data->predMV.y;
1267                    pMB->qmvs[block] = *(Data->currentQMV);
1268            } else {
1269                    pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1270                    pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
1271                          }                          }
1272    
1273            pMB->mvs[block] = *(Data->currentMV);
1274            pMB->sad8[block] =  4 * (*Data->iMinSAD);
1275                  }                  }
1276    
1277    /* B-frames code starts here */
1278    
1279    static __inline VECTOR
1280    ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1281    {
1282    /* the stupidiest function ever */
1283            if (mode == MODE_FORWARD) return pMB->mvs[0];
1284            else return pMB->b_mvs[0];
1285          }          }
1286    
1287  /***************        Choose best MV found     **************/  static void __inline
1288    PreparePredictionsBF(VECTOR * const pmv, const int x, const int y,
1289                                                            const uint32_t iWcount,
1290                                                            const MACROBLOCK * const pMB,
1291                                                            const uint32_t mode_curr)
1292    {
1293    
1294    EPZS8_Terminate_with_Refine:          // [0] is prediction
1295          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step          pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
                 iMinSAD =  
                         Halfpel8_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,  
                                                         iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,  
                                                         iFcode, iQuant, iEdgedWidth);  
1296    
1297    EPZS8_Terminate_without_Refine:          pmv[1].x = pmv[1].y = 0; // [1] is zero
1298    
1299          currPMV->x = currMV->x - center_x;          pmv[2] = ChoosePred(pMB, mode_curr);
1300          currPMV->y = currMV->y - center_y;          pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
1301          return iMinSAD;  
1302  }          if ((y != 0)&&(x != (int)(iWcount+1))) {                        // [3] top-right neighbour
1303                    pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
1304                    pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
1305            } else pmv[3].x = pmv[3].y = 0;
1306    
1307            if (y != 0) {
1308                    pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
1309                    pmv[4].x = EVEN(pmv[4].x); pmv[4].y = EVEN(pmv[4].y);
1310            } else pmv[4].x = pmv[4].y = 0;
1311    
1312            if (x != 0) {
1313                    pmv[5] = ChoosePred(pMB-1, mode_curr);
1314                    pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1315            } else pmv[5].x = pmv[5].y = 0;
1316    
1317            if ((x != 0)&&(y != 0)) {
1318                    pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
1319                    pmv[6].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1320            } else pmv[6].x = pmv[6].y = 0;
1321    
1322    // more?
1323    }
1324    
1325    
1326  int32_t  /* search backward or forward, for b-frames */
1327  PMVfastIntSearch16(const uint8_t * const pRef,  static void
1328    SearchBF(       const uint8_t * const pRef,
1329                                  const uint8_t * const pRefH,                                  const uint8_t * const pRefH,
1330                                  const uint8_t * const pRefV,                                  const uint8_t * const pRefV,
1331                                  const uint8_t * const pRefHV,                                  const uint8_t * const pRefHV,
1332                                  const IMAGE * const pCur,                                  const IMAGE * const pCur,
1333                                  const int x,                          const int x, const int y,
                                 const int y,  
                                 const int start_x,              /* start should be most likely vector */  
                                 const int start_y,  
                                 const int center_x,             /* center is from where length of MVs is measured */  
                                 const int center_y,  
1334                                  const uint32_t MotionFlags,                                  const uint32_t MotionFlags,
                                 const uint32_t iQuant,  
1335                                  const uint32_t iFcode,                                  const uint32_t iFcode,
1336                                  const MBParam * const pParam,                                  const MBParam * const pParam,
1337                                  const MACROBLOCK * const pMBs,                          MACROBLOCK * const pMB,
1338                                  const MACROBLOCK * const prevMBs,                          const VECTOR * const predMV,
1339                                  VECTOR * const currMV,                          int32_t * const best_sad,
1340                                  VECTOR * const currPMV)                          const int32_t mode_current,
1341                            SearchData * const Data)
1342  {  {
1343          const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
1344          const int32_t iEdgedWidth = pParam->edged_width;          const int32_t iEdgedWidth = pParam->edged_width;
1345    
1346          const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          int i, iDirection = 255, mask;
1347          const VECTOR zeroMV = { 0, 0 };          VECTOR pmv[7];
1348            MainSearchFunc *MainSearchPtr;
1349            *Data->iMinSAD = MV_MAX_ERROR;
1350            Data->iFcode = iFcode;
1351            Data->qpel_precision = 0;
1352    
1353            Data->Ref = pRef + (x + y * iEdgedWidth) * 16;
1354            Data->RefH = pRefH + (x + y * iEdgedWidth) * 16;
1355            Data->RefV = pRefV + (x + y * iEdgedWidth) * 16;
1356            Data->RefHV = pRefHV + (x + y * iEdgedWidth) * 16;
1357    
1358            Data->predMV = *predMV;
1359    
1360            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1361                                    pParam->width, pParam->height, iFcode - Data->qpel, 0, 0);
1362    
1363            pmv[0] = Data->predMV;
1364            if (Data->qpel) { pmv[0].x /= 2; pmv[0].y /= 2; }
1365            PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);
1366    
1367            Data->currentMV->x = Data->currentMV->y = 0;
1368            CheckCandidate = CheckCandidate16no4v;
1369    
1370    // main loop. checking all predictions
1371            for (i = 0; i < 7; i++) {
1372                    if (!(mask = make_mask(pmv, i)) ) continue;
1373                    CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1374            }
1375    
1376          int32_t iDiamondSize;          if (MotionFlags & PMV_USESQUARES16)
1377                    MainSearchPtr = SquareSearch;
1378            else if (MotionFlags & PMV_ADVANCEDDIAMOND16)
1379                    MainSearchPtr = AdvDiamondSearch;
1380                    else MainSearchPtr = DiamondSearch;
1381    
1382          int32_t min_dx;          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
1383    
1384          int32_t iFound;          SubpelRefine(Data);
1385    
1386          VECTOR newMV;          if (Data->qpel && *Data->iMinSAD < *best_sad + 300) {
1387          VECTOR backupMV;                  Data->currentQMV->x = 2*Data->currentMV->x;
1388                    Data->currentQMV->y = 2*Data->currentMV->y;
1389                    Data->qpel_precision = 1;
1390                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1391                                            pParam->width, pParam->height, iFcode, 1, 0);
1392                    SubpelRefine(Data);
1393            }
1394    
1395    // three bits are needed to code backward mode. four for forward
1396    
1397            if (mode_current == MODE_FORWARD) *Data->iMinSAD +=  4 * Data->lambda16;
1398            else *Data->iMinSAD +=  3 * Data->lambda16;
1399    
1400            if (*Data->iMinSAD < *best_sad) {
1401                    *best_sad = *Data->iMinSAD;
1402                    pMB->mode = mode_current;
1403                    if (Data->qpel) {
1404                            pMB->pmvs[0].x = Data->currentQMV->x - predMV->x;
1405                            pMB->pmvs[0].y = Data->currentQMV->y - predMV->y;
1406                            if (mode_current == MODE_FORWARD)
1407                                    pMB->qmvs[0] = *Data->currentQMV;
1408                            else
1409                                    pMB->b_qmvs[0] = *Data->currentQMV;
1410                    } else {
1411                            pMB->pmvs[0].x = Data->currentMV->x - predMV->x;
1412                            pMB->pmvs[0].y = Data->currentMV->y - predMV->y;
1413                    }
1414                    if (mode_current == MODE_FORWARD) pMB->mvs[0] = *Data->currentMV;
1415                    else pMB->b_mvs[0] = *Data->currentMV;
1416            }
1417            if (mode_current == MODE_FORWARD)  *(Data->currentMV+2) = *Data->currentMV;
1418            else *(Data->currentMV+1) = *Data->currentMV; //we store currmv for interpolate search
1419    
1420          VECTOR pmv[4];  }
         int32_t psad[4];  
1421    
1422          MainSearch16FuncPtr MainSearchPtr;  static void
1423    SkipDecisionB(const IMAGE * const pCur,
1424                              const IMAGE * const f_Ref,
1425                              const IMAGE * const b_Ref,
1426                              MACROBLOCK * const pMB,
1427                              const uint32_t quant,
1428                              const uint32_t x, const uint32_t y,
1429                              const SearchData * const Data)
1430    {
1431            int dx, dy, b_dx, b_dy;
1432            uint32_t sum;
1433    //this is not full chroma compensation, only it's fullpel approximation. should work though
1434            if (Data->qpel) {
1435                    dy = Data->directmvF[0].y/2 + Data->directmvF[1].y/2 +
1436                                    Data->directmvF[2].y/2 + Data->directmvF[3].y/2;
1437    
1438          const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;                  dx = Data->directmvF[0].x/2 + Data->directmvF[1].x/2 +
1439          MACROBLOCK *const pMB = pMBs + x + y * iWcount;                                  Data->directmvF[2].x/2 + Data->directmvF[3].x/2;
1440    
1441          int32_t threshA, threshB;                  b_dy = Data->directmvB[0].y/2 + Data->directmvB[1].y/2 +
1442          int32_t bPredEq;                                  Data->directmvB[2].y/2 + Data->directmvB[3].y/2;
         int32_t iMinSAD, iSAD;  
1443    
1444                    b_dx = Data->directmvB[0].x/2 + Data->directmvB[1].x/2 +
1445                                    Data->directmvB[2].x/2 + Data->directmvB[3].x/2;
1446    
1447  /* Get maximum range */          } else {
1448          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,                  dy = Data->directmvF[0].y + Data->directmvF[1].y +
1449                            iFcode);                                  Data->directmvF[2].y + Data->directmvF[3].y;
1450    
1451  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */                  dx = Data->directmvF[0].x + Data->directmvF[1].x +
1452                                    Data->directmvF[2].x + Data->directmvF[3].x;
1453    
1454          if ((x == 0) && (y == 0)) {                  b_dy = Data->directmvB[0].y + Data->directmvB[1].y +
1455                  threshA = 512;                                  Data->directmvB[2].y + Data->directmvB[3].y;
                 threshB = 1024;  
1456    
1457                  bPredEq = 0;                  b_dx = Data->directmvB[0].x + Data->directmvB[1].x +
1458                  psad[0] = psad[1] = psad[2] = psad[3] = 0;                                  Data->directmvB[2].x + Data->directmvB[3].x;
1459                  *currMV = pmv[0] = pmv[1] = pmv[2] = pmv[3] = zeroMV;          }
1460    
         } else {  
1461    
1462                  bPredEq = get_ipmvdata(pMBs, iWcount, 0, x, y, 0, pmv, psad);          dy = (dy >> 3) + roundtab_76[dy & 0xf];
1463            dx = (dx >> 3) + roundtab_76[dx & 0xf];
1464            b_dy = (b_dy >> 3) + roundtab_76[b_dy & 0xf];
1465            b_dx = (b_dx >> 3) + roundtab_76[b_dx & 0xf];
1466    
1467                  threshA = psad[0];          sum = sad8bi(pCur->u + 8*x + 8*y*(Data->iEdgedWidth/2),
1468                  threshB = threshA + 256;                                          f_Ref->u + (y*8 + dy/2) * (Data->iEdgedWidth/2) + x*8 + dx/2,
1469                  if (threshA < 512)                                          b_Ref->u + (y*8 + b_dy/2) * (Data->iEdgedWidth/2) + x*8 + b_dx/2,
1470                          threshA = 512;                                          Data->iEdgedWidth/2);
1471                  if (threshA > 1024)          sum += sad8bi(pCur->v + 8*x + 8*y*(Data->iEdgedWidth/2),
1472                          threshA = 1024;                                          f_Ref->v + (y*8 + dy/2) * (Data->iEdgedWidth/2) + x*8 + dx/2,
1473                  if (threshB > 1792)                                          b_Ref->v + (y*8 + b_dy/2) * (Data->iEdgedWidth/2) + x*8 + b_dx/2,
1474                          threshB = 1792;                                          Data->iEdgedWidth/2);
1475    
1476                  *currMV = pmv[0];                       /* current best := prediction */          if (sum < 2*MAX_CHROMA_SAD_FOR_SKIP * quant) pMB->mode = MODE_DIRECT_NONE_MV; //skipped
1477          }          }
1478    
         iFound = 0;  
1479    
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
1480    
1481          if (currMV->x > max_dx) {  static __inline uint32_t
1482                  currMV->x = EVEN(max_dx);  SearchDirect(const IMAGE * const f_Ref,
1483          }                                  const uint8_t * const f_RefH,
1484          if (currMV->x < min_dx) {                                  const uint8_t * const f_RefV,
1485                  currMV->x = EVEN(min_dx);                                  const uint8_t * const f_RefHV,
1486          }                                  const IMAGE * const b_Ref,
1487          if (currMV->y > max_dy) {                                  const uint8_t * const b_RefH,
1488                  currMV->y = EVEN(max_dy);                                  const uint8_t * const b_RefV,
1489          }                                  const uint8_t * const b_RefHV,
1490          if (currMV->y < min_dy) {                                  const IMAGE * const pCur,
1491                  currMV->y = EVEN(min_dy);                                  const int x, const int y,
1492          }                                  const uint32_t MotionFlags,
1493                                    const int32_t TRB, const int32_t TRD,
1494                                    const MBParam * const pParam,
1495                                    MACROBLOCK * const pMB,
1496                                    const MACROBLOCK * const b_mb,
1497                                    int32_t * const best_sad,
1498                                    SearchData * const Data)
1499    
1500    {
1501            int32_t skip_sad;
1502            int k;
1503    
1504            MainSearchFunc *MainSearchPtr;
1505    
1506            *Data->iMinSAD = 256*4096;
1507    
1508            Data->Ref = f_Ref->y + (x + Data->iEdgedWidth*y) * 16;
1509            Data->RefH = f_RefH + (x + Data->iEdgedWidth*y) * 16;
1510            Data->RefV = f_RefV + (x + Data->iEdgedWidth*y) * 16;
1511            Data->RefHV = f_RefHV + (x + Data->iEdgedWidth*y) * 16;
1512            Data->bRef = b_Ref->y + (x + Data->iEdgedWidth*y) * 16;
1513            Data->bRefH = b_RefH + (x + Data->iEdgedWidth*y) * 16;
1514            Data->bRefV = b_RefV + (x + Data->iEdgedWidth*y) * 16;
1515            Data->bRefHV = b_RefHV + (x + Data->iEdgedWidth*y) * 16;
1516    
1517            Data->max_dx = 2 * pParam->width - 2 * (x) * 16;
1518            Data->max_dy = 2 * pParam->height - 2 * (y) * 16;
1519            Data->min_dx = -(2 * 16 + 2 * (x) * 16);
1520            Data->min_dy = -(2 * 16 + 2 * (y) * 16);
1521            if (Data->qpel) { //we measure in qpixels
1522                    Data->max_dx *= 2;
1523                    Data->max_dy *= 2;
1524                    Data->min_dx *= 2;
1525                    Data->min_dy *= 2;
1526                    Data->referencemv = b_mb->qmvs;
1527            } else Data->referencemv = b_mb->mvs;
1528            Data->qpel_precision = 0; // it's a trick. it's 1 not 0, but we need 0 here
1529    
1530            for (k = 0; k < 4; k++) {
1531                    pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);
1532                    pMB->b_mvs[k].x = Data->directmvB[k].x = ((TRB - TRD) * Data->referencemv[k].x) / TRD;
1533                    pMB->mvs[k].y = Data->directmvF[k].y = ((TRB * Data->referencemv[k].y) / TRD);
1534                    pMB->b_mvs[k].y = Data->directmvB[k].y = ((TRB - TRD) * Data->referencemv[k].y) / TRD;
1535    
1536          iMinSAD =                  if ( ( pMB->b_mvs[k].x > Data->max_dx ) || ( pMB->b_mvs[k].x < Data->min_dx )
1537                  sad16(cur,                          || ( pMB->b_mvs[k].y > Data->max_dy ) || ( pMB->b_mvs[k].y < Data->min_dy )) {
                           get_iref_mv(pRef, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
1538    
1539          if ((iMinSAD < 256) ||                          *best_sad = 256*4096; // in that case, we won't use direct mode
1540                  ((MVequal(*currMV, prevMB->i_mvs[0])) &&                          pMB->mode = MODE_DIRECT; // just to make sure it doesn't say "MODE_DIRECT_NONE_MV"
1541                   ((int32_t) iMinSAD < prevMB->i_sad16))) {                          pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;
1542                  if (iMinSAD < 2 * iQuant)       // high chances for SKIP-mode                          return 256*4096;
                 {  
                         if (!MVzero(*currMV)) {  
                                 iMinSAD += MV16_00_BIAS;  
                                 CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures  
                                 iMinSAD -= MV16_00_BIAS;  
1543                          }                          }
1544                    if (b_mb->mode != MODE_INTER4V) {
1545                            pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mvs[0];
1546                            pMB->b_mvs[1] = pMB->b_mvs[2] = pMB->b_mvs[3] = pMB->b_mvs[0];
1547                            Data->directmvF[1] = Data->directmvF[2] = Data->directmvF[3] = Data->directmvF[0];
1548                            Data->directmvB[1] = Data->directmvB[2] = Data->directmvB[3] = Data->directmvB[0];
1549                            break;
1550                  }                  }
   
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfastInt16_Terminate_with_Refine;  
1551          }          }
1552    
1553            if (b_mb->mode == MODE_INTER4V) CheckCandidate = CheckCandidateDirect;
1554            else CheckCandidate = CheckCandidateDirectno4v;
1555    
1556  /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion          (*CheckCandidate)(0, 0, 255, &k, Data);
    vector of the median.  
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
   
         if ((bPredEq) && (MVequal(pmv[0], prevMB->i_mvs[0])))  
                 iFound = 2;  
   
 /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.  
    Otherwise select large Diamond Search.  
 */  
   
         if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))  
                 iDiamondSize = 2;               // halfpel units!  
         else  
                 iDiamondSize = 4;               // halfpel units!  
   
 /*  
    Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  
    Also calculate (0,0) but do not subtract offset.  
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset.  
 */  
   
 // (0,0) is often a good choice  
   
         if (!MVzero(pmv[0]))  
                 CHECK_MV16_ZERO;  
   
 // previous frame MV is always possible  
   
         if (!MVzero(prevMB->i_mvs[0]))  
                 if (!MVequal(prevMB->i_mvs[0], pmv[0]))  
                         CHECK_MV16_CANDIDATE(prevMB->i_mvs[0].x, prevMB->i_mvs[0].y);  
   
 // left neighbour, if allowed  
   
         if (!MVzero(pmv[1]))  
                 if (!MVequal(pmv[1], prevMB->i_mvs[0]))  
                         if (!MVequal(pmv[1], pmv[0]))  
                                 CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
   
 // top neighbour, if allowed  
         if (!MVzero(pmv[2]))  
                 if (!MVequal(pmv[2], prevMB->i_mvs[0]))  
                         if (!MVequal(pmv[2], pmv[0]))  
                                 if (!MVequal(pmv[2], pmv[1]))  
                                         CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
   
 // top right neighbour, if allowed  
                                         if (!MVzero(pmv[3]))  
                                                 if (!MVequal(pmv[3], prevMB->i_mvs[0]))  
                                                         if (!MVequal(pmv[3], pmv[0]))  
                                                                 if (!MVequal(pmv[3], pmv[1]))  
                                                                         if (!MVequal(pmv[3], pmv[2]))  
                                                                                 CHECK_MV16_CANDIDATE(pmv[3].x,  
                                                                                                                          pmv[3].y);  
   
         if ((MVzero(*currMV)) &&  
                 (!MVzero(pmv[0])) /* && (iMinSAD <= iQuant * 96) */ )  
                 iMinSAD -= MV16_00_BIAS;  
   
   
 /* Step 6: If MinSAD <= thresa goto Step 10.  
    If Motion Vector equal to Previous frame motion vector and MinSAD<PrevFrmSAD goto Step 10.  
 */  
   
         if ((iMinSAD <= threshA) ||  
                 (MVequal(*currMV, prevMB->i_mvs[0]) &&  
                  ((int32_t) iMinSAD < prevMB->i_sad16))) {  
   
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfastInt16_Terminate_with_Refine;  
         }  
   
   
 /************ (Diamond Search)  **************/  
 /*  
    Step 7: Perform Diamond search, with either the small or large diamond.  
    If Found=2 only examine one Diamond pattern, and afterwards goto step 10  
    Step 8: If small diamond, iterate small diamond search pattern until motion vector lies in the center of the diamond.  
    If center then goto step 10.  
    Step 9: If large diamond, iterate large diamond search pattern until motion vector lies in the center.  
    Refine by using small diamond and goto step 10.  
 */  
1557    
1558          if (MotionFlags & PMV_USESQUARES16)  // initial (fast) skip decision
1559                  MainSearchPtr = Square16_MainSearch;          if (*Data->iMinSAD < pMB->quant * INITIAL_SKIP_THRESH*2) {
1560          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)                  SkipDecisionB(pCur, f_Ref, b_Ref, pMB, x, y, Data->chroma, Data); //possible skip - checking chroma
1561                  MainSearchPtr = AdvDiamond16_MainSearch;                  if (pMB->mode == MODE_DIRECT_NONE_MV) return *Data->iMinSAD; // skip.
1562          else          }
                 MainSearchPtr = Diamond16_MainSearch;  
1563    
1564          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          skip_sad = *Data->iMinSAD;
1565    
1566    //  DIRECT MODE DELTA VECTOR SEARCH.
1567    //      This has to be made more effective, but at the moment I'm happy it's running at all
1568    
1569  /* default: use best prediction as starting point for one call of PMVfast_MainSearch */          if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1570          iSAD =                  else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1571                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,                          else MainSearchPtr = DiamondSearch;
                                                   currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,  
                                                   min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                   iQuant, iFound);  
1572    
1573          if (iSAD < iMinSAD) {          (*MainSearchPtr)(0, 0, Data, 255);
                 *currMV = newMV;  
                 iMinSAD = iSAD;  
         }  
1574    
1575          if (MotionFlags & PMV_EXTSEARCH16) {          SubpelRefine(Data);
 /* extended: search (up to) two more times: orignal prediction and (0,0) */  
1576    
1577                  if (!(MVequal(pmv[0], backupMV))) {          *best_sad = *Data->iMinSAD;
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  
                                                                   pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,  
                                                                   min_dx, max_dx, min_dy, max_dy, iEdgedWidth,  
                                                                   iDiamondSize, iFcode, iQuant, iFound);  
1578    
1579                          if (iSAD < iMinSAD) {          if (b_mb->mode == MODE_INTER4V || Data->qpel) pMB->mode = MODE_DIRECT;
1580                                  *currMV = newMV;          else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation
                                 iMinSAD = iSAD;  
                         }  
                 }  
1581    
1582                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {          pMB->pmvs[3] = *Data->currentMV;
                         iSAD =  
                                 (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,  
                                                                   iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  
                                                                   max_dy, iEdgedWidth, iDiamondSize, iFcode,  
                                                                   iQuant, iFound);  
1583    
1584                          if (iSAD < iMinSAD) {          for (k = 0; k < 4; k++) {
1585                                  *currMV = newMV;                  pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
1586                                  iMinSAD = iSAD;                  pMB->b_mvs[k].x = (     (Data->currentMV->x == 0)
1587                                                            ? Data->directmvB[k].x
1588                                                            :pMB->mvs[k].x - Data->referencemv[k].x);
1589                    pMB->mvs[k].y = (Data->directmvF[k].y + Data->currentMV->y);
1590                    pMB->b_mvs[k].y = ((Data->currentMV->y == 0)
1591                                                            ? Data->directmvB[k].y
1592                                                            : pMB->mvs[k].y - Data->referencemv[k].y);
1593                    if (Data->qpel) {
1594                            pMB->qmvs[k].x = pMB->mvs[k].x; pMB->mvs[k].x /= 2;
1595                            pMB->b_qmvs[k].x = pMB->b_mvs[k].x; pMB->b_mvs[k].x /= 2;
1596                            pMB->qmvs[k].y = pMB->mvs[k].y; pMB->mvs[k].y /= 2;
1597                            pMB->b_qmvs[k].y = pMB->b_mvs[k].y; pMB->b_mvs[k].y /= 2;
1598                    }
1599    
1600                    if (b_mb->mode != MODE_INTER4V) {
1601                            pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1602                            pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1603                            pMB->qmvs[3] = pMB->qmvs[2] = pMB->qmvs[1] = pMB->qmvs[0];
1604                            pMB->b_qmvs[3] = pMB->b_qmvs[2] = pMB->b_qmvs[1] = pMB->b_qmvs[0];
1605                            break;
1606                          }                          }
1607                  }                  }
1608            return skip_sad;
1609          }          }
1610    
 /*  
    Step 10:  The motion vector is chosen according to the block corresponding to MinSAD.  
 */  
   
 PMVfastInt16_Terminate_with_Refine:  
1611    
1612          pMB->i_mvs[0] = pMB->i_mvs[1] = pMB->i_mvs[2] = pMB->i_mvs[3] = pMB->i_mv16 = *currMV;  static void
1613          pMB->i_sad8[0] = pMB->i_sad8[1] = pMB->i_sad8[2] = pMB->i_sad8[3] = pMB->i_sad16 = iMinSAD;  SearchInterpolate(const uint8_t * const f_Ref,
1614                                    const uint8_t * const f_RefH,
1615          if (MotionFlags & PMV_HALFPELREFINE16)  // perform final half-pel step                                  const uint8_t * const f_RefV,
1616                  iMinSAD =                                  const uint8_t * const f_RefHV,
1617                          Halfpel16_Refine(pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV,                                  const uint8_t * const b_Ref,
1618                                                           iMinSAD, center_x, center_y, min_dx, max_dx, min_dy, max_dy,                                  const uint8_t * const b_RefH,
1619                                                           iFcode, iQuant, iEdgedWidth);                                  const uint8_t * const b_RefV,
1620                                    const uint8_t * const b_RefHV,
1621                                    const IMAGE * const pCur,
1622                                    const int x, const int y,
1623                                    const uint32_t fcode,
1624                                    const uint32_t bcode,
1625                                    const uint32_t MotionFlags,
1626                                    const MBParam * const pParam,
1627                                    const VECTOR * const f_predMV,
1628                                    const VECTOR * const b_predMV,
1629                                    MACROBLOCK * const pMB,
1630                                    int32_t * const best_sad,
1631                                    SearchData * const fData)
1632    
1633          pmv[0] = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          // get _REAL_ prediction (halfpel possible)  {
1634    
1635  PMVfastInt16_Terminate_without_Refine:          int iDirection, i, j;
1636          currPMV->x = currMV->x - center_x;          SearchData bData;
1637          currPMV->y = currMV->y - center_y;  
1638          return iMinSAD;          fData->qpel_precision = 0;
1639  }          memcpy(&bData, fData, sizeof(SearchData)); //quick copy of common data
1640            *fData->iMinSAD = 4096*256;
1641            bData.currentMV++; bData.currentQMV++;
1642            fData->iFcode = bData.bFcode = fcode; fData->bFcode = bData.iFcode = bcode;
1643    
1644            i = (x + y * fData->iEdgedWidth) * 16;
1645            bData.bRef = fData->Ref = f_Ref + i;
1646            bData.bRefH = fData->RefH = f_RefH + i;
1647            bData.bRefV = fData->RefV = f_RefV + i;
1648            bData.bRefHV = fData->RefHV = f_RefHV + i;
1649            bData.Ref = fData->bRef = b_Ref + i;
1650            bData.RefH = fData->bRefH = b_RefH + i;
1651            bData.RefV = fData->bRefV = b_RefV + i;
1652            bData.RefHV = fData->bRefHV = b_RefHV + i;
1653    
1654            bData.bpredMV = fData->predMV = *f_predMV;
1655            fData->bpredMV = bData.predMV = *b_predMV;
1656            fData->currentMV[0] = fData->currentMV[2];
1657    
1658            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);
1659            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);
1660    
1661            if (fData->currentMV[0].x > fData->max_dx) fData->currentMV[0].x = fData->max_dx;
1662            if (fData->currentMV[0].x < fData->min_dx) fData->currentMV[0].x = fData->min_dx;
1663            if (fData->currentMV[0].y > fData->max_dy) fData->currentMV[0].y = fData->max_dy;
1664            if (fData->currentMV[0].y < fData->min_dy) fData->currentMV[0].y = fData->min_dy;
1665    
1666            if (fData->currentMV[1].x > bData.max_dx) fData->currentMV[1].x = bData.max_dx;
1667            if (fData->currentMV[1].x < bData.min_dx) fData->currentMV[1].x = bData.min_dx;
1668            if (fData->currentMV[1].y > bData.max_dy) fData->currentMV[1].y = bData.max_dy;
1669            if (fData->currentMV[1].y < bData.min_dy) fData->currentMV[1].y = bData.min_dy;
1670    
1671            CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, 255, &iDirection, fData);
1672    
1673    //diamond. I wish we could use normal mainsearch functions (square, advdiamond)
1674    
1675  /* ***********************************************************          do {
1676          bvop motion estimation                  iDirection = 255;
1677  ***************************************************************/                  // forward MV moves
1678                    i = fData->currentMV[0].x; j = fData->currentMV[0].y;
1679    
1680                    CheckCandidateInt(i + 1, j, 0, &iDirection, fData);
1681                    CheckCandidateInt(i, j + 1, 0, &iDirection, fData);
1682                    CheckCandidateInt(i - 1, j, 0, &iDirection, fData);
1683                    CheckCandidateInt(i, j - 1, 0, &iDirection, fData);
1684    
1685                    // backward MV moves
1686                    i = fData->currentMV[1].x; j = fData->currentMV[1].y;
1687                    fData->currentMV[2] = fData->currentMV[0];
1688                    CheckCandidateInt(i + 1, j, 0, &iDirection, &bData);
1689                    CheckCandidateInt(i, j + 1, 0, &iDirection, &bData);
1690                    CheckCandidateInt(i - 1, j, 0, &iDirection, &bData);
1691                    CheckCandidateInt(i, j - 1, 0, &iDirection, &bData);
1692    
1693            } while (!(iDirection));
1694    
1695            if (fData->qpel) {
1696                    if (*fData->iMinSAD > *best_sad + 500) return;
1697                    CheckCandidate = CheckCandidateInt;
1698                    fData->qpel_precision = bData.qpel_precision = 1;
1699                    get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode, 1, 0);
1700                    get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode, 1, 0);
1701                    fData->currentQMV[2].x = fData->currentQMV[0].x = 2 * fData->currentMV[0].x;
1702                    fData->currentQMV[2].y = fData->currentQMV[0].y = 2 * fData->currentMV[0].y;
1703                    fData->currentQMV[1].x = 2 * fData->currentMV[1].x;
1704                    fData->currentQMV[1].y = 2 * fData->currentMV[1].y;
1705                    SubpelRefine(fData);
1706                    if (*fData->iMinSAD > *best_sad + 300) return;
1707                    fData->currentQMV[2] = fData->currentQMV[0];
1708                    SubpelRefine(&bData);
1709            }
1710    
1711            *fData->iMinSAD +=  (2+3) * fData->lambda16; // two bits are needed to code interpolate mode.
1712    
1713            if (*fData->iMinSAD < *best_sad) {
1714                    *best_sad = *fData->iMinSAD;
1715                    pMB->mvs[0] = fData->currentMV[0];
1716                    pMB->b_mvs[0] = fData->currentMV[1];
1717                    pMB->mode = MODE_INTERPOLATE;
1718                    if (fData->qpel) {
1719                            pMB->qmvs[0] = fData->currentQMV[0];
1720                            pMB->b_qmvs[0] = fData->currentQMV[1];
1721                            pMB->pmvs[1].x = pMB->qmvs[0].x - f_predMV->x;
1722                            pMB->pmvs[1].y = pMB->qmvs[0].y - f_predMV->y;
1723                            pMB->pmvs[0].x = pMB->b_qmvs[0].x - b_predMV->x;
1724                            pMB->pmvs[0].y = pMB->b_qmvs[0].y - b_predMV->y;
1725                    } else {
1726                            pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;
1727                            pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;
1728                            pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;
1729                            pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;
1730                    }
1731            }
1732    }
1733    
1734  void  void
1735  MotionEstimationBVOP(MBParam * const pParam,  MotionEstimationBVOP(MBParam * const pParam,
# Line 3132  Line 1743 
1743                                           const IMAGE * const f_refV,                                           const IMAGE * const f_refV,
1744                                           const IMAGE * const f_refHV,                                           const IMAGE * const f_refHV,
1745                                           // backward (future) reference                                           // backward (future) reference
1746                                           const MACROBLOCK * const b_mbs,                                           const FRAMEINFO * const b_reference,
1747                                           const IMAGE * const b_ref,                                           const IMAGE * const b_ref,
1748                                           const IMAGE * const b_refH,                                           const IMAGE * const b_refH,
1749                                           const IMAGE * const b_refV,                                           const IMAGE * const b_refV,
1750                                           const IMAGE * const b_refHV)                                           const IMAGE * const b_refHV)
1751  {  {
1752          const int mb_width = pParam->mb_width;          uint32_t i, j;
1753          const int mb_height = pParam->mb_height;          int32_t best_sad;
1754          const int edged_width = pParam->edged_width;          uint32_t skip_sad;
1755            int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
   
         int i, j, k;  
   
1756          static const VECTOR zeroMV={0,0};          static const VECTOR zeroMV={0,0};
1757            const MACROBLOCK * const b_mbs = b_reference->mbs;
         int f_sad16;    /* forward (as usual) search */  
         int b_sad16;    /* backward (only in b-frames) search */  
         int i_sad16;    /* interpolated (both direction, b-frames only) */  
         int d_sad16;    /* direct mode (assume almost linear motion) */  
   
         int best_sad;  
1758    
1759          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
         VECTOR f_interpolMV, b_interpolMV;  
         VECTOR pmv_dontcare;  
   
         int min_dx, max_dx, min_dy, max_dy;  
         int f_min_dx, f_max_dx, f_min_dy, f_max_dy;  
         int b_min_dx, b_max_dx, b_min_dy, b_max_dy;  
   
         int f_count=0;  
         int b_count=0;  
         int i_count=0;  
         int d_count=0;  
1760    
1761          const int64_t TRB = (int32_t)time_pp - (int32_t)time_bp;          const int32_t TRB = time_pp - time_bp;
1762      const int64_t TRD = (int32_t)time_pp;          const int32_t TRD = time_pp;
1763            uint8_t * qimage;
1764    
1765    // some pre-inintialized data for the rest of the search
1766    
1767            SearchData Data;
1768            int32_t iMinSAD;
1769            VECTOR currentMV[3];
1770            VECTOR currentQMV[3];
1771            memset(&Data, 0, sizeof(SearchData));
1772            Data.iEdgedWidth = pParam->edged_width;
1773            Data.currentMV = currentMV; Data.currentQMV = currentQMV;
1774            Data.iMinSAD = &iMinSAD;
1775            Data.lambda16 = lambda_vec16[frame->quant];
1776            Data.chroma = frame->quant;
1777            Data.qpel = pParam->m_quarterpel;
1778            Data.rounding = 0;
1779    
1780            if((qimage = (uint8_t *) malloc(32 * pParam->edged_width)) == NULL)
1781                    return; // allocate some mem for qpel interpolated blocks
1782                                      // somehow this is dirty since I think we shouldn't use malloc outside
1783                                      // encoder_create() - so please fix me!
1784            Data.RefQ = qimage;
1785    
         // fprintf(stderr,"TRB = %lld  TRD = %lld  time_bp =%d time_pp =%d\n\n",TRB,TRD,time_bp,time_pp);  
1786          // note: i==horizontal, j==vertical          // note: i==horizontal, j==vertical
1787          for (j = 0; j < mb_height; j++) {          for (j = 0; j < pParam->mb_height; j++) {
   
                 f_predMV = zeroMV;      /* prediction is reset at left boundary */  
                 b_predMV = zeroMV;  
   
                 for (i = 0; i < mb_width; i++) {  
                         MACROBLOCK *mb = &frame->mbs[i + j * mb_width];  
                         const MACROBLOCK *f_mb = &f_mbs[i + j * mb_width];  
                         const MACROBLOCK *b_mb = &b_mbs[i + j * mb_width];  
1788    
1789                          mb->deltamv=zeroMV;                  f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
1790    
1791  /* special case, if collocated block is SKIPed: encoding is forward (0,0), cpb=0 without further ado */                  for (i = 0; i < pParam->mb_width; i++) {
1792                            MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
1793                          if (b_mb->mode == MODE_INTER && b_mb->cbp == 0 &&                          const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
1794                                  b_mb->mvs[0].x == 0 && b_mb->mvs[0].y == 0) {  
1795                                  mb->mode = MODE_NOT_CODED;  /* special case, if collocated block is SKIPed in P-VOP: encoding is forward (0,0), cpb=0 without further ado */
1796                                  mb->b_mvs[0] = mb->mvs[0] = zeroMV;                          if (b_reference->coding_type != S_VOP)
1797                                    if (b_mb->mode == MODE_NOT_CODED) {
1798                                            pMB->mode = MODE_NOT_CODED;
1799                                  continue;                                  continue;
1800                          }                          }
1801    
1802                          if (b_mb->mode == MODE_INTER4V)                          Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
1803                          {                          pMB->quant = frame->quant;
                                 d_sad16 = 0;  
                         /* same method of scaling as in decoder.c, so we copy from there */  
                     for (k = 0; k < 4; k++) {  
   
                                         mb->directmv[k] = b_mb->mvs[k];  
   
                                         mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);  
                     mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)  
                                                                                 ? ((TRB - TRD) * mb->directmv[k].x) / TRD  
                                             : mb->mvs[k].x - mb->directmv[k].x);  
   
                     mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);  
                         mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)  
                                                                                 ? ((TRB - TRD) * mb->directmv[k].y) / TRD  
                                             : mb->mvs[k].y - mb->directmv[k].y);  
   
                                         d_sad16 +=  
                                                 sad8bi(frame->image.y + (2*i+(k&1))*8 + (2*j+(k>>1))*8*edged_width,  
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 (2*i+(k&1)), (2*j+(k>>1)), 8, &mb->mvs[k], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 (2*i+(k&1)), (2*j+(k>>1)), 8, &mb->b_mvs[k], edged_width),  
                                                   edged_width);  
                                 }  
                         }  
                         else  
                         {  
                                 mb->directmv[3] = mb->directmv[2] = mb->directmv[1] =  
                                         mb->directmv[0] = b_mb->mvs[0];  
1804    
1805                                  mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);  /* direct search comes first, because it (1) checks for SKIP-mode
1806                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)          and (2) sets very good predictions for forward and backward search */
1807                                                                          ? ((TRB - TRD) * mb->directmv[0].x) / TRD                          skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
1808                                      : mb->mvs[0].x - mb->directmv[0].x);                                                                          b_ref, b_refH->y, b_refV->y, b_refHV->y,
1809                                                                            &frame->image,
1810                      mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);                                                                          i, j,
1811                  mb->b_mvs[0].y = (int32_t) ((mb->directmv[0].y == 0)                                                                          frame->motion_flags,
1812                                                                          ? ((TRB - TRD) * mb->directmv[0].y) / TRD                                                                          TRB, TRD,
1813                                      : mb->mvs[0].y - mb->directmv[0].y);                                                                          pParam,
1814                                                                            pMB, b_mb,
1815                                  d_sad16 = sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,                                                                          &best_sad,
1816                                                    get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,                                                                          &Data);
                                                                 i, j, 16, &mb->mvs[0], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 i, j, 16, &mb->b_mvs[0], edged_width),  
                                                   edged_width);  
1817    
1818              }                          if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
                     d_sad16 += calc_delta_16(mb->deltamv.x, mb->deltamv.y, 1, frame->quant);  
1819    
1820                          // forward search                          // forward search
1821                          f_sad16 = SEARCH16(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,                          SearchBF(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
1822                                                  &frame->image, i, j,                                                  &frame->image, i, j,
                                                 mb->mvs[0].x, mb->mvs[0].y,                     /* start point f_directMV */  
                                                 f_predMV.x, f_predMV.y,                         /* center is f-prediction */  
1823                                                  frame->motion_flags,                                                  frame->motion_flags,
1824                                                  frame->quant, frame->fcode, pParam,                                                  frame->fcode, pParam,
1825                                                  f_mbs, f_mbs,                                                  pMB, &f_predMV, &best_sad,
1826                                                  &mb->mvs[0], &pmv_dontcare);                                                  MODE_FORWARD, &Data);
   
1827    
1828                          // backward search                          // backward search
1829                          b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,                          SearchBF(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
1830                                                  &frame->image, i, j,                                                  &frame->image, i, j,
                                                 mb->b_mvs[0].x, mb->b_mvs[0].y,         /* start point b_directMV */  
                                                 b_predMV.x, b_predMV.y,                         /* center is b-prediction */  
1831                                                  frame->motion_flags,                                                  frame->motion_flags,
1832                                                  frame->quant, frame->bcode, pParam,                                                  frame->bcode, pParam,
1833                                                  b_mbs, b_mbs,                                                  pMB, &b_predMV, &best_sad,
1834                                                  &mb->b_mvs[0], &pmv_dontcare);                                                  MODE_BACKWARD, &Data);
1835    
1836                          i_sad16 =                          // interpolate search comes last, because it uses data from forward and backward as prediction
1837                                  sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,                          SearchInterpolate(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
                                                   get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                                 i, j, 16, &mb->mvs[0], edged_width),  
                                                   get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                                 i, j, 16, &mb->b_mvs[0], edged_width),  
                                                   edged_width);  
                     i_sad16 += calc_delta_16(mb->mvs[0].x-f_predMV.x, mb->mvs[0].y-f_predMV.y,  
                                                                 frame->fcode, frame->quant);  
                     i_sad16 += calc_delta_16(mb->b_mvs[0].x-b_predMV.x, mb->b_mvs[0].y-b_predMV.y,  
                                                                 frame->bcode, frame->quant);  
   
                         get_range(&f_min_dx, &f_max_dx, &f_min_dy, &f_max_dy, i, j, 16, iWidth, iHeight,  
                           frame->fcode);  
                         get_range(&b_min_dx, &b_max_dx, &b_min_dy, &b_max_dy, i, j, 16, iWidth, iHeight,  
                           frame->bcode);  
   
 /* Interpolated MC motion vector search, this is tedious and more complicated because there are  
    two values for everything, always one for backward and one for forward ME. Still, we don't gain  
    much from this search, maybe it should simply be skipped and simply current i_sad16 value used  
    as "optimal". */  
   
                         i_sad16 = Diamond16_InterpolMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i * 16 + j * 16 * edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 mb->mvs[0].x, mb->mvs[0].y,  
                                                 mb->b_mvs[0].x, mb->b_mvs[0].y,  
                                                 i_sad16,  
                                                 &f_interpolMV, &b_interpolMV,  
                                                 f_predMV.x, f_predMV.y, b_predMV.x, b_predMV.y,  
                                                 f_min_dx, f_max_dx, f_min_dy, f_max_dy,  
                                                 b_min_dx, b_max_dx, b_min_dy, b_max_dy,  
                                                 edged_width,  2,  
                                                 frame->fcode, frame->bcode,frame->quant,0);  
   
                         i_sad16 = Diamond16_InterpolMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i * 16 + j * 16 * edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 f_interpolMV.x, f_interpolMV.y,  
                                                 b_interpolMV.x, b_interpolMV.y,  
                                                 i_sad16,  
                                                 &f_interpolMV, &b_interpolMV,  
                                                 f_predMV.x, f_predMV.y, b_predMV.x, b_predMV.y,  
                                                 f_min_dx, f_max_dx, f_min_dy, f_max_dy,  
                                                 b_min_dx, b_max_dx, b_min_dy, b_max_dy,  
                                                 edged_width,  1,  
                                                 frame->fcode, frame->bcode,frame->quant,0);             // equiv to halfpel refine  
   
   
 /*  DIRECT MODE DELTA VECTOR SEARCH.  
     This has to be made more effective, but at the moment I'm happy it's running at all */  
   
 /* There are two range restrictions for direct mode: deltaMV is limited to [-32,31] in halfpel units, and  
    absolute vector must not lie outside of image dimensions. Constraint one is dealt with by CHECK_MV16_DIRECT  
    and for constraint two we need distance to boundary. This is done by get_range very large fcode (hack!) */  
   
                         get_range(&min_dx, &max_dx, &min_dy, &max_dy, i, j, 16, iWidth, iHeight, 19);  
   
                         d_sad16 = Diamond16_DirectMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i*16 + j*16*edged_width,  
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
                                                 i, j,  
                                                 TRB,TRD,  
                                                 0,0,  
                                                 d_sad16,  
                                                 &mb->deltamv,  
                                                 mb->directmv, // this has to be pre-initialized with b_mb->mvs[]  
                                         min_dx, max_dx, min_dy, max_dy,  
                                                 edged_width, 2, frame->quant, 0);  
   
                         d_sad16 = Diamond16_DirectMainSearch(  
                                                 f_ref->y, f_refH->y, f_refV->y, f_refHV->y,  
                                                 frame->image.y + i*16 + j*16*edged_width,  
1838                                                  b_ref->y, b_refH->y, b_refV->y, b_refHV->y,                                                  b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
1839                                                    &frame->image,
1840                                                  i, j,                                                  i, j,
1841                                                  TRB,TRD,                                                  frame->fcode, frame->bcode,
1842                                                  mb->deltamv.x, mb->deltamv.y,                                                  frame->motion_flags,
1843                                                  d_sad16,                                                  pParam,
1844                                                  &mb->deltamv,                                                  &f_predMV, &b_predMV,
1845                                                  mb->directmv, // this has to be pre-initialized with b_mb->mvs[]                                                  pMB, &best_sad,
1846                                          min_dx, max_dx, min_dy, max_dy,                                                  &Data);
1847                                                  edged_width, 1, frame->quant, 0);               // equiv to halfpel refine  
1848    // final skip decision
1849                            if ( (skip_sad < frame->quant * MAX_SAD00_FOR_SKIP*2)
1850  //                      i_sad16 = 65535;                /* remove the comment to disable any of the MODEs */                                          && ((100*best_sad)/(skip_sad+1) > FINAL_SKIP_THRESH) )
1851  //                      f_sad16 = 65535;                                  SkipDecisionB(&frame->image, f_ref, b_ref, pMB,frame->quant, i, j, &Data);
1852  //                      b_sad16 = 65535;  
1853  //                      d_sad16 = 65535;                          switch (pMB->mode) {
1854                                    case MODE_FORWARD:
1855                          if (f_sad16 < b_sad16) {                                          f_count++;
1856                                  best_sad = f_sad16;                                          if (Data.qpel) f_predMV = pMB->qmvs[0];
1857                                  mb->mode = MODE_FORWARD;                                          else f_predMV = pMB->mvs[0];
1858                                            break;
1859                                    case MODE_BACKWARD:
1860                                            b_count++;
1861                                            if (Data.qpel) b_predMV = pMB->b_qmvs[0];
1862                                            else b_predMV = pMB->b_mvs[0];
1863                                            break;
1864                                    case MODE_INTERPOLATE:
1865                                            i_count++;
1866                                            if (Data.qpel) {
1867                                                    f_predMV = pMB->qmvs[0];
1868                                                    b_predMV = pMB->b_qmvs[0];
1869                          } else {                          } else {
1870                                  best_sad = b_sad16;                                                  f_predMV = pMB->mvs[0];
1871                                  mb->mode = MODE_BACKWARD;                                                  b_predMV = pMB->b_mvs[0];
1872                          }                          }
1873                                            break;
1874                          if (i_sad16 < best_sad) {                                  case MODE_DIRECT:
1875                                  best_sad = i_sad16;                                  case MODE_DIRECT_NO4V:
1876                                  mb->mode = MODE_INTERPOLATE;                                          d_count++;
1877                                    default:
1878                                            break;
1879                            }
1880                    }
1881            }
1882            free(qimage);
1883                          }                          }
1884    
1885                          if (d_sad16 < best_sad) {  static __inline void
1886    MEanalyzeMB (   const uint8_t * const pRef,
1887                                  if (b_mb->mode == MODE_INTER4V)                                  const uint8_t * const pCur,
1888                                    const int x,
1889                                    const int y,
1890                                    const MBParam * const pParam,
1891                                    MACROBLOCK * const pMBs,
1892                                    SearchData * const Data)
1893                                  {                                  {
1894    
1895                                  /* how to calc vectors is defined in standard. mvs[] and b_mvs[] are only for motion compensation */          int i, mask;
1896                                  /* for the bitstream, the value mb->deltamv is read directly */          VECTOR pmv[3];
1897            MACROBLOCK * pMB = &pMBs[x + y * pParam->mb_width];
1898    
1899                              for (k = 0; k < 4; k++) {          for (i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;
1900    
1901            //median is only used as prediction. it doesn't have to be real
1902            if (x == 1 && y == 1) Data->predMV.x = Data->predMV.y = 0;
1903            else
1904                    if (x == 1) //left macroblock does not have any vector now
1905                            Data->predMV = (pMB - pParam->mb_width)->mvs[0]; // top instead of median
1906                    else if (y == 1) // top macroblock doesn't have it's vector
1907                            Data->predMV = (pMB - 1)->mvs[0]; // left instead of median
1908                            else Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); //else median
1909    
1910            get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1911                                    pParam->width, pParam->height, Data->iFcode - pParam->m_quarterpel, 0, Data->rrv);
1912    
1913            Data->Cur = pCur + (x + y * pParam->edged_width) * 16;
1914            Data->Ref = pRef + (x + y * pParam->edged_width) * 16;
1915    
1916            pmv[1].x = EVEN(pMB->mvs[0].x);
1917            pmv[1].y = EVEN(pMB->mvs[0].y);
1918            pmv[2].x = EVEN(Data->predMV.x);
1919            pmv[2].y = EVEN(Data->predMV.y);
1920            pmv[0].x = pmv[0].y = 0;
1921    
1922            CheckCandidate32I(0, 0, 255, &i, Data);
1923    
1924            if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP * 4) {
1925    
1926                    if (!(mask = make_mask(pmv, 1)))
1927                            CheckCandidate32I(pmv[1].x, pmv[1].y, mask, &i, Data);
1928                    if (!(mask = make_mask(pmv, 2)))
1929                            CheckCandidate32I(pmv[2].x, pmv[2].y, mask, &i, Data);
1930    
1931                    if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP * 4) // diamond only if needed
1932                            DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, i);
1933    
1934                                                  mb->mvs[k].x = (int32_t) ((TRB * mb->directmv[k].x) / TRD + mb->deltamv.x);                  for (i = 0; i < 4; i++) {
1935                              mb->b_mvs[k].x = (int32_t) ((mb->deltamv.x == 0)                          MACROBLOCK * MB = &pMBs[x + (i&1) + (y+(i>>1) * pParam->mb_width)];
1936                                                                                          ? ((TRB - TRD) * mb->directmv[k].x) / TRD                          MB->mvs[0] = MB->mvs[1] = MB->mvs[2] = MB->mvs[3] = Data->currentMV[i];
1937                                                      : mb->mvs[k].x - mb->directmv[k].x);                          MB->mode = MODE_INTER;
1938                            MB->sad16 = Data->iMinSAD[i+1];
                             mb->mvs[k].y = (int32_t) ((TRB * mb->directmv[k].y) / TRD + mb->deltamv.y);  
                         mb->b_mvs[k].y = (int32_t) ((mb->deltamv.y == 0)  
                                                                                         ? ((TRB - TRD) * mb->directmv[k].y) / TRD  
                                             : mb->mvs[k].y - mb->directmv[k].y);  
1939                                          }                                          }
1940                                  }                                  }
1941    }
1942    
1943    #define INTRA_BIAS              2500
1944    #define INTRA_THRESH    1500
1945    #define INTER_THRESH    1400
1946    
1947    
1948    int
1949    MEanalysis(     const IMAGE * const pRef,
1950                            FRAMEINFO * const Current,
1951                            MBParam * const pParam,
1952                            int maxIntra, //maximum number if non-I frames
1953                            int intraCount, //number of non-I frames after last I frame; 0 if we force P/B frame
1954                            int bCount) // number if B frames in a row
1955    {
1956            uint32_t x, y, intra = 0;
1957            int sSAD = 0;
1958            MACROBLOCK * const pMBs = Current->mbs;
1959            const IMAGE * const pCurrent = &Current->image;
1960            int IntraThresh = INTRA_THRESH, InterThresh = INTER_THRESH;
1961            const VECTOR zeroMV = {0,0};
1962    
1963            int32_t iMinSAD[5], temp[5];
1964            VECTOR currentMV[5];
1965            SearchData Data;
1966            Data.iEdgedWidth = pParam->edged_width;
1967            Data.currentMV = currentMV;
1968            Data.iMinSAD = iMinSAD;
1969            Data.iFcode = Current->fcode;
1970            Data.rrv = Current->global_flags & XVID_REDUCED;
1971            Data.temp = temp;
1972            CheckCandidate = CheckCandidate32I;
1973    
1974            if (intraCount < 10) // we're right after an I frame
1975                    IntraThresh += 4 * (intraCount - 10) * (intraCount - 10);
1976                                  else                                  else
1977                                  {                  if ( 5*(maxIntra - intraCount) < maxIntra) // we're close to maximum. 2 sec when max is 10 sec
1978                                          mb->mvs[0].x = (int32_t) ((TRB * mb->directmv[0].x) / TRD + mb->deltamv.x);                          IntraThresh -= (IntraThresh * (maxIntra - 5*(maxIntra - intraCount)))/maxIntra;
1979    
1980            InterThresh += 400 * (1 - bCount);
1981            if (InterThresh < 300) InterThresh = 300;
1982    
1983                      mb->b_mvs[0].x = (int32_t) ((mb->deltamv.x == 0)          if (sadInit) (*sadInit) ();
                                                                                 ? ((TRB - TRD) * mb->directmv[0].x) / TRD  
                                         : mb->mvs[0].x - mb->directmv[0].x);  
1984    
1985                              mb->mvs[0].y = (int32_t) ((TRB * mb->directmv[0].y) / TRD + mb->deltamv.y);          for (y = 1; y < pParam->mb_height-1; y+=2) {
1986                    for (x = 1; x < pParam->mb_width-1; x+=2) {
1987                            int i;
1988    
1989                          mb->b_mvs[0].y = (int32_t) ((mb->deltamv.y == 0)                          if (bCount == 0) pMBs[x + y * pParam->mb_width].mvs[0] = zeroMV;
                                                                                 ? ((TRB - TRD) * mb->directmv[0].y) / TRD  
                                             : mb->mvs[0].y - mb->directmv[0].y);  
1990    
1991                                          mb->mvs[3] = mb->mvs[2] = mb->mvs[1] = mb->mvs[0];                          MEanalyzeMB(pRef->y, pCurrent->y, x, y, pParam, pMBs, &Data);
1992                                          mb->b_mvs[3] = mb->b_mvs[2] = mb->b_mvs[1] = mb->b_mvs[0];  
1993                            for (i = 0; i < 4; i++) {
1994                                    int dev;
1995                                    MACROBLOCK *pMB = &pMBs[x+(i&1) + y+(i>>1) * pParam->mb_width];
1996                                    if (pMB->sad16 > IntraThresh) {
1997                                            dev = dev16(pCurrent->y + (x + (i&1) + (y + (i>>1))* pParam->edged_width) * 16,
1998                                                                              pParam->edged_width);
1999                                            if (dev + IntraThresh < pMB->sad16) {
2000                                                    pMB->mode = MODE_INTRA;
2001                                                    if (++intra > (pParam->mb_height-2)*(pParam->mb_width-2)/2) return I_VOP;
2002                                            }
2003                                    }
2004                                    sSAD += pMB->sad16;
2005                            }
2006                  }                  }
2007            }
2008            sSAD /= (pParam->mb_height-2)*(pParam->mb_width-2);
2009            if (sSAD > IntraThresh + INTRA_BIAS ) return I_VOP;
2010            if (sSAD > InterThresh ) return P_VOP;
2011            emms();
2012            return B_VOP;
2013    
                                 best_sad = d_sad16;  
                                 mb->mode = MODE_DIRECT;  
2014                          }                          }
2015    
2016                          switch (mb->mode)  static void
2017    CheckGMC(int x, int y, const int dir, int * iDirection,
2018                    const MACROBLOCK * const pMBs, uint32_t * bestcount, VECTOR * GMC,
2019                    const MBParam * const pParam)
2020                          {                          {
2021                                  case MODE_FORWARD:          uint32_t mx, my, a, count = 0;
                                         f_count++;  
                                         f_predMV = mb->mvs[0];  
                                         break;  
                                 case MODE_BACKWARD:  
                                         b_count++;  
                                         b_predMV = mb->b_mvs[0];  
2022    
2023                                          break;          for (my = 1; my < pParam->mb_height-1; my++)
2024                                  case MODE_INTERPOLATE:                  for (mx = 1; mx < pParam->mb_width-1; mx++) {
2025                                          i_count++;                          VECTOR mv;
2026                                          mb->mvs[0] = f_interpolMV;                          const MACROBLOCK *pMB = &pMBs[mx + my * pParam->mb_width];
2027                                          mb->b_mvs[0] = b_interpolMV;                          if (pMB->mode == MODE_INTRA || pMB->mode == MODE_NOT_CODED) continue;
2028                                          f_predMV = mb->mvs[0];                          mv = pMB->mvs[0];
2029                                          b_predMV = mb->b_mvs[0];                          a = ABS(mv.x - x) + ABS(mv.y - y);
2030                                          break;                          if (a < 6) count += 6 - a;
2031                                  case MODE_DIRECT:                  }
2032                                          d_count++;  
2033                                          break;          if (count > *bestcount) {
2034                                  default:                  *bestcount = count;
2035                                          break;                  *iDirection = dir;
2036                    GMC->x = x; GMC->y = y;
2037            }
2038                          }                          }
2039    
2040    
2041    static VECTOR
2042    GlobalMotionEst(const MACROBLOCK * const pMBs, const MBParam * const pParam, const uint32_t iFcode)
2043    {
2044    
2045            uint32_t count, bestcount = 0;
2046            int x, y;
2047            VECTOR gmc = {0,0};
2048            int step, min_x, max_x, min_y, max_y;
2049            uint32_t mx, my;
2050            int iDirection, bDirection;
2051    
2052            min_x = min_y = -32<<iFcode;
2053            max_x = max_y = 32<<iFcode;
2054    
2055    //step1: let's find a rough camera panning
2056            for (step = 32; step >= 2; step /= 2) {
2057                    bestcount = 0;
2058                    for (y = min_y; y <= max_y; y += step)
2059                            for (x = min_x ; x <= max_x; x += step) {
2060                                    count = 0;
2061                                    //for all macroblocks
2062                                    for (my = 1; my < pParam->mb_height-1; my++)
2063                                            for (mx = 1; mx < pParam->mb_width-1; mx++) {
2064                                                    const MACROBLOCK *pMB = &pMBs[mx + my * pParam->mb_width];
2065                                                    VECTOR mv;
2066    
2067                                                    if (pMB->mode == MODE_INTRA || pMB->mode == MODE_NOT_CODED)
2068                                                            continue;
2069    
2070                                                    mv = pMB->mvs[0];
2071                                                    if ( ABS(mv.x - x) <= step && ABS(mv.y - y) <= step )   /* GMC translation is always halfpel-res */
2072                                                            count++;
2073                  }                  }
2074                                    if (count >= bestcount) { bestcount = count; gmc.x = x; gmc.y = y; }
2075          }          }
2076                    min_x = gmc.x - step;
2077                    max_x = gmc.x + step;
2078                    min_y = gmc.y - step;
2079                    max_y = gmc.y + step;
2080            }
2081    
2082            if (bestcount < (pParam->mb_height-2)*(pParam->mb_width-2)/10)
2083                    gmc.x = gmc.y = 0; //no camara pan, no GMC
2084    
2085  #ifdef _DEBUG_BFRAME_STAT  // step2: let's refine camera panning using gradiend-descent approach
2086          fprintf(stderr,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d\n",  // TODO: more warping points may be evaluated here (like in interpolate mode search - two vectors in one diamond)
2087                                  f_count,b_count,i_count,d_count);          bestcount = 0;
2088  #endif          CheckGMC(gmc.x, gmc.y, 255, &iDirection, pMBs, &bestcount, &gmc, pParam);
2089            do {
2090                    x = gmc.x; y = gmc.y;
2091                    bDirection = iDirection; iDirection = 0;
2092                    if (bDirection & 1) CheckGMC(x - 1, y, 1+4+8, &iDirection, pMBs, &bestcount, &gmc, pParam);
2093                    if (bDirection & 2) CheckGMC(x + 1, y, 2+4+8, &iDirection, pMBs, &bestcount, &gmc, pParam);
2094                    if (bDirection & 4) CheckGMC(x, y - 1, 1+2+4, &iDirection, pMBs, &bestcount, &gmc, pParam);
2095                    if (bDirection & 8) CheckGMC(x, y + 1, 1+2+8, &iDirection, pMBs, &bestcount, &gmc, pParam);
2096    
2097            } while (iDirection);
2098    
2099            if (pParam->m_quarterpel) {
2100                    gmc.x *= 2;
2101                    gmc.y *= 2;     /* we store the halfpel value as pseudo-qpel to make comparison easier */
2102            }
2103    
2104            return gmc;
2105  }  }

Legend:
Removed from v.392  
changed lines
  Added in v.753

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