[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 739, Tue Dec 24 16:44:24 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); // this reference is used in all cases
152            ref1 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
153            switch( ((x&1)<<1) + (y&1) ) {
154            case 0: // pure halfpel position
155                    Reference = (uint8_t *) GetReference(halfpel_x, halfpel_y, dir, data);
156                    Reference += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
157                    break;
158    
159            case 1: // x halfpel, y qpel - top or bottom during qpel refinement
160                    ref2 = GetReference(halfpel_x, y - halfpel_y, dir, data);
161                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
162                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
163                    break;
164    
165            case 2: // x qpel, y halfpel - left or right during qpel refinement
166                    ref2 = GetReference(x - halfpel_x, halfpel_y, dir, data);
167                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
168                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
169                    break;
170    
171            default: // x and y in qpel resolution - the "corners" (top left/right and
172                             // bottom left/right) during qpel refinement
173                    ref2 = GetReference(halfpel_x, y - halfpel_y, dir, data);
174                    ref3 = GetReference(x - halfpel_x, halfpel_y, dir, data);
175                    ref4 = GetReference(x - halfpel_x, y - halfpel_y, dir, data);
176                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
177                    ref3 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
178                    ref4 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
179                    interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
180                    break;
181            }
182            return Reference;
183    }
184    
185    static uint8_t *
186    Interpolate16x16qpel(const int x, const int y, const int dir, const SearchData * const data)
187    {
188    // create or find a qpel-precision reference picture; return pointer to it
189            uint8_t * Reference = (uint8_t *)data->RefQ + 16*dir;
190            const int32_t iEdgedWidth = data->iEdgedWidth;
191            const uint32_t rounding = data->rounding;
192            const int halfpel_x = x/2;
193            const int halfpel_y = y/2;
194            const uint8_t *ref1, *ref2, *ref3, *ref4;
195    
196            ref1 = GetReference(halfpel_x, halfpel_y, dir, data); // this reference is used in all cases
197            switch( ((x&1)<<1) + (y&1) ) {
198            case 0: // pure halfpel position
199                    return (uint8_t *) GetReference(halfpel_x, halfpel_y, dir, data);
200            case 1: // x halfpel, y qpel - top or bottom during qpel refinement
201                    ref2 = GetReference(halfpel_x, y - halfpel_y, dir, data);
202                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
203                    interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
204                    interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
205                    interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
206                    break;
207    
208            case 2: // x qpel, y halfpel - left or right during qpel refinement
209                    ref2 = GetReference(x - halfpel_x, halfpel_y, dir, data);
210                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
211                    interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
212                    interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
213                    interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
214                    break;
215    
216            default: // x and y in qpel resolution - the "corners" (top left/right and
217                             // bottom left/right) during qpel refinement
218                    ref2 = GetReference(halfpel_x, y - halfpel_y, dir, data);
219                    ref3 = GetReference(x - halfpel_x, halfpel_y, dir, data);
220                    ref4 = GetReference(x - halfpel_x, y - halfpel_y, dir, data);
221                    interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
222                    interpolate8x8_avg4(Reference+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, rounding);
223                    interpolate8x8_avg4(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, rounding);
224                    interpolate8x8_avg4(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, rounding);
225                    break;
226            }
227            return Reference;
228    }
229    
230    /* CHECK_CANDIATE FUNCTIONS START */
231    
232    static void
233    CheckCandidate16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
234    {
235            int t, xc, yc;
236            const uint8_t * Reference;
237            VECTOR * current;
238    
239            if (( x > data->max_dx) || ( x < data->min_dx)
240                    || ( y > data->max_dy) || (y < data->min_dy)) return;
241    
242            if (data->qpel_precision) { // x and y are in 1/4 precision
243                    Reference = Interpolate16x16qpel(x, y, 0, data);
244                    xc = x/2; yc = y/2; //for chroma sad
245                    current = data->currentQMV;
246            } else {
247                    Reference = GetReference(x, y, 0, data);
248                    current = data->currentMV;
249                    xc = x; yc = y;
250                          }                          }
251            t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel && !data->qpel_precision, 0);
252    
253                          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  
                                          */  
254    
255                                          if (sad8 < pMB->sad16) {          data->temp[0] += (data->lambda16 * t * data->temp[0])/1000;
256                                                  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;  
                                         }  
257    
258                                  }          if (data->chroma) data->temp[0] += ChromaSAD(xc, yc, data);
259    
260                          pMB->mode = MODE_INTER;          if (data->temp[0] < data->iMinSAD[0]) {
261                          pMB->pmvs[0] = pmv;     /* pMB->pmvs[1] = pMB->pmvs[2] = pMB->pmvs[3]  are not needed for INTER */                  data->iMinSAD[0] = data->temp[0];
262                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mv16;                  current[0].x = x; current[0].y = y;
263                          pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] =                  *dir = Direction; }
                                 pMB->sad16;  
                         }  
                         }  
264    
265          return 0;          if (data->temp[1] < data->iMinSAD[1]) {
266  }                  data->iMinSAD[1] = data->temp[1]; current[1].x = x; current[1].y= y; }
267            if (data->temp[2] < data->iMinSAD[2]) {
268                    data->iMinSAD[2] = data->temp[2]; current[2].x = x; current[2].y = y; }
269            if (data->temp[3] < data->iMinSAD[3]) {
270                    data->iMinSAD[3] = data->temp[3]; current[3].x = x; current[3].y = y; }
271            if (data->temp[4] < data->iMinSAD[4]) {
272                    data->iMinSAD[4] = data->temp[4]; current[4].x = x; current[4].y = y; }
273    
274    }
275    
276  #define CHECK_MV16_ZERO {\  static void
277    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)  
278  {  {
279          const int32_t iEdgedWidth = pParam->edged_width;          int t;
280          const uint8_t * cur = pCur->y + x*16 + y*16*iEdgedWidth;          const uint8_t * Reference;
         int32_t iSAD;  
         VECTOR pred;  
281    
282            if ( (!(x&1) && x !=0) || (!(y&1) && y !=0) || //non-zero integer value
283                    ( x > data->max_dx) || ( x < data->min_dx)
284                    || ( y > data->max_dy) || (y < data->min_dy)) return;
285    
286          pred = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);          Reference = GetReference(x, y, 0, data);
287            t = d_mv_bits(x, y, data->predMV, data->iFcode, 0, 1);
288    
289          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;  
290    
291          currMV->x = 0;          data->temp[0] += (data->lambda16 * t * data->temp[0])/1000;
292          currMV->y = 0;          data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))/100;
         currPMV->x = -pred.x;  
         currPMV->y = -pred.y;  
293    
294          return iSAD;          if (data->temp[0] < data->iMinSAD[0]) {
295                    data->iMinSAD[0] = data->temp[0];
296                    data->currentMV[0].x = x; data->currentMV[0].y = y;
297                    *dir = Direction; }
298    
299            if (data->temp[1] < data->iMinSAD[1]) {
300                    data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
301            if (data->temp[2] < data->iMinSAD[2]) {
302                    data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
303            if (data->temp[3] < data->iMinSAD[3]) {
304                    data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
305            if (data->temp[4] < data->iMinSAD[4]) {
306                    data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
307  }  }
 */  
308    
309  int32_t  static void
310  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)  
311  {  {
312  /* Do a diamond search around given starting point, return SAD of best */          int32_t sad;
313            const uint8_t * Reference;
314          int32_t iDirection = 0;          int t;
315          int32_t iSAD;          VECTOR * current;
         VECTOR backupMV;  
316    
317          backupMV.x = start_x;          if (( x > data->max_dx) || ( x < data->min_dx)
318          backupMV.y = start_y;                  || ( y > data->max_dy) || (y < data->min_dy)) return;
319    
320  /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */          if (data->rrv)
321                    if ( (!(x&1) && x !=0) || (!(y&1) && y !=0) ) return; //non-zero integer value
322    
323          CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);          if (data->qpel_precision) { // x and y are in 1/4 precision
324          CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);                  Reference = Interpolate16x16qpel(x, y, 0, data);
325          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);  
326          } else {          } else {
327                  currMV->x = start_x;                  Reference = GetReference(x, y, 0, data);
328                  currMV->y = start_y;                  current = data->currentMV;
         }  
         return iMinSAD;  
329  }  }
330            t = d_mv_bits(x, y, data->predMV, data->iFcode,
331                                            data->qpel && !data->qpel_precision && !data->rrv, data->rrv);
332    
333  int32_t          sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
334  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 */  
335    
336          int32_t iDirection = 0;          if (sad < *(data->iMinSAD)) {
337          int32_t iSAD;                  *(data->iMinSAD) = sad;
338          VECTOR backupMV;                  current->x = x; current->y = y;
339                    *dir = Direction; }
340          backupMV.x = start_x;  }
         backupMV.y = start_y;  
341    
342  /* It's one search with full square pattern, and new parts for all following diamonds */  static void
343    CheckCandidate32I(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
344    {
345    // maximum speed - for P/B/I decision
346    
347  /*   new direction are extra, so 1-4 is normal diamond          if (( x > data->max_dx) || ( x < data->min_dx)
348        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;  
349    
350                          switch (iDirection) {          data->temp[0] = sad32v_c(data->Cur, data->Ref + x/2 + (y/2)*(data->iEdgedWidth),
351                          case 1:                                                          data->iEdgedWidth, data->temp+1);
352                                  CHECK_MV16_CANDIDATE_FOUND(backupMV.x - iDiamondSize,          if (data->temp[0] < *(data->iMinSAD)) {
353                                                                                     backupMV.y, 1);                  *(data->iMinSAD) = data->temp[0];
354                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,                  data->currentMV[0].x = x; data->currentMV[0].y = y;
355                                                                                   backupMV.y - iDiamondSize, 5);                  *dir = Direction; }
356                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize,          if (data->temp[1] < data->iMinSAD[1]) {
357                                                                                   backupMV.y - iDiamondSize, 7);                  data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
358                                  break;          if (data->temp[2] < data->iMinSAD[2]) {
359                          case 2:                  data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
360                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y,          if (data->temp[3] < data->iMinSAD[3]) {
361                                                                                   2);                  data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
362                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x - iDiamondSize,          if (data->temp[4] < data->iMinSAD[4]) {
363                                                                                   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;  
364    
365                          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;  
366    
                         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);  
367    
368                                  break;  static void
369    CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)
370    {
371            int32_t sad;
372            int xb, yb, t;
373            const uint8_t *ReferenceF, *ReferenceB;
374            VECTOR *current;
375    
376                          case 7:          if (( xf > data->max_dx) || ( xf < data->min_dx)
377                                  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;  
378    
379                          case 8:          if (data->qpel_precision) {
380                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y,                  ReferenceF = Interpolate16x16qpel(xf, yf, 0, data);
381                                                                                   2);                  xb = data->currentQMV[1].x; yb = data->currentQMV[1].y;
382                                  CHECK_MV16_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize,                  current = data->currentQMV;
383                                                                                   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;  
                         }  
384          } else {          } else {
385                  currMV->x = start_x;                  ReferenceF = GetReference(xf, yf, 0, data);
386                  currMV->y = start_y;                  xb = data->currentMV[1].x; yb = data->currentMV[1].y;
387          }                  ReferenceB = GetReference(xb, yb, 1, data);
388          return iMinSAD;                  current = data->currentMV;
389  }  }
390    
391            t = d_mv_bits(xf, yf, data->predMV, data->iFcode, data->qpel && !data->qpel_precision, 0)
392                     + d_mv_bits(xb, yb, data->bpredMV, data->iFcode, data->qpel && !data->qpel_precision, 0);
393    
394  int32_t          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
395  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);  
396    
397          return iMinSAD;          if (sad < *(data->iMinSAD)) {
398                    *(data->iMinSAD) = sad;
399                    current->x = xf; current->y = yf;
400                    *dir = Direction; }
401  }  }
402    
403  int32_t  static void
404  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)  
405  {  {
406            int32_t sad = 0;
407            int k;
408            const uint8_t *ReferenceF;
409            const uint8_t *ReferenceB;
410            VECTOR mvs, b_mvs;
411            const VECTOR zeroMV={0,0};
412    
413          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);  
414    
415                          if (bDirection & 4)          for (k = 0; k < 4; k++) {
416                                  CHECK_MV16_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);                  mvs.x = data->directmvF[k].x + x;
417                    b_mvs.x = ((x == 0) ?
418                            data->directmvB[k].x
419                            : mvs.x - data->referencemv[k].x);
420    
421                          if (bDirection & 8)                  mvs.y = data->directmvF[k].y + y;
422                                  CHECK_MV16_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);                  b_mvs.y = ((y == 0) ?
423                            data->directmvB[k].y
424                            : mvs.y - data->referencemv[k].y);
425    
426                          /* now we're doing diagonal checks near our candidate */                  if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
427                            || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
428                            || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
429                            || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
430    
431                          if (iDirection)         //checking if anything found                  if (!data->qpel) {
432                          {                          mvs.x *= 2; mvs.y *= 2;
433                                  bDirection = iDirection;                          b_mvs.x *= 2; b_mvs.y *= 2; //we move to qpel precision anyway
                                 iDirection = 0;  
                                 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);  
434                                  }                                  }
435                    ReferenceF = Interpolate8x8qpel(mvs.x, mvs.y, k, 0, data);
436                    ReferenceB = Interpolate8x8qpel(b_mvs.x, b_mvs.y, k, 1, data);
437    
438                                  if (iDirection) {                  sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
439                                          bDirection += iDirection;                                                  ReferenceF, ReferenceB,
440                                          start_x = currMV->x;                                                  data->iEdgedWidth);
441                                          start_y = currMV->y;                  if (sad > *(data->iMinSAD)) return;
442                                  }                                  }
                         } else                          //about to quit, eh? not so fast....  
                         {  
                                 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:  
443    
444                                          CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,          sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)/1000;
                                                                                          start_y - iDiamondSize, 1 + 4);  
                                         CHECK_MV16_CANDIDATE_DIR(start_x - iDiamondSize,  
                                                                                          start_y + iDiamondSize, 1 + 8);  
                                         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;  
 }  
445    
446            if (sad < *(data->iMinSAD)) {
447  #define CHECK_MV16_F_INTERPOL(X,Y,BX,BY) { \                  *(data->iMinSAD) = sad;
448    if ( ((X) <= max_dx) && ((X) >= min_dx) \                  data->currentMV->x = x; data->currentMV->y = y;
449      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \                  *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); } } \  
450  }  }
451    
452  #define CHECK_MV16_F_INTERPOL_DIR(X,Y,BX,BY,D) { \  static void
453    if ( ((X) <= max_dx) && ((X) >= min_dx) \  CheckCandidateDirectno4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
454      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \  {
455    { \          int32_t sad;
456      iSAD = sad16( cur, get_ref(pRef, pRefH, pRefV, pRefHV, x, y, 16, X, Y, iEdgedWidth),iEdgedWidth, iMinSAD); \          const uint8_t *ReferenceF;
457      iSAD += calc_delta_16((X) - center_x, (Y) - center_y, (uint8_t)iFcode, iQuant);\          const uint8_t *ReferenceB;
458      if (iSAD < iMinSAD) \          VECTOR mvs, b_mvs;
459      {  iMinSAD=iSAD; currMV->x=(X); currMV->y=(Y); iDirection=(D); } } \          const VECTOR zeroMV = {0,0};
 }  
460    
461  #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; } } \  
 }  
462    
463            mvs.x = data->directmvF[0].x + x;
464            b_mvs.x = ((x == 0) ?
465                    data->directmvB[0].x
466                    : mvs.x - data->referencemv[0].x);
467    
468  #define CHECK_MV16_B_INTERPOL(FX,FY,X,Y) { \          mvs.y = data->directmvF[0].y + y;
469    if ( ((X) <= max_dx) && ((X) >= min_dx) \          b_mvs.y = ((y == 0) ?
470      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \                  data->directmvB[0].y
471    { \                  : 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); } } \  
 }  
472    
473            if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )
474                    || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )
475                    || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )
476                    || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;
477    
478  #define CHECK_MV16_B_INTERPOL_DIR(FX,FY,X,Y,D) { \          if (!data->qpel) {
479    if ( ((X) <= max_dx) && ((X) >= min_dx) \                          mvs.x *= 2; mvs.y *= 2;
480      && ((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); } } \  
481  }  }
482            ReferenceF = Interpolate16x16qpel(mvs.x, mvs.y, 0, data);
483            ReferenceB = Interpolate16x16qpel(b_mvs.x, b_mvs.y, 1, data);
484    
485            sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
486            sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)/1000;
487    
488  #define CHECK_MV16_B_INTERPOL_FOUND(FX,FY,X,Y,D) { \          if (sad < *(data->iMinSAD)) {
489    if ( ((X) <= max_dx) && ((X) >= min_dx) \                  *(data->iMinSAD) = sad;
490      && ((Y) <= max_dy) && ((Y) >= min_dy) ) \                  data->currentMV->x = x; data->currentMV->y = y;
491    { \                  *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; } } \  
492  }  }
493    
494    static void
495    CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
496    {
497            int32_t sad; int t;
498            const uint8_t * Reference;
499    
500  #if (0==1)          if (( x > data->max_dx) || ( x < data->min_dx)
501  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,  
502    
503                                          const uint8_t * const b_pRef,          if (data->qpel) Reference = Interpolate16x16qpel(x, y, 0, data);
504                                           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,  
505    
506                                           const int x,          sad = sad8(data->Cur, Reference, data->iEdgedWidth);
507                                           const int y,          t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel && !data->qpel_precision, 0);
508    
509                                     const int f_start_x,          sad += (data->lambda8 * t * (sad+NEIGH_8X8_BIAS))/100;
510                                     const int f_start_y,  
511                                     const int b_start_x,          if (sad < *(data->iMinSAD)) {
512                                     const int b_start_y,                  *(data->iMinSAD) = sad;
513                    data->currentMV->x = x; data->currentMV->y = y;
514                                     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;  
515  }  }
 #endif  
516    
517    /* CHECK_CANDIATE FUNCTIONS END */
518    
519  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)  
 {  
520    
521          int32_t iSAD;  static void
522    AdvDiamondSearch(int x, int y, const SearchData * const data, int bDirection)
523    {
524    
525  /* 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) */
526    
527          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;  
528    
529                  do {          for(;;) { //forever
530                          iDirection = 0;                          iDirection = 0;
531                          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);
532                                  CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize, start_y, 1);                  if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
533                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
534                          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);  
535    
536                          /* now we're doing diagonal checks near our candidate */                          /* now we're doing diagonal checks near our candidate */
537    
538                          if (iDirection)         //checking if anything found                  if (iDirection) {               //checking if anything found
                         {  
539                                  bDirection = iDirection;                                  bDirection = iDirection;
540                                  iDirection = 0;                                  iDirection = 0;
541                                  start_x = currMV->x;                          x = data->currentMV->x; y = data->currentMV->y;
542                                  start_y = currMV->y;                          if (bDirection & 3) {   //our candidate is left or right
543                                  if (bDirection & 3)     //our candidate is left or right                                  CHECK_CANDIDATE(x, y + iDiamondSize, 8);
544                                  {                                  CHECK_CANDIDATE(x, y - iDiamondSize, 4);
545                                          CHECK_MV8_CANDIDATE_DIR(start_x, start_y + iDiamondSize, 8);                          } else {                        // what remains here is up or down
546                                          CHECK_MV8_CANDIDATE_DIR(start_x, start_y - iDiamondSize, 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y, 2);
547                                  } 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);  
548                                  }                                  }
549    
550                                  if (iDirection) {                                  if (iDirection) {
551                                          bDirection += iDirection;                                          bDirection += iDirection;
552                                          start_x = currMV->x;                                  x = data->currentMV->x; y = data->currentMV->y;
                                         start_y = currMV->y;  
553                                  }                                  }
554                          } else                          //about to quit, eh? not so fast....                  } else {                                //about to quit, eh? not so fast....
                         {  
555                                  switch (bDirection) {                                  switch (bDirection) {
556                                  case 2:                                  case 2:
557                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
558                                                                                          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);  
559                                          break;                                          break;
560                                  case 1:                                  case 1:
561                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
562                                                                                          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);  
563                                          break;                                          break;
564                                  case 2 + 4:                                  case 2 + 4:
565                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
566                                                                                          start_y - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
567                                          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);  
568                                          break;                                          break;
569                                  case 4:                                  case 4:
570                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
571                                                                                          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);  
572                                          break;                                          break;
573                                  case 8:                                  case 8:
574                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
575                                                                                          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);  
576                                          break;                                          break;
577                                  case 1 + 4:                                  case 1 + 4:
578                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
579                                                                                          start_y + iDiamondSize, 1 + 8);                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
580                                          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);  
581                                          break;                                          break;
582                                  case 2 + 8:                                  case 2 + 8:
583                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
584                                                                                          start_y - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
585                                          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);  
586                                          break;                                          break;
587                                  case 1 + 8:                                  case 1 + 8:
588                                          CHECK_MV8_CANDIDATE_DIR(start_x + iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
589                                                                                          start_y - iDiamondSize, 2 + 4);                                  CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2 + 8);
590                                          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);  
591                                          break;                                          break;
592                                  default:                //1+2+4+8 == we didn't find anything at all                                  default:                //1+2+4+8 == we didn't find anything at all
593                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1 + 4);
594                                                                                          start_y - iDiamondSize, 1 + 4);                                  CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1 + 8);
595                                          CHECK_MV8_CANDIDATE_DIR(start_x - iDiamondSize,                                  CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2 + 4);
596                                                                                          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);  
597                                          break;                                          break;
598                                  }                                  }
599                                  if (!(iDirection))                          if (!iDirection) break;         //ok, the end. really
                                         break;          //ok, the end. really  
                                 else {  
600                                          bDirection = iDirection;                                          bDirection = iDirection;
601                                          start_x = currMV->x;                          x = data->currentMV->x; y = data->currentMV->y;
                                         start_y = currMV->y;  
                                 }  
602                          }                          }
603                  }                  }
                 while (1);                              //forever  
604          }          }
         return iMinSAD;  
 }  
   
605    
606  int32_t  static void
607  Full8_MainSearch(const uint8_t * const pRef,  SquareSearch(int x, int y, const SearchData * const data, int bDirection)
                                  const uint8_t * const pRefH,  
                                  const uint8_t * const pRefV,  
                                  const uint8_t * const pRefHV,  
                                  const uint8_t * const cur,  
                                  const int x,  
                                  const int y,  
                            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)  
608  {  {
609          int32_t iSAD;          int iDirection;
         int32_t dx, dy;  
         VECTOR backupMV;  
   
         backupMV.x = start_x;  
         backupMV.y = start_y;  
   
         for (dx = min_dx; dx <= max_dx; dx += iDiamondSize)  
                 for (dy = min_dy; dy <= max_dy; dy += iDiamondSize)  
                         NOCHECK_MV8_CANDIDATE(dx, dy);  
   
         return iMinSAD;  
 }  
   
 Halfpel8_RefineFuncPtr Halfpel8_Refine;  
   
 int32_t  
 Halfpel16_Refine(const uint8_t * const pRef,  
                                  const uint8_t * const pRefH,  
                                  const uint8_t * const pRefV,  
                                  const uint8_t * const pRefHV,  
                                  const uint8_t * const cur,  
                                  const int x,  
                                  const int y,  
                                  VECTOR * const currMV,  
                                  int32_t iMinSAD,  
                            const int center_x,  
                            const int center_y,  
                                  const int32_t min_dx,  
                                  const int32_t max_dx,  
                                  const int32_t min_dy,  
                                  const int32_t max_dy,  
                                  const int32_t iFcode,  
                                  const int32_t iQuant,  
                                  const int32_t iEdgedWidth)  
 {  
 /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  
   
         int32_t iSAD;  
         VECTOR backupMV = *currMV;  
   
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y - 1);  
         CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y - 1);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y - 1);  
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y);  
         CHECK_MV16_CANDIDATE(backupMV.x - 1, backupMV.y + 1);  
         CHECK_MV16_CANDIDATE(backupMV.x, backupMV.y + 1);  
         CHECK_MV16_CANDIDATE(backupMV.x + 1, backupMV.y + 1);  
   
         return iMinSAD;  
 }  
   
 #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)  
610    
611            do {
612                    iDirection = 0;
613                    if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1+16+64);
614                    if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2+32+128);
615                    if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4+16+32);
616                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8+64+128);
617                    if (bDirection & 16) CHECK_CANDIDATE(x - iDiamondSize, y - iDiamondSize, 1+4+16+32+64);
618                    if (bDirection & 32) CHECK_CANDIDATE(x + iDiamondSize, y - iDiamondSize, 2+4+16+32+128);
619                    if (bDirection & 64) CHECK_CANDIDATE(x - iDiamondSize, y + iDiamondSize, 1+8+16+64+128);
620                    if (bDirection & 128) CHECK_CANDIDATE(x + iDiamondSize, y + iDiamondSize, 2+8+32+64+128);
621    
622                    bDirection = iDirection;
623  int32_t                  x = data->currentMV->x; y = data->currentMV->y;
624  PMVfastSearch16(const uint8_t * const pRef,          } while (iDirection);
                                 const uint8_t * const pRefH,  
                                 const uint8_t * const pRefV,  
                                 const uint8_t * const pRefHV,  
                                 const IMAGE * const pCur,  
                                 const int x,  
                                 const int y,  
                                 const int start_x,  
                                 const int start_y,  
                                 const int center_x,  
                                 const int center_y,  
                                 const uint32_t MotionFlags,  
                                 const uint32_t iQuant,  
                                 const uint32_t iFcode,  
                                 const MBParam * const pParam,  
                                 const MACROBLOCK * const pMBs,  
                                 const MACROBLOCK * const prevMBs,  
                                 VECTOR * const currMV,  
                                 VECTOR * const currPMV)  
 {  
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
   
         const uint8_t *cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;  
   
         int32_t iDiamondSize;  
   
         int32_t min_dx;  
         int32_t max_dx;  
         int32_t min_dy;  
         int32_t max_dy;  
   
         int32_t iFound;  
   
         VECTOR newMV;  
         VECTOR backupMV;                        /* just for PMVFAST */  
   
         VECTOR pmv[4];  
         int32_t psad[4];  
   
         MainSearch16FuncPtr MainSearchPtr;  
   
         const MACROBLOCK *const prevMB = prevMBs + x + y * iWcount;  
   
         int32_t threshA, threshB;  
         int32_t bPredEq;  
         int32_t iMinSAD, iSAD;  
   
 /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
   
 /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */  
   
         if (!(MotionFlags & PMV_HALFPEL16)) {  
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
         }  
   
         /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
         //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);  
   
         if ((x == 0) && (y == 0)) {  
                 threshA = 512;  
                 threshB = 1024;  
         } else {  
                 threshA = psad[0];  
                 threshB = threshA + 256;  
                 if (threshA < 512)  
                         threshA = 512;  
                 if (threshA > 1024)  
                         threshA = 1024;  
                 if (threshB > 1792)  
                         threshB = 1792;  
         }  
   
         iFound = 0;  
   
 /* Step 4: Calculate SAD around the Median prediction.  
    MinSAD=SAD  
    If Motion Vector equal to Previous frame motion vector  
    and MinSAD<PrevFrmSAD goto Step 10.  
    If SAD<=256 goto Step 10.  
 */  
   
         currMV->x = start_x;  
         currMV->y = start_y;  
   
         if (!(MotionFlags & PMV_HALFPEL16)) {   /* This should NOT be necessary! */  
                 currMV->x = EVEN(currMV->x);  
                 currMV->y = EVEN(currMV->y);  
         }  
   
         if (currMV->x > max_dx) {  
                 currMV->x = max_dx;  
         }  
         if (currMV->x < min_dx) {  
                 currMV->x = min_dx;  
         }  
         if (currMV->y > max_dy) {  
                 currMV->y = max_dy;  
         }  
         if (currMV->y < min_dy) {  
                 currMV->y = min_dy;  
625          }          }
626    
627          iMinSAD =  static void
628                  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  
629                  {                  {
                         if (!MVzero(*currMV)) {  
                                 iMinSAD += MV16_00_BIAS;  
                                 CHECK_MV16_ZERO;        // (0,0) saves space for letterboxed pictures  
                                 iMinSAD -= MV16_00_BIAS;  
                         }  
                 }  
   
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto PMVfast16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto PMVfast16_Terminate_with_Refine;  
         }  
   
   
 /* Step 2 (lazy eval): Calculate Distance= |MedianMVX| + |MedianMVY| where MedianMV is the motion  
    vector of the median.  
    If PredEq=1 and MVpredicted = Previous Frame MV, set Found=2  
 */  
   
         if ((bPredEq) && (MVequal(pmv[0], prevMB->mvs[0])))  
                 iFound = 2;  
   
 /* Step 3 (lazy eval): If Distance>0 or thresb<1536 or PredEq=1 Select small Diamond Search.  
    Otherwise select large Diamond Search.  
 */  
   
         if ((!MVzero(pmv[0])) || (threshB < 1536) || (bPredEq))  
                 iDiamondSize = 1;               // halfpel!  
         else  
                 iDiamondSize = 2;               // halfpel!  
   
         if (!(MotionFlags & PMV_HALFPELDIAMOND16))  
                 iDiamondSize *= 2;  
   
 /*  
    Step 5: Calculate SAD for motion vectors taken from left block, top, top-right, and Previous frame block.  
    Also calculate (0,0) but do not subtract offset.  
    Let MinSAD be the smallest SAD up to this point.  
    If MV is (0,0) subtract offset.  
 */  
   
 // (0,0) is always possible  
   
         if (!MVzero(pmv[0]))  
                 CHECK_MV16_ZERO;  
   
 // previous frame MV is always possible  
630    
631          if (!MVzero(prevMB->mvs[0]))  /* directions: 1 - left (x-1); 2 - right (x+1), 4 - up (y-1); 8 - down (y+1) */
                 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) */  
632    
633                  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);  
634    
635                          if (iSAD < iMinSAD) {          do {
636                                  *currMV = newMV;                  iDirection = 0;
637                                  iMinSAD = iSAD;                  if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
638                          }                  if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
639                  }                  if (bDirection & 4) CHECK_CANDIDATE(x, y - iDiamondSize, 4);
640                    if (bDirection & 8) CHECK_CANDIDATE(x, y + iDiamondSize, 8);
641    
642                  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);  
643    
644                          if (iSAD < iMinSAD) {                  if (iDirection) {               //checking if anything found
645                                  *currMV = newMV;                          bDirection = iDirection;
646                                  iMinSAD = iSAD;                          iDirection = 0;
647                            x = data->currentMV->x; y = data->currentMV->y;
648                            if (bDirection & 3) {   //our candidate is left or right
649                                    CHECK_CANDIDATE(x, y + iDiamondSize, 8);
650                                    CHECK_CANDIDATE(x, y - iDiamondSize, 4);
651                            } else {                        // what remains here is up or down
652                                    CHECK_CANDIDATE(x + iDiamondSize, y, 2);
653                                    CHECK_CANDIDATE(x - iDiamondSize, y, 1);
654                          }                          }
655                            bDirection += iDirection;
656                            x = data->currentMV->x; y = data->currentMV->y;
657                  }                  }
658          }          }
659            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;  
660  }  }
661    
662    /* MAINSEARCH FUNCTIONS END */
663    
664    /* HALFPELREFINE COULD BE A MAINSEARCH FUNCTION, BUT THERE IS NO NEED FOR IT */
665    
666    static void
667    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)  
668  {  {
669  /* 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;  
670          VECTOR backupMV;          VECTOR backupMV;
671            int iDirection; //not needed
672    
673          backupMV.x = start_x;          if (data->qpel_precision)
674          backupMV.y = start_y;                  backupMV = *(data->currentQMV);
675            else backupMV = *(data->currentMV);
 /* It's one search with full Diamond pattern, and only 3 of 4 for all following diamonds */  
676    
677          CHECK_MV8_CANDIDATE_DIR(backupMV.x - iDiamondSize, backupMV.y, 1);          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y - 1, 0);
678          CHECK_MV8_CANDIDATE_DIR(backupMV.x + iDiamondSize, backupMV.y, 2);          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y - 1, 0);
679          CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y - iDiamondSize, 3);          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y + 1, 0);
680          CHECK_MV8_CANDIDATE_DIR(backupMV.x, backupMV.y + iDiamondSize, 4);          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y + 1, 0);
   
         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;  
 }  
681    
682  int32_t          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y, 0);
683  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);  
684    
685          return iMinSAD;          CHECK_CANDIDATE(backupMV.x, backupMV.y + 1, 0);
686            CHECK_CANDIDATE(backupMV.x, backupMV.y - 1, 0);
687  }  }
688    
689    static __inline int
690    SkipDecisionP(const IMAGE * current, const IMAGE * reference,
691                                                            const int x, const int y,
692                                                            const uint32_t iEdgedWidth, const uint32_t iQuant, int rrv)
693    
 #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)  
694  {  {
695          const uint32_t iWcount = pParam->mb_width;  /*      keep repeating checks for all b-frames before this P frame,
696          const int32_t iWidth = pParam->width;          to make sure that SKIP is possible (todo)
697          const int32_t iHeight = pParam->height;          how: if skip is not possible set sad00 to a very high value */
698          const int32_t iEdgedWidth = pParam->edged_width;          if(rrv) {
699                    uint32_t sadC = sad16(current->u + x*16 + y*(iEdgedWidth/2)*16,
700          const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;                                                  reference->u + x*16 + y*(iEdgedWidth/2)*16, iEdgedWidth/2, 256*4096);
701                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
702          int32_t iDiamondSize;                  sadC += sad16(current->v + (x + y*(iEdgedWidth/2))*16,
703                                                    reference->v + (x + y*(iEdgedWidth/2))*16, iEdgedWidth/2, 256*4096);
704          int32_t min_dx;                  if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
705          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;  
   
706          } else {          } else {
707                  threshA = psad[0] / 4;  /* good estimate? */                  uint32_t sadC = sad8(current->u + x*8 + y*(iEdgedWidth/2)*8,
708                  threshB = threshA + 256 / 4;                                                  reference->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2);
709                  if (threshA < 512 / 4)                  if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
710                          threshA = 512 / 4;                  sadC += sad8(current->v + (x + y*(iEdgedWidth/2))*8,
711                  if (threshA > 1024 / 4)                                                  reference->v + (x + y*(iEdgedWidth/2))*8, iEdgedWidth/2);
712                          threshA = 1024 / 4;                  if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
713                  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;  
                         }  
                 }  
714          }          }
   
 /* 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;  
715  }  }
716    
717  int32_t  static __inline void
718  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)  
719  {  {
720          const uint32_t iWcount = pParam->mb_width;          pMB->mode = MODE_NOT_CODED;
721          const uint32_t iHcount = pParam->mb_height;          pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = 0;
722            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;  
723    
724          VECTOR pmv[4];          pMB->qmvs[0].x = pMB->qmvs[1].x = pMB->qmvs[2].x = pMB->qmvs[3].x = 0;
725          int32_t psad[8];          pMB->qmvs[0].y = pMB->qmvs[1].y = pMB->qmvs[2].y = pMB->qmvs[3].y = 0;
726    
727          static MACROBLOCK *oldMBs = NULL;          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
   
 //  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));  
728          }          }
         oldMB = oldMBs + x + y * iWcount;  
   
 /* Get maximum range */  
         get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 16, iWidth, iHeight,  
                           iFcode);  
   
         if (!(MotionFlags & PMV_HALFPEL16)) {  
                 min_dx = EVEN(min_dx);  
                 max_dx = EVEN(max_dx);  
                 min_dy = EVEN(min_dy);  
                 max_dy = EVEN(max_dy);  
         }  
         /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
         //bPredEq = get_pmvdata(pMBs, x, y, iWcount, 0, pmv, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, x, y, 0, pmv, psad);  
   
 /* Step 4: Calculate SAD around the Median prediction.  
         MinSAD=SAD  
         If Motion Vector equal to Previous frame motion vector  
                 and MinSAD<PrevFrmSAD goto Step 10.  
         If SAD<=256 goto Step 10.  
 */  
   
 // Prepare for main loop  
   
         currMV->x = start_x;  
         currMV->y = start_y;  
   
         if (!(MotionFlags & PMV_HALFPEL16)) {  
                 currMV->x = EVEN(currMV->x);  
                 currMV->y = EVEN(currMV->y);  
         }  
   
         if (currMV->x > max_dx)  
                 currMV->x = max_dx;  
         if (currMV->x < min_dx)  
                 currMV->x = min_dx;  
         if (currMV->y > max_dy)  
                 currMV->y = max_dy;  
         if (currMV->y < min_dy)  
                 currMV->y = min_dy;  
   
 /***************** This is predictor SET A: only median prediction ******************/  
   
         iMinSAD =  
                 sad16(cur,  
                           get_ref_mv(pRef, pRefH, pRefV, pRefHV, x, y, 16, currMV,  
                                                  iEdgedWidth), iEdgedWidth, MV_MAX_ERROR);  
         iMinSAD +=  
                 calc_delta_16(currMV->x - center_x, currMV->y - center_y,  
                                           (uint8_t) iFcode, iQuant);  
   
 // thresh1 is fixed to 256  
         if ((iMinSAD < 256) ||  
                 ((MVequal(*currMV, prevMB->mvs[0])) &&  
                  ((int32_t) iMinSAD < prevMB->sad16))) {  
                 if (MotionFlags & PMV_QUICKSTOP16)  
                         goto EPZS16_Terminate_without_Refine;  
                 if (MotionFlags & PMV_EARLYSTOP16)  
                         goto EPZS16_Terminate_with_Refine;  
         }  
   
 /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/  
   
 // previous frame MV  
         CHECK_MV16_CANDIDATE(prevMB->mvs[0].x, prevMB->mvs[0].y);  
   
 // set threshhold based on Min of Prediction and SAD of collocated block  
 // CHECK_MV16 always uses iSAD for the SAD of last vector to check, so now iSAD is what we want  
   
         if ((x == 0) && (y == 0)) {  
                 thresh2 = 512;  
         } else {  
 /* T_k = 1.2 * MIN(SAD_top,SAD_left,SAD_topleft,SAD_coll) +128;   [Tourapis, 2002] */  
   
                 thresh2 = MIN(psad[0], iSAD) * 6 / 5 + 128;  
         }  
   
 // MV=(0,0) is often a good choice  
   
         CHECK_MV16_ZERO;  
729    
730    bool
731    MotionEstimation(MBParam * const pParam,
732                                     FRAMEINFO * const current,
733                                     FRAMEINFO * const reference,
734                                     const IMAGE * const pRefH,
735                                     const IMAGE * const pRefV,
736                                     const IMAGE * const pRefHV,
737                                     const uint32_t iLimit)
738    {
739            MACROBLOCK *const pMBs = current->mbs;
740            const IMAGE *const pCurrent = &current->image;
741            const IMAGE *const pRef = &reference->image;
742    
743  // left neighbour, if allowed          const VECTOR zeroMV = { 0, 0 };
         if (x != 0) {  
                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                         pmv[1].x = EVEN(pmv[1].x);  
                         pmv[1].y = EVEN(pmv[1].y);  
                 }  
                 CHECK_MV16_CANDIDATE(pmv[1].x, pmv[1].y);  
         }  
 // top neighbour, if allowed  
         if (y != 0) {  
                 if (!(MotionFlags & PMV_HALFPEL16)) {  
                         pmv[2].x = EVEN(pmv[2].x);  
                         pmv[2].y = EVEN(pmv[2].y);  
                 }  
                 CHECK_MV16_CANDIDATE(pmv[2].x, pmv[2].y);  
744    
745  // top right neighbour, if allowed          uint32_t mb_width = pParam->mb_width;
746                  if ((uint32_t) x != (iWcount - 1)) {          uint32_t mb_height = pParam->mb_height;
747                          if (!(MotionFlags & PMV_HALFPEL16)) {  
748                                  pmv[3].x = EVEN(pmv[3].x);          uint32_t x, y;
749                                  pmv[3].y = EVEN(pmv[3].y);          uint32_t iIntra = 0;
750            int32_t InterBias, quant = current->quant, sad00;
751            uint8_t *qimage;
752    
753            // some pre-initialized thingies for SearchP
754            int32_t temp[8];
755            VECTOR currentMV[5];
756            VECTOR currentQMV[5];
757            int32_t iMinSAD[5];
758            SearchData Data;
759            memset(&Data, 0, sizeof(SearchData));
760            Data.iEdgedWidth = pParam->edged_width;
761            Data.currentMV = currentMV;
762            Data.currentQMV = currentQMV;
763            Data.iMinSAD = iMinSAD;
764            Data.temp = temp;
765            Data.iFcode = current->fcode;
766            Data.rounding = pParam->m_rounding_type;
767            Data.qpel = pParam->m_quarterpel;
768            Data.chroma = current->global_flags & XVID_ME_COLOUR;
769            Data.rrv = current->global_flags & XVID_REDUCED;
770    
771            if ((current->global_flags & XVID_REDUCED)) {
772                    mb_width = (pParam->width + 31) / 32;
773                    mb_height = (pParam->height + 31) / 32;
774                    Data.qpel = Data.chroma = 0;
775            }
776    
777            if((qimage = (uint8_t *) malloc(32 * pParam->edged_width)) == NULL)
778                    return 1; // allocate some mem for qpel interpolated blocks
779                                      // somehow this is dirty since I think we shouldn't use malloc outside
780                                      // encoder_create() - so please fix me!
781            Data.RefQ = qimage;
782            if (sadInit) (*sadInit) ();
783    
784            for (y = 0; y < mb_height; y++) {
785                    for (x = 0; x < mb_width; x++)  {
786                            MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
787    
788                            if (Data.rrv) pMB->sad16 =
789                                    sad32v_c(pCurrent->y + (x + y * pParam->edged_width) * 32,
790                                                            pRef->y + (x + y * pParam->edged_width) * 32,
791                                                            pParam->edged_width, pMB->sad8 );
792    
793                            else pMB->sad16 =
794                                    sad16v(pCurrent->y + (x + y * pParam->edged_width) * 16,
795                                                            pRef->y + (x + y * pParam->edged_width) * 16,
796                                                            pParam->edged_width, pMB->sad8 );
797    
798                            if (Data.chroma) {
799                                    pMB->sad16 += sad8(pCurrent->u + x*8 + y*(pParam->edged_width/2)*8,
800                                                                    pRef->u + x*8 + y*(pParam->edged_width/2)*8, pParam->edged_width/2);
801    
802                                    pMB->sad16 += sad8(pCurrent->v + (x + y*(pParam->edged_width/2))*8,
803                                                                    pRef->v + (x + y*(pParam->edged_width/2))*8, pParam->edged_width/2);
804                            }
805    
806                            sad00 = pMB->sad16; //if no gmc; else sad00 = (..)
807    
808                            if (!(current->global_flags & XVID_LUMIMASKING)) {
809                                    pMB->dquant = NO_CHANGE;
810                                    pMB->quant = current->quant;
811                            } else {
812                                    if (pMB->dquant != NO_CHANGE) {
813                                            quant += DQtab[pMB->dquant];
814                                            if (quant > 31) quant = 31;
815                                            else if (quant < 1) quant = 1;
816                                    }
817                                    pMB->quant = quant;
818                          }                          }
819                          CHECK_MV16_CANDIDATE(pmv[3].x, pmv[3].y);  
820    //initial skip decision
821    /* no early skip for GMC (global vector = skip vector is unknown!)  */
822                            if (current->coding_type == P_VOP)      { /* no fast SKIP for S(GMC)-VOPs */
823                                    if (pMB->dquant == NO_CHANGE && sad00 < pMB->quant * INITIAL_SKIP_THRESH  * (Data.rrv ? 4:1) )
824                                            if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, pParam->edged_width, pMB->quant, Data.rrv)) {
825                                                    SkipMacroblockP(pMB, sad00);
826                                                    continue;
827                  }                  }
828          }          }
829    
830  /* Terminate if MinSAD <= T_2                          SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
831     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]                                                  y, current->motion_flags, pMB->quant,
832  */                                                  &Data, pParam, pMBs, reference->mbs,
833                                                    current->global_flags & XVID_INTER4V, pMB);
834          if ((iMinSAD <= thresh2)  
835                  || (MVequal(*currMV, prevMB->mvs[0]) &&  /* final skip decision, a.k.a. "the vector you found, really that good?" */
836                          ((int32_t) iMinSAD <= prevMB->sad16))) {                          if (current->coding_type == P_VOP)      {
837                  if (MotionFlags & PMV_QUICKSTOP16)                                  if ( (pMB->dquant == NO_CHANGE) && (sad00 < pMB->quant * MAX_SAD00_FOR_SKIP)
838                          goto EPZS16_Terminate_without_Refine;                                          && ((100*pMB->sad16)/(sad00+1) > FINAL_SKIP_THRESH * (Data.rrv ? 4:1)) )
839                  if (MotionFlags & PMV_EARLYSTOP16)                                          if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, pParam->edged_width, pMB->quant, Data.rrv)) {
840                          goto EPZS16_Terminate_with_Refine;                                                  SkipMacroblockP(pMB, sad00);
841                                                    continue;
842                                            }
843          }          }
844    
845  /***** 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);  
846    
847  // top neighbour                          InterBias = MV16_INTER_BIAS;
848                            if (pMB->quant > 8)  InterBias += 100 * (pMB->quant - 8); // to make high quants work
849          if (y != 0)          if (y != 0)
850                  CHECK_MV16_CANDIDATE((prevMB - iWcount)->mvs[0].x,                                  if ((pMB - pParam->mb_width)->mode == MODE_INTRA ) InterBias -= 80;
851                                                           (prevMB - iWcount)->mvs[0].y);                          if (x != 0)
852                                    if ((pMB - 1)->mode == MODE_INTRA ) InterBias -= 80;
 // right neighbour, if allowed (this value is not written yet, so take it from   pMB->mvs  
853    
854          if ((uint32_t) x != iWcount - 1)                          if (Data.chroma) InterBias += 50; // to compensate bigger SAD
855                  CHECK_MV16_CANDIDATE((prevMB + 1)->mvs[0].x, (prevMB + 1)->mvs[0].y);                          if (Data.rrv) InterBias *= 4; //??
856    
857  // bottom neighbour, dito                          if (InterBias < pMB->sad16)  {
858          if ((uint32_t) y != iHcount - 1)                                  int32_t deviation;
859                  CHECK_MV16_CANDIDATE((prevMB + iWcount)->mvs[0].x,                                  if (Data.rrv) {
860                                                           (prevMB + iWcount)->mvs[0].y);                                          deviation = dev16(pCurrent->y + (x + y * pParam->edged_width) * 32,
861                                                                                    pParam->edged_width)
862                                                    + dev16(pCurrent->y + (x + y * pParam->edged_width) * 32 + 16,
863                                                                                    pParam->edged_width)
864                                                    + dev16(pCurrent->y + (x + y * pParam->edged_width) * 32 + 16 * pParam->edged_width,
865                                                                                    pParam->edged_width)
866                                                    + dev16(pCurrent->y + (x + y * pParam->edged_width) * 32 + 16 * (pParam->edged_width+1),
867                                                                                    pParam->edged_width);
868                                    } else
869                                            deviation = dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,
870                                                      pParam->edged_width);
871    
872  /* Terminate if MinSAD <= T_3 (here T_3 = T_2)  */                                          if (deviation < (pMB->sad16 - InterBias)) {
873          if (iMinSAD <= thresh2) {                                          if (++iIntra >= iLimit) { free(qimage); return 1; }
874                  if (MotionFlags & PMV_QUICKSTOP16)                                          pMB->mode = MODE_INTRA;
875                          goto EPZS16_Terminate_without_Refine;                                          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =
876                  if (MotionFlags & PMV_EARLYSTOP16)                                                          pMB->mvs[3] = zeroMV;
877                          goto EPZS16_Terminate_with_Refine;                                          pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] =
878                                                            pMB->qmvs[3] = zeroMV;
879                                            pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =
880                                                    pMB->sad8[3] = 0;
881          }          }
882                            }
883                    }
884            }
885            free(qimage);
886    
887  /************ (if Diamond Search)  **************/          if (current->coding_type == S_VOP)      /* first GMC step only for S(GMC)-VOPs */
888                    current->GMC_MV = GlobalMotionEst( pMBs, pParam, current->fcode );
         backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */  
   
         if (MotionFlags & PMV_USESQUARES16)  
                 MainSearchPtr = Square16_MainSearch;  
889          else          else
890           if (MotionFlags & PMV_ADVANCEDDIAMOND16)                  current->GMC_MV = zeroMV;
                 MainSearchPtr = AdvDiamond16_MainSearch;  
         else  
                 MainSearchPtr = Diamond16_MainSearch;  
   
 /* default: use best prediction as starting point for one call of PMVfast_MainSearch */  
891    
892          iSAD =          return 0;
                 (*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;  
893          }          }
894    
895    
896          if (MotionFlags & PMV_EXTSEARCH16) {  #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)
 /* extended mode: search (up to) two more times: orignal prediction and (0,0) */  
897    
898                  if (!(MVequal(pmv[0], backupMV))) {  static __inline int
899                          iSAD =  make_mask(const VECTOR * const pmv, const int i)
900                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y,  {
901                                                                    pmv[0].x, pmv[0].y, iMinSAD, &newMV, center_x, center_y,          int mask = 255, j;
902                                                                    min_dx, max_dx, min_dy, max_dy, iEdgedWidth,          for (j = 0; j < i; j++) {
903                                                                    2, iFcode, iQuant, 0);                  if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already
904                    if (pmv[i].x == pmv[j].x) {
905                            if (pmv[i].y == pmv[j].y + iDiamondSize) { mask &= ~4; continue; }
906                            if (pmv[i].y == pmv[j].y - iDiamondSize) { mask &= ~8; continue; }
907                    } else
908                            if (pmv[i].y == pmv[j].y) {
909                                    if (pmv[i].x == pmv[j].x + iDiamondSize) { mask &= ~1; continue; }
910                                    if (pmv[i].x == pmv[j].x - iDiamondSize) { mask &= ~2; continue; }
911                  }                  }
912            }
913                  if (iSAD < iMinSAD) {          return mask;
                         *currMV = newMV;  
                         iMinSAD = iSAD;  
914                  }                  }
915    
916                  if ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {  static __inline void
917                          iSAD =  PreparePredictionsP(VECTOR * const pmv, int x, int y, int iWcount,
918                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                          int iHcount, const MACROBLOCK * const prevMB, int rrv)
919                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,  {
                                                                   max_dy, iEdgedWidth, 2, iFcode, iQuant, 0);  
920    
921                          if (iSAD < iMinSAD) {  //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself
922                                  *currMV = newMV;          if (rrv) { iWcount /= 2; iHcount /= 2; }
                                 iMinSAD = iSAD;  
                         }  
                 }  
         }  
923    
924  /***************        Choose best MV found     **************/          if ( (y != 0) && (x < (iWcount-1)) ) {          // [5] top-right neighbour
925                    pmv[5].x = EVEN(pmv[3].x);
926                    pmv[5].y = EVEN(pmv[3].y);
927            } else pmv[5].x = pmv[5].y = 0;
928    
929    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
930          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);  
931    
932    EPZS16_Terminate_without_Refine:          if (y != 0) { pmv[4].x = EVEN(pmv[2].x); pmv[4].y = EVEN(pmv[2].y); }// [4] top neighbour
933        else pmv[4].x = pmv[4].y = 0;
934    
935          *oldMB = *prevMB;          // [1] median prediction
936            if (rrv) { //median is in halfzero-precision
937                    pmv[1].x = RRV_MV_SCALEUP(pmv[0].x);
938                    pmv[1].y = RRV_MV_SCALEUP(pmv[0].y);
939            } else { pmv[1].x = EVEN(pmv[0].x); pmv[1].y = EVEN(pmv[0].y); }
940    
941          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
942          currPMV->y = currMV->y - center_y;  
943          return iMinSAD;          pmv[2].x = EVEN(prevMB->mvs[0].x); // [2] is last frame
944  }          pmv[2].y = EVEN(prevMB->mvs[0].y);
945    
946            if ((x < iWcount-1) && (y < iHcount-1)) {
947                    pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); //[6] right-down neighbour in last frame
948                    pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
949            } else pmv[6].x = pmv[6].y = 0;
950    
951  int32_t          if (rrv) {
952  EPZSSearch8(const uint8_t * const pRef,                  int i;
953                    for (i = 0; i < 7; i++) {
954                            pmv[i].x = RRV_MV_SCALEDOWN(pmv[i].x);
955                            pmv[i].x = RRV_MV_SCALEUP(pmv[i].x); // a trick
956                    }
957            }
958    }
959    
960    static void
961    SearchP(const IMAGE * const pRef,
962                          const uint8_t * const pRefH,                          const uint8_t * const pRefH,
963                          const uint8_t * const pRefV,                          const uint8_t * const pRefV,
964                          const uint8_t * const pRefHV,                          const uint8_t * const pRefHV,
965                          const IMAGE * const pCur,                          const IMAGE * const pCur,
966                          const int x,                          const int x,
967                          const int y,                          const int y,
                         const int start_x,  
                         const int start_y,  
                         const int center_x,  
                         const int center_y,  
968                          const uint32_t MotionFlags,                          const uint32_t MotionFlags,
969                          const uint32_t iQuant,                          const uint32_t iQuant,
970                          const uint32_t iFcode,                  SearchData * const Data,
971                          const MBParam * const pParam,                          const MBParam * const pParam,
972                          const MACROBLOCK * const pMBs,                          const MACROBLOCK * const pMBs,
973                          const MACROBLOCK * const prevMBs,                          const MACROBLOCK * const prevMBs,
974                          VECTOR * const currMV,                  int inter4v,
975                          VECTOR * const currPMV)                  MACROBLOCK * const pMB)
976  {  {
 /* Please not that EPZS might not be a good choice for 8x8-block motion search ! */  
   
         const uint32_t iWcount = pParam->mb_width;  
         const int32_t iWidth = pParam->width;  
         const int32_t iHeight = pParam->height;  
         const int32_t iEdgedWidth = pParam->edged_width;  
   
         const uint8_t *cur = pCur->y + x * 8 + y * 8 * iEdgedWidth;  
977    
978          int32_t iDiamondSize = 1;          int i, iDirection = 255, mask, threshA;
979            VECTOR pmv[7];
980    
981          int32_t min_dx;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
982          int32_t max_dx;                                                  pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
         int32_t min_dy;  
         int32_t max_dy;  
983    
984          VECTOR newMV;          get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);  //has to be changed to get_pmv(2)()
         VECTOR backupMV;  
   
         VECTOR pmv[4];  
         int32_t psad[8];  
985    
986          const int32_t iSubBlock = ((y & 1) << 1) + (x & 1);          Data->temp[5] = Data->temp[7] = 256*4096; // to reset chroma-sad cache
987            if (Data->rrv) i = 2; else i = 1;
988            Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16*i;
989            Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
990            Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
991    
992  //  const MACROBLOCK * const pMB = pMBs + (x>>1) + (y>>1) * iWcount;          Data->Ref = pRef->y + (x + Data->iEdgedWidth*y) * 16*i;
993          const MACROBLOCK *const prevMB = prevMBs + (x >> 1) + (y >> 1) * iWcount;          Data->RefH = pRefH + (x + Data->iEdgedWidth*y) * 16*i;
994            Data->RefV = pRefV + (x + Data->iEdgedWidth*y) * 16*i;
995            Data->RefHV = pRefHV + (x + Data->iEdgedWidth*y) * 16*i;
996            Data->RefCV = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
997            Data->RefCU = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
998    
999          int32_t bPredEq;          Data->lambda16 = lambda_vec16[iQuant];
1000          int32_t iMinSAD, iSAD = 9999;          Data->lambda8 = lambda_vec8[iQuant];
1001            Data->qpel_precision = 0;
1002    
1003          MainSearch8FuncPtr MainSearchPtr;          if (pMB->dquant != NO_CHANGE) inter4v = 0;
1004    
1005  /* Get maximum range */          for(i = 0;  i < 5; i++)
1006          get_range(&min_dx, &max_dx, &min_dy, &max_dy, x, y, 8, iWidth, iHeight,                  Data->currentMV[i].x = Data->currentMV[i].y = 0;
                           iFcode);  
1007    
1008  /* we work with abs. MVs, not relative to prediction, so get_range is called relative to 0,0 */          if (pParam->m_quarterpel) Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1009            else Data->predMV = pmv[0];
1010    
1011          if (!(MotionFlags & PMV_HALFPEL8)) {          i = d_mv_bits(0, 0, Data->predMV, Data->iFcode, 0, 0);
1012                  min_dx = EVEN(min_dx);          Data->iMinSAD[0] = pMB->sad16 + (Data->lambda16 * i * pMB->sad16)/1000;
1013                  max_dx = EVEN(max_dx);          Data->iMinSAD[1] = pMB->sad8[0] + (Data->lambda8 * i * (pMB->sad8[0]+NEIGH_8X8_BIAS))/100;
1014                  min_dy = EVEN(min_dy);          Data->iMinSAD[2] = pMB->sad8[1];
1015                  max_dy = EVEN(max_dy);          Data->iMinSAD[3] = pMB->sad8[2];
1016          }          Data->iMinSAD[4] = pMB->sad8[3];
         /* because we might use something like IF (dx>max_dx) THEN dx=max_dx; */  
         //bPredEq = get_pmvdata(pMBs, x >> 1, y >> 1, iWcount, iSubBlock, pmv[0].x, pmv[0].y, psad);  
         bPredEq = get_pmvdata2(pMBs, iWcount, 0, x >> 1, y >> 1, iSubBlock, pmv, psad);  
1017    
1018            if ((x == 0) && (y == 0)) threshA = 512;
1019            else {
1020                    threshA = Data->temp[0]; // that's when we keep this SAD atm
1021                    if (threshA < 512) threshA = 512;
1022                    if (threshA > 1024) threshA = 1024; }
1023    
1024  /* Step 4: Calculate SAD around the Median prediction.          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
1025          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.  
 */  
1026    
1027  // Prepare for main loop          if (Data->rrv) CheckCandidate = CheckCandidate32;
1028            else if (inter4v || Data->chroma) CheckCandidate = CheckCandidate16;
1029                    else CheckCandidate = CheckCandidate16no4v; //for extra speed
1030    
1031    /* main loop. checking all predictions */
1032    
1033          if (!(MotionFlags & PMV_HALFPEL8)) {          for (i = 1; i < 7; i++) {
1034                  currMV->x = EVEN(currMV->x);                  if (!(mask = make_mask(pmv, i)) ) continue;
1035                  currMV->y = EVEN(currMV->y);                  (*CheckCandidate)(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1036                    if (Data->iMinSAD[0] <= threshA) break;
1037          }          }
1038    
1039          if (currMV->x > max_dx)          if ((Data->iMinSAD[0] <= threshA) ||
1040                  currMV->x = max_dx;                          (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
1041          if (currMV->x < min_dx)                          (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16))) {
1042                  currMV->x = min_dx;                  inter4v = 0;
1043          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);  
1044    
1045                    MainSearchFunc * MainSearchPtr;
1046                    if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1047                    else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1048                            else MainSearchPtr = DiamondSearch;
1049    
1050                    (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
1051    
1052    /* extended search, diamond starting in 0,0 and in prediction.
1053            note that this search is/might be done in halfpel positions,
1054            which makes it more different than the diamond above */
1055    
1056  // thresh1 is fixed to 256                  if (MotionFlags & PMV_EXTSEARCH16) {
1057          if (iMinSAD < 256 / 4) {                          int32_t bSAD;
1058                  if (MotionFlags & PMV_QUICKSTOP8)                          VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
1059                          goto EPZS8_Terminate_without_Refine;                          if (Data->rrv) {
1060                  if (MotionFlags & PMV_EARLYSTOP8)                                  startMV.x = RRV_MV_SCALEUP(startMV.x);
1061                          goto EPZS8_Terminate_with_Refine;                                  startMV.y = RRV_MV_SCALEUP(startMV.y);
1062                            } else
1063                                    if (!(MotionFlags & PMV_HALFPELREFINE16)) // who's gonna use extsearch and no halfpel?
1064                                            startMV.x = EVEN(startMV.x); startMV.y = EVEN(startMV.y);
1065                            if (!(MVequal(startMV, backupMV))) {
1066                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1067    
1068                                    (*CheckCandidate)(startMV.x, startMV.y, 255, &iDirection, Data);
1069                                    (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
1070                                    if (bSAD < Data->iMinSAD[0]) {
1071                                            Data->currentMV[0] = backupMV;
1072                                            Data->iMinSAD[0] = bSAD; }
1073                            }
1074    
1075                            backupMV = Data->currentMV[0];
1076                            if (!MotionFlags & PMV_HALFPELREFINE16 || Data->rrv) startMV.x = startMV.y = 0;
1077                            else startMV.x = startMV.y = 1;
1078                            if (!(MVequal(startMV, backupMV))) {
1079                                    bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1080    
1081                                    (*CheckCandidate)(startMV.x, startMV.y, 255, &iDirection, Data);
1082                                    (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
1083                                    if (bSAD < Data->iMinSAD[0]) {
1084                                            Data->currentMV[0] = backupMV;
1085                                            Data->iMinSAD[0] = bSAD; }
1086                            }
1087                    }
1088            }
1089    
1090            if (MotionFlags & PMV_HALFPELREFINE16) SubpelRefine(Data);
1091    
1092            for(i = 0; i < 5; i++) {
1093                    Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // initialize qpel vectors
1094                    Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
1095            }
1096    
1097            if((!Data->rrv) && (pParam->m_quarterpel) && (MotionFlags & PMV_QUARTERPELREFINE16)) {
1098    
1099                    Data->qpel_precision = 1;
1100                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1101                                    pParam->width, pParam->height, Data->iFcode, 1, 0);
1102    
1103                    SubpelRefine(Data);
1104            }
1105    
1106            if (Data->iMinSAD[0] < (int32_t)iQuant * 30 ) inter4v = 0;
1107            if (inter4v) {
1108                    SearchData Data8;
1109                    Data8.iFcode = Data->iFcode;
1110                    Data8.lambda8 = Data->lambda8;
1111                    Data8.iEdgedWidth = Data->iEdgedWidth;
1112                    Data8.RefQ = Data->RefQ;
1113                    Data8.qpel = Data->qpel;
1114                    Data8.rrv = Data->rrv;
1115                    Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
1116                    Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
1117                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
1118                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
1119    
1120                    if (Data->chroma) {
1121                            int sumx, sumy, dx, dy;
1122    
1123                            if(pParam->m_quarterpel) {
1124                                    sumx= pMB->qmvs[0].x/2 + pMB->qmvs[1].x/2 + pMB->qmvs[2].x/2 + pMB->qmvs[3].x/2;
1125                                    sumy = pMB->qmvs[0].y/2 + pMB->qmvs[1].y/2 + pMB->qmvs[2].y/2 + pMB->qmvs[3].y/2;
1126                            } else {
1127                                    sumx = pMB->mvs[0].x + pMB->mvs[1].x + pMB->mvs[2].x + pMB->mvs[3].x;
1128                                    sumy = pMB->mvs[0].y + pMB->mvs[1].y + pMB->mvs[2].y + pMB->mvs[3].y;
1129          }          }
1130                            dx = (sumx >> 3) + roundtab_76[sumx & 0xf];
1131                            dy = (sumy >> 3) + roundtab_76[sumy & 0xf];
1132    
1133  /************** This is predictor SET B: (0,0), prev.frame MV, neighbours **************/                          Data->iMinSAD[1] += ChromaSAD(dx, dy, Data);
   
   
 // MV=(0,0) is often a good choice  
         CHECK_MV8_ZERO;  
   
 // previous frame MV  
         CHECK_MV8_CANDIDATE(prevMB->mvs[iSubBlock].x, prevMB->mvs[iSubBlock].y);  
   
 // left neighbour, if allowed  
         if (psad[1] != MV_MAX_ERROR) {  
                 if (!(MotionFlags & PMV_HALFPEL8)) {  
                         pmv[1].x = EVEN(pmv[1].x);  
                         pmv[1].y = EVEN(pmv[1].y);  
1134                  }                  }
                 CHECK_MV8_CANDIDATE(pmv[1].x, pmv[1].y);  
1135          }          }
1136  // top neighbour, if allowed  
1137          if (psad[2] != MV_MAX_ERROR) {          if (Data->rrv) {
1138                  if (!(MotionFlags & PMV_HALFPEL8)) {                          Data->currentMV[0].x = RRV_MV_SCALEDOWN(Data->currentMV[0].x);
1139                          pmv[2].x = EVEN(pmv[2].x);                          Data->currentMV[0].y = RRV_MV_SCALEDOWN(Data->currentMV[0].y);
                         pmv[2].y = EVEN(pmv[2].y);  
1140                  }                  }
1141                  CHECK_MV8_CANDIDATE(pmv[2].x, pmv[2].y);          if (!(inter4v) ||
1142                    (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  // top right neighbour, if allowed                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =
1150                  if (psad[3] != MV_MAX_ERROR) {                          pMB->sad8[2] = pMB->sad8[3] =  Data->iMinSAD[0];
1151                          if (!(MotionFlags & PMV_HALFPEL8)) {  
1152                                  pmv[3].x = EVEN(pmv[3].x);                  if(pParam->m_quarterpel) {
1153                                  pmv[3].y = EVEN(pmv[3].y);                          pMB->qmvs[0] = pMB->qmvs[1]
1154                                    = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1155                            pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1156                            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[3].x, pmv[3].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                  }                  }
1167          }          }
1168    
1169  /*  // this bias is zero anyway, at the moment!  static void
1170    Search8(const SearchData * const OldData,
1171          if ( (MVzero(*currMV)) && (!MVzero(pmv[0])) ) // && (iMinSAD <= iQuant * 96)                  const int x, const int y,
1172                  iMinSAD -= MV8_00_BIAS;                  const uint32_t MotionFlags,
1173                    const MBParam * const pParam,
1174  */                  MACROBLOCK * const pMB,
1175                    const MACROBLOCK * const pMBs,
1176  /* Terminate if MinSAD <= T_2                  const int block,
1177     Terminate if MV[t] == MV[t-1] and MinSAD[t] <= MinSAD[t-1]                  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          if (iMinSAD < 512 / 4) {        /* T_2 == 512/4 hardcoded */          } else {
1190                  if (MotionFlags & PMV_QUICKSTOP8)                  Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1191                          goto EPZS8_Terminate_without_Refine;                  if (block != 0) {
1192                  if (MotionFlags & PMV_EARLYSTOP8)                          if (block != 0) i = d_mv_bits(  Data->currentMV->x, Data->currentMV->y,
1193                          goto EPZS8_Terminate_with_Refine;                                                                                          Data->predMV, Data->iFcode, 0, Data->rrv);
1194                    }
1195          }          }
1196    
1197  /************ (Diamond Search)  **************/          *(Data->iMinSAD) += (Data->lambda8 * i * (*Data->iMinSAD + NEIGH_8X8_BIAS))/100;
1198    
1199          backupMV = *currMV;                     /* save best prediction, actually only for EXTSEARCH */          if (MotionFlags & (PMV_EXTSEARCH8|PMV_HALFPELREFINE8)) {
1200                    if (Data->rrv) i = 2; else i = 1;
1201    
1202          if (!(MotionFlags & PMV_HALFPELDIAMOND8))                  Data->Ref = OldData->Ref + i*8 * ((block&1) + pParam->edged_width*(block>>1));
1203                  iDiamondSize *= 2;                  Data->RefH = OldData->RefH + i*8 * ((block&1) + pParam->edged_width*(block>>1));
1204                    Data->RefV = OldData->RefV + i*8 * ((block&1) + pParam->edged_width*(block>>1));
1205                    Data->RefHV = OldData->RefHV + i*8 * ((block&1) + pParam->edged_width*(block>>1));
1206    
1207  /* default: use best prediction as starting point for one call of EPZS_MainSearch */                  Data->Cur = OldData->Cur + i*8 * ((block&1) + pParam->edged_width*(block>>1));
1208                    Data->qpel_precision = 0;
1209    
1210  // there is no EPZS^2 for inter4v at the moment                  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_USESQUARES8)                  if (Data->rrv) CheckCandidate = CheckCandidate16no4v;
1214  //      MainSearchPtr = Square8_MainSearch;                  else CheckCandidate = CheckCandidate8;
 //  else  
1215    
1216          if (MotionFlags & PMV_ADVANCEDDIAMOND8)                  if (MotionFlags & PMV_EXTSEARCH8) {
1217                  MainSearchPtr = AdvDiamond8_MainSearch;                          int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
         else  
                 MainSearchPtr = Diamond8_MainSearch;  
1218    
1219          iSAD =                          MainSearchFunc *MainSearchPtr;
1220                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, currMV->x,                          if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
1221                                                    currMV->y, iMinSAD, &newMV, center_x, center_y, min_dx, max_dx,                                  else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1222                                                    min_dy, max_dy, iEdgedWidth, iDiamondSize, iFcode,                                          else MainSearchPtr = DiamondSearch;
                                                   iQuant, 0);  
1223    
1224                            (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);
1225    
1226          if (iSAD < iMinSAD) {                          if(*(Data->iMinSAD) < temp_sad) {
1227                  *currMV = newMV;                                          Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1228                  iMinSAD = iSAD;                                          Data->currentQMV->y = 2 * Data->currentMV->y;
1229                            }
1230          }          }
1231    
1232          if (MotionFlags & PMV_EXTSEARCH8) {                  if (MotionFlags & PMV_HALFPELREFINE8) {
1233  /* extended mode: search (up to) two more times: orignal prediction and (0,0) */                          int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
1234    
1235                  if (!(MVequal(pmv[0], backupMV))) {                          SubpelRefine(Data); // perform halfpel refine of current best vector
                         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, 0);  
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 ((!(MVzero(pmv[0]))) && (!(MVzero(backupMV)))) {                  if(!Data->rrv && Data->qpel) {
1244                          iSAD =                          if((!(Data->currentQMV->x & 1)) && (!(Data->currentQMV->y & 1)) &&
1245                                  (*MainSearchPtr) (pRef, pRefH, pRefV, pRefHV, cur, x, y, 0, 0,                                  (MotionFlags & PMV_QUARTERPELREFINE8)) {
1246                                                                    iMinSAD, &newMV, center_x, center_y, min_dx, max_dx, min_dy,                          Data->qpel_precision = 1;
1247                                                                    max_dy, iEdgedWidth, iDiamondSize, iFcode,                          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1248                                                                    iQuant, 0);                                  pParam->width, pParam->height, OldData->iFcode, 1, 0);
1249                            SubpelRefine(Data);
1250                          if (iSAD < iMinSAD) {                          }
                                 *currMV = newMV;  
                                 iMinSAD = iSAD;  
1251                          }                          }
1252                  }                  }
1253    
1254            if (Data->rrv) {
1255                            Data->currentMV->x = RRV_MV_SCALEDOWN(Data->currentMV->x);
1256                            Data->currentMV->y = RRV_MV_SCALEDOWN(Data->currentMV->y);
1257          }          }
1258    
1259  /***************        Choose best MV found     **************/          if(Data->qpel) {
1260                    pMB->pmvs[block].x = Data->currentQMV->x - Data->predMV.x;
1261                    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    EPZS8_Terminate_with_Refine:          pMB->mvs[block] = *(Data->currentMV);
1269          if (MotionFlags & PMV_HALFPELREFINE8)   // perform final half-pel step          pMB->sad8[block] =  4 * (*Data->iMinSAD);
1270                  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);  
1271    
1272    EPZS8_Terminate_without_Refine:  /* B-frames code starts here */
1273    
1274          currPMV->x = currMV->x - center_x;  static __inline VECTOR
1275          currPMV->y = currMV->y - center_y;  ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1276          return iMinSAD;  {
1277    /* the stupidiest function ever */
1278            if (mode == MODE_FORWARD) return pMB->mvs[0];
1279            else return pMB->b_mvs[0];
1280  }  }
1281    
1282    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            // [0] is prediction
1290            pmv[0].x = EVEN(pmv[0].x); pmv[0].y = EVEN(pmv[0].y);
1291    
1292            pmv[1].x = pmv[1].y = 0; // [1] is zero
1293    
1294            pmv[2] = ChoosePred(pMB, mode_curr);
1295            pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
1296    
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, 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 < 8; 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, 255);
         VECTOR backupMV;                        /* just for PMVFAST */  
1378    
1379          VECTOR pmv[4];          SubpelRefine(Data);
         int32_t psad[4];  
1380    
1381          MainSearch16FuncPtr MainSearchPtr;          if (Data->qpel) {
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    // we treat the bits just like they were vector's
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) 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                    CheckCandidate = CheckCandidateInt;
1692                    fData->qpel_precision = bData.qpel_precision = 1;
1693                    get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode, 1, 0);
1694                    get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode, 1, 0);
1695                    fData->currentQMV[2].x = fData->currentQMV[0].x = 2 * fData->currentMV[0].x;
1696                    fData->currentQMV[2].y = fData->currentQMV[0].y = 2 * fData->currentMV[0].y;
1697                    fData->currentQMV[1].x = 2 * fData->currentMV[1].x;
1698                    fData->currentQMV[1].y = 2 * fData->currentMV[1].y;
1699                    SubpelRefine(fData);
1700                    fData->currentQMV[2] = fData->currentQMV[0];
1701                    SubpelRefine(&bData);
1702            }
1703    
1704            *fData->iMinSAD +=  (2+2) * fData->lambda16; // two bits are needed to code interpolate mode.
1705    
1706            if (*fData->iMinSAD < *best_sad) {
1707                    *best_sad = *fData->iMinSAD;
1708                    pMB->mvs[0] = fData->currentMV[0];
1709                    pMB->b_mvs[0] = fData->currentMV[1];
1710                    pMB->mode = MODE_INTERPOLATE;
1711                    if (fData->qpel) {
1712                            pMB->qmvs[0] = fData->currentQMV[0];
1713                            pMB->b_qmvs[0] = fData->currentQMV[1];
1714                            pMB->pmvs[1].x = pMB->qmvs[0].x - f_predMV->x;
1715                            pMB->pmvs[1].y = pMB->qmvs[0].y - f_predMV->y;
1716                            pMB->pmvs[0].x = pMB->b_qmvs[0].x - b_predMV->x;
1717                            pMB->pmvs[0].y = pMB->b_qmvs[0].y - b_predMV->y;
1718                    } else {
1719                            pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;
1720                            pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;
1721                            pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;
1722                            pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;
1723                    }
1724            }
1725    }
1726    
1727  void  void
1728  MotionEstimationBVOP(MBParam * const pParam,  MotionEstimationBVOP(MBParam * const pParam,
# Line 2850  Line 1736 
1736                                           const IMAGE * const f_refV,                                           const IMAGE * const f_refV,
1737                                           const IMAGE * const f_refHV,                                           const IMAGE * const f_refHV,
1738                                           // backward (future) reference                                           // backward (future) reference
1739                                           const MACROBLOCK * const b_mbs,                                           const FRAMEINFO * const b_reference,
1740                                           const IMAGE * const b_ref,                                           const IMAGE * const b_ref,
1741                                           const IMAGE * const b_refH,                                           const IMAGE * const b_refH,
1742                                           const IMAGE * const b_refV,                                           const IMAGE * const b_refV,
1743                                           const IMAGE * const b_refHV)                                           const IMAGE * const b_refHV)
1744  {  {
1745          const int mb_width = pParam->mb_width;          uint32_t i, j;
1746          const int mb_height = pParam->mb_height;          int32_t best_sad;
1747          const int edged_width = pParam->edged_width;          uint32_t skip_sad;
1748            int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;
         int i, j, k;  
   
1749          static const VECTOR zeroMV={0,0};          static const VECTOR zeroMV={0,0};
1750            const MACROBLOCK * const b_mbs = b_reference->mbs;
1751    
1752            VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
1753    
1754          int f_sad16;    /* forward (as usual) search */          const int32_t TRB = time_pp - time_bp;
1755          int b_sad16;    /* backward (only in b-frames) search */          const int32_t TRD = time_pp;
1756          int i_sad16;    /* interpolated (both direction, b-frames only) */          uint8_t * qimage;
1757          int d_sad16;    /* direct mode (assume linear motion) */  
1758          int dnv_sad16;  /* direct mode (assume linear motion) without correction vector */  // some pre-inintialized data for the rest of the search
1759    
1760          int best_sad;          SearchData Data;
1761            int32_t iMinSAD;
1762          VECTOR f_predMV, b_predMV;      /* there is no direct prediction */          VECTOR currentMV[3];
1763          VECTOR pmv_dontcare;          VECTOR currentQMV[3];
1764            memset(&Data, 0, sizeof(SearchData));
1765          int f_count=0;          Data.iEdgedWidth = pParam->edged_width;
1766          int b_count=0;          Data.currentMV = currentMV; Data.currentQMV = currentQMV;
1767          int i_count=0;          Data.iMinSAD = &iMinSAD;
1768          int d_count=0;          Data.lambda16 = lambda_vec16[frame->quant];
1769          int dnv_count=0;          Data.chroma = frame->quant;
1770          int s_count=0;          Data.qpel = pParam->m_quarterpel;
1771          const int64_t TRB = (int32_t)time_pp - (int32_t)time_bp;          Data.rounding = 0;
1772      const int64_t TRD = (int32_t)time_pp;  
1773            if((qimage = (uint8_t *) malloc(32 * pParam->edged_width)) == NULL)
1774                    return; // allocate some mem for qpel interpolated blocks
1775                                      // somehow this is dirty since I think we shouldn't use malloc outside
1776                                      // encoder_create() - so please fix me!
1777            Data.RefQ = qimage;
1778    
         // fprintf(stderr,"TRB = %lld  TRD = %lld  time_bp =%d time_pp =%d\n\n",TRB,TRD,time_bp,time_pp);  
1779          // note: i==horizontal, j==vertical          // note: i==horizontal, j==vertical
1780          for (j = 0; j < mb_height; j++) {          for (j = 0; j < pParam->mb_height; j++) {
1781    
1782                  f_predMV = zeroMV;      /* prediction is reset at left boundary */                  f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
                 b_predMV = zeroMV;  
1783    
1784                  for (i = 0; i < mb_width; i++) {                  for (i = 0; i < pParam->mb_width; i++) {
1785                          MACROBLOCK *mb = &frame->mbs[i + j * mb_width];                          MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
1786                          const MACROBLOCK *f_mb = &f_mbs[i + j * mb_width];                          const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
1787                          const MACROBLOCK *b_mb = &b_mbs[i + j * mb_width];  
1788    /* special case, if collocated block is SKIPed in P-VOP: encoding is forward (0,0), cpb=0 without further ado */
1789                          VECTOR directMV;                          if (b_reference->coding_type != S_VOP)
1790                          VECTOR deltaMV=zeroMV;                                  if (b_mb->mode == MODE_NOT_CODED) {
1791                                            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;  
1792                                  continue;                                  continue;
1793                          }                          }
 #endif  
1794    
1795                          dnv_sad16 = DIRECT_PENALTY;                          Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
1796                            pMB->quant = frame->quant;
1797    
1798                          if (b_mb->mode == MODE_INTER4V)  /* direct search comes first, because it (1) checks for SKIP-mode
1799                          {          and (2) sets very good predictions for forward and backward search */
1800                            skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
1801                                                                            b_ref, b_refH->y, b_refV->y, b_refHV->y,
1802                                                                            &frame->image,
1803                                                                            i, j,
1804                                                                            frame->motion_flags,
1805                                                                            TRB, TRD,
1806                                                                            pParam,
1807                                                                            pMB, b_mb,
1808                                                                            &best_sad,
1809                                                                            &Data);
1810    
1811                          /* 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++) {  
1812    
1813                                          directMV = b_mb->mvs[k];                          // forward search
1814                            SearchBF(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
1815                                                    &frame->image, i, j,
1816                                                    frame->motion_flags,
1817                                                    frame->fcode, pParam,
1818                                                    pMB, &f_predMV, &best_sad,
1819                                                    MODE_FORWARD, &Data);
1820    
1821                            // backward search
1822                            SearchBF(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
1823                                                    &frame->image, i, j,
1824                                                    frame->motion_flags,
1825                                                    frame->bcode, pParam,
1826                                                    pMB, &b_predMV, &best_sad,
1827                                                    MODE_BACKWARD, &Data);
1828    
1829                            // interpolate search comes last, because it uses data from forward and backward as prediction
1830                            SearchInterpolate(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,
1831                                                    b_ref->y, b_refH->y, b_refV->y, b_refHV->y,
1832                                                    &frame->image,
1833                                                    i, j,
1834                                                    frame->fcode, frame->bcode,
1835                                                    frame->motion_flags,
1836                                                    pParam,
1837                                                    &f_predMV, &b_predMV,
1838                                                    pMB, &best_sad,
1839                                                    &Data);
1840    
1841    // final skip decision
1842                            if ( (skip_sad < frame->quant * MAX_SAD00_FOR_SKIP*2)
1843                                            && ((100*best_sad)/(skip_sad+1) > FINAL_SKIP_THRESH) )
1844                                    SkipDecisionB(&frame->image, f_ref, b_ref, pMB,frame->quant, i, j, &Data);
1845    
1846                                          mb->mvs[k].x = (int32_t) ((TRB * directMV.x) / TRD + deltaMV.x);                          switch (pMB->mode) {
1847                      mb->b_mvs[k].x = (int32_t) ((deltaMV.x == 0)                                  case MODE_FORWARD:
1848                                                                                  ? ((TRB - TRD) * directMV.x) / TRD                                          f_count++;
1849                                              : mb->mvs[k].x - directMV.x);                                          if (Data.qpel) f_predMV = pMB->qmvs[0];
1850                      mb->mvs[k].y = (int32_t) ((TRB * directMV.y) / TRD + deltaMV.y);                                          else f_predMV = pMB->mvs[0];
1851                          mb->b_mvs[k].y = (int32_t) ((deltaMV.y == 0)                                          break;
1852                                                                                  ? ((TRB - TRD) * directMV.y) / TRD                                  case MODE_BACKWARD:
1853                                              : mb->mvs[k].y - directMV.y);                                          b_count++;
1854                                            if (Data.qpel) b_predMV = pMB->b_qmvs[0];
1855                                          dnv_sad16 +=                                          else b_predMV = pMB->b_mvs[0];
1856                                                  sad8bi(frame->image.y + 2*(i+(k&1))*8 + 2*(j+(k>>1))*8*edged_width,                                          break;
1857                                                    get_ref_mv(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,                                  case MODE_INTERPOLATE:
1858                                                                  2*(i+(k&1)), 2*(j+(k>>1)), 8, &mb->mvs[k], edged_width),                                          i_count++;
1859                                                    get_ref_mv(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,                                          if (Data.qpel) {
1860                                                                  2*(i+(k&1)), 2*(j+(k>>1)), 8, &mb->b_mvs[k], edged_width),                                                  f_predMV = pMB->qmvs[0];
1861                                                    edged_width);                                                  b_predMV = pMB->b_qmvs[0];
1862                                            } else {
1863                                                    f_predMV = pMB->mvs[0];
1864                                                    b_predMV = pMB->b_mvs[0];
1865                                            }
1866                                            break;
1867                                    case MODE_DIRECT:
1868                                    case MODE_DIRECT_NO4V:
1869                                            d_count++;
1870                                    default:
1871                                            break;
1872                                  }                                  }
1873                          }                          }
1874                          else          }
1875            free(qimage);
1876    }
1877    
1878    static __inline void
1879    MEanalyzeMB (   const uint8_t * const pRef,
1880                                    const uint8_t * const pCur,
1881                                    const int x,
1882                                    const int y,
1883                                    const MBParam * const pParam,
1884                                    MACROBLOCK * const pMBs,
1885                                    SearchData * const Data)
1886                          {                          {
                                 directMV = b_mb->mvs[0];  
1887    
1888                                  mb->mvs[0].x = (int32_t) ((TRB * directMV.x) / TRD + deltaMV.x);          int i, mask;
1889                  mb->b_mvs[0].x = (int32_t) ((deltaMV.x == 0)          VECTOR pmv[3];
1890                                                                  ? ((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);  
1891    
1892            for (i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;
1893    
1894              }          //median is only used as prediction. it doesn't have to be real
1895            if (x == 1 && y == 1) Data->predMV.x = Data->predMV.y = 0;
1896            else
1897                    if (x == 1) //left macroblock does not have any vector now
1898                            Data->predMV = (pMB - pParam->mb_width)->mvs[0]; // top instead of median
1899                    else if (y == 1) // top macroblock doesn't have it's vector
1900                            Data->predMV = (pMB - 1)->mvs[0]; // left instead of median
1901                            else Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); //else median
1902    
1903                          // forward search          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1904                          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);  
1905    
1906            Data->Cur = pCur + (x + y * pParam->edged_width) * 16;
1907            Data->Ref = pRef + (x + y * pParam->edged_width) * 16;
1908    
1909                          // backward search          pmv[1].x = EVEN(pMB->mvs[0].x);
1910                          b_sad16 = SEARCH16(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,          pmv[1].y = EVEN(pMB->mvs[0].y);
1911                                                  &frame->image, i, j,          pmv[2].x = EVEN(Data->predMV.x);
1912                                                  mb->b_mvs[0].x, mb->b_mvs[0].y,         /* start point b_directMV */          pmv[2].y = EVEN(Data->predMV.y);
1913                                                  b_predMV.x, b_predMV.y,                         /* center is b-prediction */          pmv[0].x = pmv[0].y = 0;
1914                                                  frame->motion_flags & (~(PMV_EARLYSTOP16|PMV_QUICKSTOP16)),  
1915                                                  frame->quant, frame->bcode, pParam,          CheckCandidate32I(0, 0, 255, &i, Data);
1916                                                  b_mbs, b_mbs,  
1917                                                  &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;  
                         }  
1918    
1919                          if (i_sad16 < best_sad) {                  if (!(mask = make_mask(pmv, 1)))
1920                                  best_sad = i_sad16;                          CheckCandidate32I(pmv[1].x, pmv[1].y, mask, &i, Data);
1921                                  mb->mode = MODE_INTERPOLATE;                  if (!(mask = make_mask(pmv, 2)))
1922                            CheckCandidate32I(pmv[2].x, pmv[2].y, mask, &i, Data);
1923    
1924                    if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP * 4) // diamond only if needed
1925                            DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, i);
1926    
1927                    for (i = 0; i < 4; i++) {
1928                            MACROBLOCK * MB = &pMBs[x + (i&1) + (y+(i>>1) * pParam->mb_width)];
1929                            MB->mvs[0] = MB->mvs[1] = MB->mvs[2] = MB->mvs[3] = Data->currentMV[i];
1930                            MB->mode = MODE_INTER;
1931                            MB->sad16 = Data->iMinSAD[i+1];
1932                    }
1933            }
1934                          }                          }
1935    
1936                          if (dnv_sad16 < best_sad) {  #define INTRA_BIAS              2500
1937    #define INTRA_THRESH    1500
1938    #define INTER_THRESH    1400
1939    
                                 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)  
1940    
1941                                                  This has to be replaced later by "real" direct mode, including delta  int
1942                                                  vector and (if needed) residue encoding  MEanalysis(     const IMAGE * const pRef,
1943                            FRAMEINFO * const Current,
1944                            MBParam * const pParam,
1945                            int maxIntra, //maximum number if non-I frames
1946                            int intraCount, //number of non-I frames after last I frame; 0 if we force P/B frame
1947                            int bCount) // number if B frames in a row
1948    {
1949            uint32_t x, y, intra = 0;
1950            int sSAD = 0;
1951            MACROBLOCK * const pMBs = Current->mbs;
1952            const IMAGE * const pCurrent = &Current->image;
1953            int IntraThresh = INTRA_THRESH, InterThresh = INTER_THRESH;
1954            const VECTOR zeroMV = {0,0};
1955    
1956            int32_t iMinSAD[5], temp[5];
1957            VECTOR currentMV[5];
1958            SearchData Data;
1959            Data.iEdgedWidth = pParam->edged_width;
1960            Data.currentMV = currentMV;
1961            Data.iMinSAD = iMinSAD;
1962            Data.iFcode = Current->fcode;
1963            Data.rrv = Current->global_flags & XVID_REDUCED;
1964            Data.temp = temp;
1965            CheckCandidate = CheckCandidate32I;
1966    
1967                                          */          if (intraCount < 10) // we're right after an I frame
1968                    IntraThresh += 4 * (intraCount - 10) * (intraCount - 10);
1969            else
1970                    if ( 5*(maxIntra - intraCount) < maxIntra) // we're close to maximum. 2 sec when max is 10 sec
1971                            IntraThresh -= (IntraThresh * (maxIntra - 5*(maxIntra - intraCount)))/maxIntra;
1972    
1973                                          directMV = b_mb->mvs[0];          InterThresh += 400 * (1 - bCount);
1974            if (InterThresh < 300) InterThresh = 300;
1975    
1976                                          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);  
1977    
1978                                          dnv_sad16 =          for (y = 1; y < pParam->mb_height-1; y+=2) {
1979                                                  sad16bi(frame->image.y + i * 16 + j * 16 * edged_width,                  for (x = 1; x < pParam->mb_width-1; x+=2) {
1980                                                    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);  
1981    
1982                                          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;  
1983    
1984  /*                                              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);
1985                                                          f_sad16,b_sad16,i_sad16,dnv_sad16);  
1986  */                                      }                          for (i = 0; i < 4; i++) {
1987                                    int dev;
1988                                    MACROBLOCK *pMB = &pMBs[x+(i&1) + y+(i>>1) * pParam->mb_width];
1989                                    if (pMB->sad16 > IntraThresh) {
1990                                            dev = dev16(pCurrent->y + (x + (i&1) + (y + (i>>1))* pParam->edged_width) * 16,
1991                                                                              pParam->edged_width);
1992                                            if (dev + IntraThresh < pMB->sad16) {
1993                                                    pMB->mode = MODE_INTRA;
1994                                                    if (++intra > (pParam->mb_height-2)*(pParam->mb_width-2)/2) return I_VOP;
1995                                  }                                  }
1996                                  else                                  }
1997                                  {                                  sSAD += pMB->sad16;
                                         best_sad = dnv_sad16;  
                                         mb->mode = MODE_DIRECT_NONE_MV;  
1998                                  }                                  }
1999                          }                          }
2000            }
2001            sSAD /= (pParam->mb_height-2)*(pParam->mb_width-2);
2002            if (sSAD > IntraThresh + INTRA_BIAS ) return I_VOP;
2003            if (sSAD > InterThresh ) return P_VOP;
2004            emms();
2005            return B_VOP;
2006    
2007    }
2008    
2009                          switch (mb->mode)  static void
2010    CheckGMC(int x, int y, const int dir, int * iDirection,
2011                    const MACROBLOCK * const pMBs, uint32_t * bestcount, VECTOR * GMC,
2012                    const MBParam * const pParam)
2013                          {                          {
2014                                  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];  
2015    
2016                                          break;          for (my = 1; my < pParam->mb_height-1; my++)
2017                                  case MODE_INTERPOLATE:                  for (mx = 1; mx < pParam->mb_width-1; mx++) {
2018                                          i_count++;                          VECTOR mv;
2019                                          f_predMV = mb->mvs[0];                          const MACROBLOCK *pMB = &pMBs[mx + my * pParam->mb_width];
2020                                          b_predMV = mb->b_mvs[0];                          if (pMB->mode == MODE_INTRA || pMB->mode == MODE_NOT_CODED) continue;
2021                                          break;                          mv = pMB->mvs[0];
2022                                  case MODE_DIRECT:                          a = ABS(mv.x - x) + ABS(mv.y - y);
2023                                          d_count++; break;                          if (a < 6) count += 6 - a;
2024                                  case MODE_DIRECT_NONE_MV:                  }
2025                                          dnv_count++; break;  
2026                                  default:          if (count > *bestcount) {
2027                                          s_count++; break;                  *bestcount = count;
2028                    *iDirection = dir;
2029                    GMC->x = x; GMC->y = y;
2030                          }                          }
2031    }
2032    
2033    
2034    static VECTOR
2035    GlobalMotionEst(const MACROBLOCK * const pMBs, const MBParam * const pParam, const uint32_t iFcode)
2036    {
2037    
2038            uint32_t count, bestcount = 0;
2039            int x, y;
2040            VECTOR gmc = {0,0};
2041            int step, min_x, max_x, min_y, max_y;
2042            uint32_t mx, my;
2043            int iDirection, bDirection;
2044    
2045            min_x = min_y = -32<<iFcode;
2046            max_x = max_y = 32<<iFcode;
2047    
2048    //step1: let's find a rough camera panning
2049            for (step = 32; step >= 2; step /= 2) {
2050                    bestcount = 0;
2051                    for (y = min_y; y <= max_y; y += step)
2052                            for (x = min_x ; x <= max_x; x += step) {
2053                                    count = 0;
2054                                    //for all macroblocks
2055                                    for (my = 1; my < pParam->mb_height-1; my++)
2056                                            for (mx = 1; mx < pParam->mb_width-1; mx++) {
2057                                                    const MACROBLOCK *pMB = &pMBs[mx + my * pParam->mb_width];
2058                                                    VECTOR mv;
2059    
2060                                                    if (pMB->mode == MODE_INTRA || pMB->mode == MODE_NOT_CODED)
2061                                                            continue;
2062    
2063                                                    mv = pMB->mvs[0];
2064                                                    if ( ABS(mv.x - x) <= step && ABS(mv.y - y) <= step )   /* GMC translation is always halfpel-res */
2065                                                            count++;
2066                                            }
2067                                    if (count >= bestcount) { bestcount = count; gmc.x = x; gmc.y = y; }
2068                  }                  }
2069                    min_x = gmc.x - step;
2070                    max_x = gmc.x + step;
2071                    min_y = gmc.y - step;
2072                    max_y = gmc.y + step;
2073    
2074          }          }
2075    
2076  #ifdef _DEBUG_BFRAME_STAT          if (bestcount < (pParam->mb_height-2)*(pParam->mb_width-2)/10)
2077          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
2078                                  f_count,b_count,i_count,dnv_count,d_count,s_count);  
2079  #endif  // step2: let's refine camera panning using gradiend-descent approach.
2080    // TODO: more warping points may be evaluated here (like in interpolate mode search - two vectors in one diamond)
2081            bestcount = 0;
2082            CheckGMC(gmc.x, gmc.y, 255, &iDirection, pMBs, &bestcount, &gmc, pParam);
2083            do {
2084                    x = gmc.x; y = gmc.y;
2085                    bDirection = iDirection; iDirection = 0;
2086                    if (bDirection & 1) CheckGMC(x - 1, y, 1+4+8, &iDirection, pMBs, &bestcount, &gmc, pParam);
2087                    if (bDirection & 2) CheckGMC(x + 1, y, 2+4+8, &iDirection, pMBs, &bestcount, &gmc, pParam);
2088                    if (bDirection & 4) CheckGMC(x, y - 1, 1+2+4, &iDirection, pMBs, &bestcount, &gmc, pParam);
2089                    if (bDirection & 8) CheckGMC(x, y + 1, 1+2+8, &iDirection, pMBs, &bestcount, &gmc, pParam);
2090    
2091            } while (iDirection);
2092    
2093            if (pParam->m_quarterpel) {
2094                    gmc.x *= 2;
2095                    gmc.y *= 2;     /* we store the halfpel value as pseudo-qpel to make comparison easier */
2096            }
2097    
2098            return gmc;
2099  }  }

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

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