[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

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

Legend:
Removed from v.337  
changed lines
  Added in v.743

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