[cvs] / xvidcore / src / motion / motion_est.c Repository:
ViewVC logotype

Diff of /xvidcore/src/motion/motion_est.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.1.44  
changed lines
  Added in v.1.44.2.40

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