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

Legend:
Removed from v.326  
changed lines
  Added in v.704

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