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

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

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