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

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

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