[svn] / branches / dev-api-3 / xvidcore / src / motion / motion_est.c Repository:
ViewVC logotype

Diff of /branches/dev-api-3/xvidcore/src/motion/motion_est.c

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

revision 530, Mon Sep 23 20:36:02 2002 UTC revision 819, Sat Feb 8 03:49:47 2003 UTC
# Line 31  Line 31 
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    #include <math.h>       // lrint
36    
37  #include "../encoder.h"  #include "../encoder.h"
38  #include "../utils/mbfunctions.h"  #include "../utils/mbfunctions.h"
39  #include "../prediction/mbprediction.h"  #include "../prediction/mbprediction.h"
40  #include "../global.h"  #include "../global.h"
41  #include "../utils/timer.h"  #include "../utils/timer.h"
42    #include "../image/interpolate8x8.h"
43  #include "motion_est.h"  #include "motion_est.h"
44  #include "motion.h"  #include "motion.h"
45  #include "sad.h"  #include "sad.h"
46    #include "../utils/emms.h"
47    
48  #define INITIAL_SKIP_THRESH     (10)  #define INITIAL_SKIP_THRESH     (10)
49  #define FINAL_SKIP_THRESH       (50)  #define FINAL_SKIP_THRESH       (50)
50  #define MAX_SAD00_FOR_SKIP      (20)  #define MAX_SAD00_FOR_SKIP      (20)
51  #define MAX_CHROMA_SAD_FOR_SKIP (18)  #define MAX_CHROMA_SAD_FOR_SKIP (22)
 #define SKIP_THRESH_B (10)  
52    
53  #define CHECK_CANDIDATE(X,Y,D) { \  #define CHECK_CANDIDATE(X,Y,D) { CheckCandidate((X),(Y), (D), &iDirection, data ); }
 (*CheckCandidate)((const int)(X),(const int)(Y), (D), &iDirection, data ); }  
54    
55  #define iDiamondSize 2  static __inline uint32_t
56    d_mv_bits(int x, int y, const VECTOR pred, const uint32_t iFcode, const int qpel, const int rrv)
 //FILE * debug;  
   
 static __inline int  
 d_mv_bits(int x, int y, const uint32_t iFcode)  
57  {  {
58          int xb, yb;          int xb, yb;
59            x = qpel ? x<<1 : x;
60            y = qpel ? y<<1 : y;
61            if (rrv) { x = RRV_MV_SCALEDOWN(x); y = RRV_MV_SCALEDOWN(y); }
62    
63          if (x == 0) xb = 1;          x -= pred.x;
64          else {          y -= pred.y;
65                  if (x < 0) x = -x;  
66            if (x) {
67                    x = ABS(x);
68                  x += (1 << (iFcode - 1)) - 1;                  x += (1 << (iFcode - 1)) - 1;
69                  x >>= (iFcode - 1);                  x >>= (iFcode - 1);
70                  if (x > 32) x = 32;                  if (x > 32) x = 32;
71                  xb = mvtab[x] + iFcode;                  xb = mvtab[x] + iFcode;
72          }          } else xb = 1;
73    
74          if (y == 0) yb = 1;          if (y) {
75          else {                  y = ABS(y);
                 if (y < 0) y = -y;  
76                  y += (1 << (iFcode - 1)) - 1;                  y += (1 << (iFcode - 1)) - 1;
77                  y >>= (iFcode - 1);                  y >>= (iFcode - 1);
78                  if (y > 32) y = 32;                  if (y > 32) y = 32;
79                  yb = mvtab[y] + iFcode;                  yb = mvtab[y] + iFcode;
80          }          } else yb = 1;
81          return xb + yb;          return xb + yb;
82  }  }
83    
84  /* CHACK_CANDIATE FUNCTIONS START */  static int32_t ChromaSAD2(int fx, int fy, int bx, int by, const SearchData * const data)
85    {
86            int sad;
87            const uint32_t stride = data->iEdgedWidth/2;
88            uint8_t * f_refu = data->RefQ,
89                    * f_refv = data->RefQ + 8,
90                    * b_refu = data->RefQ + 16,
91                    * b_refv = data->RefQ + 24;
92    
93            switch (((fx & 1) << 1) | (fy & 1))     {
94                    case 0:
95                            fx = fx / 2; fy = fy / 2;
96                            f_refu = (uint8_t*)data->RefCU + fy * stride + fx, stride;
97                            f_refv = (uint8_t*)data->RefCV + fy * stride + fx, stride;
98                            break;
99                    case 1:
100                            fx = fx / 2; fy = (fy - 1) / 2;
101                            interpolate8x8_halfpel_v(f_refu, data->RefCU + fy * stride + fx, stride, data->rounding);
102                            interpolate8x8_halfpel_v(f_refv, data->RefCV + fy * stride + fx, stride, data->rounding);
103                            break;
104                    case 2:
105                            fx = (fx - 1) / 2; fy = fy / 2;
106                            interpolate8x8_halfpel_h(f_refu, data->RefCU + fy * stride + fx, stride, data->rounding);
107                            interpolate8x8_halfpel_h(f_refv, data->RefCV + fy * stride + fx, stride, data->rounding);
108                            break;
109                    default:
110                            fx = (fx - 1) / 2; fy = (fy - 1) / 2;
111                            interpolate8x8_halfpel_hv(f_refu, data->RefCU + fy * stride + fx, stride, data->rounding);
112                            interpolate8x8_halfpel_hv(f_refv, data->RefCV + fy * stride + fx, stride, data->rounding);
113                            break;
114            }
115    
116            switch (((bx & 1) << 1) | (by & 1))     {
117                    case 0:
118                            bx = bx / 2; by = by / 2;
119                            b_refu = (uint8_t*)data->b_RefCU + by * stride + bx, stride;
120                            b_refv = (uint8_t*)data->b_RefCV + by * stride + bx, stride;
121                            break;
122                    case 1:
123                            bx = bx / 2; by = (by - 1) / 2;
124                            interpolate8x8_halfpel_v(b_refu, data->b_RefCU + by * stride + bx, stride, data->rounding);
125                            interpolate8x8_halfpel_v(b_refv, data->b_RefCV + by * stride + bx, stride, data->rounding);
126                            break;
127                    case 2:
128                            bx = (bx - 1) / 2; by = by / 2;
129                            interpolate8x8_halfpel_h(b_refu, data->b_RefCU + by * stride + bx, stride, data->rounding);
130                            interpolate8x8_halfpel_h(b_refv, data->b_RefCV + by * stride + bx, stride, data->rounding);
131                            break;
132                    default:
133                            bx = (bx - 1) / 2; by = (by - 1) / 2;
134                            interpolate8x8_halfpel_hv(b_refu, data->b_RefCU + by * stride + bx, stride, data->rounding);
135                            interpolate8x8_halfpel_hv(b_refv, data->b_RefCV + by * stride + bx, stride, data->rounding);
136                            break;
137            }
138    
139            sad = sad8bi(data->CurU, b_refu, f_refu, stride);
140            sad += sad8bi(data->CurV, b_refv, f_refv, stride);
141    
142            return sad;
143    }
144    
145    
146    static int32_t
147    ChromaSAD(int dx, int dy, const SearchData * const data)
148    {
149            int sad;
150            const uint32_t stride = data->iEdgedWidth/2;
151    
152            if (dx == data->temp[5] && dy == data->temp[6]) return data->temp[7]; //it has been checked recently
153            data->temp[5] = dx; data->temp[6] = dy; // backup
154    
155            switch (((dx & 1) << 1) | (dy & 1))     {
156                    case 0:
157                            dx = dx / 2; dy = dy / 2;
158                            sad = sad8(data->CurU, data->RefCU + dy * stride + dx, stride);
159                            sad += sad8(data->CurV, data->RefCV + dy * stride + dx, stride);
160                            break;
161                    case 1:
162                            dx = dx / 2; dy = (dy - 1) / 2;
163                            sad = sad8bi(data->CurU, data->RefCU + dy * stride + dx, data->RefCU + (dy+1) * stride + dx, stride);
164                            sad += sad8bi(data->CurV, data->RefCV + dy * stride + dx, data->RefCV + (dy+1) * stride + dx, stride);
165                            break;
166                    case 2:
167                            dx = (dx - 1) / 2; dy = dy / 2;
168                            sad = sad8bi(data->CurU, data->RefCU + dy * stride + dx, data->RefCU + dy * stride + dx+1, stride);
169                            sad += sad8bi(data->CurV, data->RefCV + dy * stride + dx, data->RefCV + dy * stride + dx+1, stride);
170                            break;
171                    default:
172                            dx = (dx - 1) / 2; dy = (dy - 1) / 2;
173                            interpolate8x8_halfpel_hv(data->RefQ, data->RefCU + dy * stride + dx, stride, data->rounding);
174                            sad = sad8(data->CurU, data->RefQ, stride);
175    
176                            interpolate8x8_halfpel_hv(data->RefQ, data->RefCV + dy * stride + dx, stride, data->rounding);
177                            sad += sad8(data->CurV, data->RefQ, stride);
178                            break;
179            }
180            data->temp[7] = sad; //backup, part 2
181            return sad;
182    }
183    
184    static __inline const uint8_t *
185    GetReferenceB(const int x, const int y, const uint32_t dir, const SearchData * const data)
186    {
187    //      dir : 0 = forward, 1 = backward
188            switch ( (dir << 2) | ((x&1)<<1) | (y&1) ) {
189                    case 0 : return data->Ref + x/2 + (y/2)*(data->iEdgedWidth);
190                    case 1 : return data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth);
191                    case 2 : return data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth);
192                    case 3 : return data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth);
193                    case 4 : return data->bRef + x/2 + (y/2)*(data->iEdgedWidth);
194                    case 5 : return data->bRefV + x/2 + ((y-1)/2)*(data->iEdgedWidth);
195                    case 6 : return data->bRefH + (x-1)/2 + (y/2)*(data->iEdgedWidth);
196                    default : return data->bRefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth);
197            }
198    }
199    
200    // this is a simpler copy of GetReferenceB, but as it's __inline anyway, we can keep the two separate
201    static __inline const uint8_t *
202    GetReference(const int x, const int y, const SearchData * const data)
203    {
204            switch ( ((x&1)<<1) | (y&1) ) {
205                    case 0 : return data->Ref + x/2 + (y/2)*(data->iEdgedWidth);
206                    case 3 : return data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth);
207                    case 1 : return data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth);
208                    default : return data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth);      //case 2
209            }
210    }
211    
212    static uint8_t *
213    Interpolate8x8qpel(const int x, const int y, const uint32_t block, const uint32_t dir, const SearchData * const data)
214    {
215    // create or find a qpel-precision reference picture; return pointer to it
216            uint8_t * Reference = data->RefQ + 16*dir;
217            const uint32_t iEdgedWidth = data->iEdgedWidth;
218            const uint32_t rounding = data->rounding;
219            const int halfpel_x = x/2;
220            const int halfpel_y = y/2;
221            const uint8_t *ref1, *ref2, *ref3, *ref4;
222    
223            ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
224            ref1 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
225            switch( ((x&1)<<1) + (y&1) ) {
226            case 0: // pure halfpel position
227                    return (uint8_t *) ref1;
228                    break;
229    
230            case 1: // x halfpel, y qpel - top or bottom during qpel refinement
231                    ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
232                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
233                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
234                    break;
235    
236            case 2: // x qpel, y halfpel - left or right during qpel refinement
237                    ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
238                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
239                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
240                    break;
241    
242            default: // x and y in qpel resolution - the "corners" (top left/right and
243                             // bottom left/right) during qpel refinement
244                    ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
245                    ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
246                    ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);
247                    ref2 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
248                    ref3 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
249                    ref4 += 8 * (block&1) + 8 * (block>>1) * iEdgedWidth;
250                    interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
251                    break;
252            }
253            return Reference;
254    }
255    
256    static uint8_t *
257    Interpolate16x16qpel(const int x, const int y, const uint32_t dir, const SearchData * const data)
258    {
259    // create or find a qpel-precision reference picture; return pointer to it
260            uint8_t * Reference = data->RefQ + 16*dir;
261            const uint32_t iEdgedWidth = data->iEdgedWidth;
262            const uint32_t rounding = data->rounding;
263            const int halfpel_x = x/2;
264            const int halfpel_y = y/2;
265            const uint8_t *ref1, *ref2, *ref3, *ref4;
266    
267            ref1 = GetReferenceB(halfpel_x, halfpel_y, dir, data);
268            switch( ((x&1)<<1) + (y&1) ) {
269            case 3: // x and y in qpel resolution - the "corners" (top left/right and
270                             // bottom left/right) during qpel refinement
271                    ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
272                    ref3 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
273                    ref4 = GetReferenceB(x - halfpel_x, y - halfpel_y, dir, data);
274                    interpolate8x8_avg4(Reference, ref1, ref2, ref3, ref4, iEdgedWidth, rounding);
275                    interpolate8x8_avg4(Reference+8, ref1+8, ref2+8, ref3+8, ref4+8, iEdgedWidth, rounding);
276                    interpolate8x8_avg4(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, ref3+8*iEdgedWidth, ref4+8*iEdgedWidth, iEdgedWidth, rounding);
277                    interpolate8x8_avg4(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, ref3+8*iEdgedWidth+8, ref4+8*iEdgedWidth+8, iEdgedWidth, rounding);
278                    break;
279    
280            case 1: // x halfpel, y qpel - top or bottom during qpel refinement
281                    ref2 = GetReferenceB(halfpel_x, y - halfpel_y, dir, data);
282                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
283                    interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
284                    interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
285                    interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
286                    break;
287    
288            case 2: // x qpel, y halfpel - left or right during qpel refinement
289                    ref2 = GetReferenceB(x - halfpel_x, halfpel_y, dir, data);
290                    interpolate8x8_avg2(Reference, ref1, ref2, iEdgedWidth, rounding, 8);
291                    interpolate8x8_avg2(Reference+8, ref1+8, ref2+8, iEdgedWidth, rounding, 8);
292                    interpolate8x8_avg2(Reference+8*iEdgedWidth, ref1+8*iEdgedWidth, ref2+8*iEdgedWidth, iEdgedWidth, rounding, 8);
293                    interpolate8x8_avg2(Reference+8*iEdgedWidth+8, ref1+8*iEdgedWidth+8, ref2+8*iEdgedWidth+8, iEdgedWidth, rounding, 8);
294                    break;
295    
296            case 0: // pure halfpel position
297                    return (uint8_t *) ref1;
298            }
299            return Reference;
300    }
301    
302    /* CHECK_CANDIATE FUNCTIONS START */
303    
304  static void  static void
305  CheckCandidate16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)  CheckCandidate16(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
306  {  {
307          int32_t * const sad = data->temp;          int xc, yc;
 //      static int32_t sad[5];  
         int t;  
308          const uint8_t * Reference;          const uint8_t * Reference;
309            VECTOR * current;
310            int32_t sad; uint32_t t;
311    
312          if (( x > data->max_dx) || ( x < data->min_dx)          if (( x > data->max_dx) || ( x < data->min_dx)
313                  || ( y > data->max_dy) || (y < data->min_dy)) return;                  || ( y > data->max_dy) || (y < data->min_dy)) return;
314    
315          switch ( ((x&1)<<1) + (y&1) ) {          if (!data->qpel_precision) {
316                  case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;                  Reference = GetReference(x, y, data);
317                  case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;                  current = data->currentMV;
318                  case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;                  xc = x; yc = y;
319                  default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;          } else { // x and y are in 1/4 precision
320                    Reference = Interpolate16x16qpel(x, y, 0, data);
321                    xc = x/2; yc = y/2; //for chroma sad
322                    current = data->currentQMV;
323            }
324    
325            sad = sad16v(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
326            t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
327    
328            sad += (data->lambda16 * t * sad)>>10;
329            data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;
330    
331            if (data->chroma) sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
332                                                                                                            (yc >> 1) + roundtab_79[yc & 0x3], data);
333    
334            if (sad < data->iMinSAD[0]) {
335                    data->iMinSAD[0] = sad;
336                    current[0].x = x; current[0].y = y;
337                    *dir = Direction;
338          }          }
339    
340          data->temp[0] = sad16v(data->Cur, Reference, data->iEdgedWidth, sad+1);          if (data->temp[1] < data->iMinSAD[1]) {
341                    data->iMinSAD[1] = data->temp[1]; current[1].x = x; current[1].y = y; }
342            if (data->temp[2] < data->iMinSAD[2]) {
343                    data->iMinSAD[2] = data->temp[2]; current[2].x = x; current[2].y = y; }
344            if (data->temp[3] < data->iMinSAD[3]) {
345                    data->iMinSAD[3] = data->temp[3]; current[3].x = x; current[3].y = y; }
346            if (data->temp[4] < data->iMinSAD[4]) {
347                    data->iMinSAD[4] = data->temp[4]; current[4].x = x; current[4].y = y; }
348    
349    }
350    
351    static void
352    CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
353    {
354            int32_t sad; uint32_t t;
355            const uint8_t * Reference;
356    
357            if ( (x > data->max_dx) || (x < data->min_dx)
358                    || (y > data->max_dy) || (y < data->min_dy) ) return;
359    
360          t = d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);          if (!data->qpel_precision) Reference = GetReference(x, y, data);
361          data->temp[0] += lambda_vec16[data->iQuant] * t;          else Reference = Interpolate8x8qpel(x, y, 0, 0, data);
362          data->temp[1] += lambda_vec8[data->iQuant] * t;  
363            sad = sad8(data->Cur, Reference, data->iEdgedWidth);
364            t = d_mv_bits(x, y, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0);
365    
366            sad += (data->lambda8 * t * (sad+NEIGH_8X8_BIAS))>>10;
367    
368            if (sad < *(data->iMinSAD)) {
369                    *(data->iMinSAD) = sad;
370                    data->currentMV->x = x; data->currentMV->y = y;
371                    *dir = Direction;
372            }
373    }
374    
375    
376    static void
377    CheckCandidate32(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
378    {
379            uint32_t t;
380            const uint8_t * Reference;
381    
382            if ( (!(x&1) && x !=0) || (!(y&1) && y !=0) || //non-zero integer value
383                    (x > data->max_dx) || (x < data->min_dx)
384                    || (y > data->max_dy) || (y < data->min_dy) ) return;
385    
386            Reference = GetReference(x, y, data);
387            t = d_mv_bits(x, y, data->predMV, data->iFcode, 0, 1);
388    
389            data->temp[0] = sad32v_c(data->Cur, Reference, data->iEdgedWidth, data->temp + 1);
390    
391            data->temp[0] += (data->lambda16 * t * data->temp[0]) >> 10;
392            data->temp[1] += (data->lambda8 * t * (data->temp[1] + NEIGH_8X8_BIAS))>>10;
393    
394          if (data->temp[0] < data->iMinSAD[0]) {          if (data->temp[0] < data->iMinSAD[0]) {
395                  data->iMinSAD[0] = data->temp[0];                  data->iMinSAD[0] = data->temp[0];
# Line 118  Line 404 
404                  data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }                  data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
405          if (data->temp[4] < data->iMinSAD[4]) {          if (data->temp[4] < data->iMinSAD[4]) {
406                  data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }                  data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
   
407  }  }
408    
409  static void  static void
410  CheckCandidate16no4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)  CheckCandidate16no4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
411  {  {
412          int32_t sad;          int32_t sad, xc, yc;
413          const uint8_t * Reference;          const uint8_t * Reference;
414            uint32_t t;
415            VECTOR * current;
416    
417          if (( x > data->max_dx) || ( x < data->min_dx)          if ( (x > data->max_dx) | ( x < data->min_dx)
418                  || ( y > data->max_dy) || (y < data->min_dy)) return;                  | (y > data->max_dy) | (y < data->min_dy) ) return;
419    
420          switch ( ((x&1)<<1) + (y&1) )          if (data->rrv && (!(x&1) && x !=0) | (!(y&1) && y !=0) ) return; //non-zero even value
421          {  
422                  case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;          if (data->qpel_precision) { // x and y are in 1/4 precision
423                  case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;                  Reference = Interpolate16x16qpel(x, y, 0, data);
424                  case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;                  current = data->currentQMV;
425                  default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;                  xc = x/2; yc = y/2;
426            } else {
427                    Reference = GetReference(x, y, data);
428                    current = data->currentMV;
429                    xc = x; yc = y;
430          }          }
431            t = d_mv_bits(x, y, data->predMV, data->iFcode,
432                                            data->qpel^data->qpel_precision, data->rrv);
433    
434            sad = sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);
435            sad += (data->lambda16 * t * sad)>>10;
436    
437            if (data->chroma) sad += ChromaSAD((xc >> 1) + roundtab_79[xc & 0x3],
438                                                                                    (yc >> 1) + roundtab_79[yc & 0x3], data);
439    
         sad = lambda_vec16[data->iQuant] *  
                         d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);  
         sad += sad16(data->Cur, Reference, data->iEdgedWidth, 256*4096);  
440    
441          if (sad < *(data->iMinSAD)) {          if (sad < *(data->iMinSAD)) {
442                  *(data->iMinSAD) = sad;                  *(data->iMinSAD) = sad;
443                  data->currentMV[0].x = x; data->currentMV[0].y = y;                  current->x = x; current->y = y;
444                  *dir = Direction; }                  *dir = Direction;
445            }
446  }  }
447    
448  static void  static void
449  CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)  CheckCandidate32I(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
450  {  {
451    // maximum speed - for P/B/I decision
452          int32_t sad;          int32_t sad;
         const int xb = data->currentMV[1].x;  
         const int yb = data->currentMV[1].y;  
         const uint8_t *ReferenceF, *ReferenceB;  
453    
454          if (( xf > data->max_dx) || ( xf < data->min_dx)          if ( (x > data->max_dx) || (x < data->min_dx)
455                  || ( yf > data->max_dy) || (yf < data->min_dy)) return;                  || (y > data->max_dy) || (y < data->min_dy) ) return;
456    
457          switch ( ((xf&1)<<1) + (yf&1) ) {          sad = sad32v_c(data->Cur, data->Ref + x/2 + (y/2)*(data->iEdgedWidth),
458                  case 0 : ReferenceF = data->Ref + xf/2 + (yf/2)*(data->iEdgedWidth); break;                                                          data->iEdgedWidth, data->temp+1);
459                  case 1 : ReferenceF = data->RefV + xf/2 + ((yf-1)/2)*(data->iEdgedWidth); break;  
460                  case 2 : ReferenceF = data->RefH + (xf-1)/2 + (yf/2)*(data->iEdgedWidth); break;          if (sad < *(data->iMinSAD)) {
461                  default : ReferenceF = data->RefHV + (xf-1)/2 + ((yf-1)/2)*(data->iEdgedWidth); break;                  *(data->iMinSAD) = sad;
462                    data->currentMV[0].x = x; data->currentMV[0].y = y;
463                    *dir = Direction;
464          }          }
465            if (data->temp[1] < data->iMinSAD[1]) {
466                    data->iMinSAD[1] = data->temp[1]; data->currentMV[1].x = x; data->currentMV[1].y = y; }
467            if (data->temp[2] < data->iMinSAD[2]) {
468                    data->iMinSAD[2] = data->temp[2]; data->currentMV[2].x = x; data->currentMV[2].y = y; }
469            if (data->temp[3] < data->iMinSAD[3]) {
470                    data->iMinSAD[3] = data->temp[3]; data->currentMV[3].x = x; data->currentMV[3].y = y; }
471            if (data->temp[4] < data->iMinSAD[4]) {
472                    data->iMinSAD[4] = data->temp[4]; data->currentMV[4].x = x; data->currentMV[4].y = y; }
473    
         switch ( ((xb&1)<<1) + (yb&1) ) {  
                 case 0 : ReferenceB = data->bRef + xb/2 + (yb/2)*(data->iEdgedWidth); break;  
                 case 1 : ReferenceB = data->bRefV + xb/2 + ((yb-1)/2)*(data->iEdgedWidth); break;  
                 case 2 : ReferenceB = data->bRefH + (xb-1)/2 + (yb/2)*(data->iEdgedWidth); break;  
                 default : ReferenceB = data->bRefHV + (xb-1)/2 + ((yb-1)/2)*(data->iEdgedWidth); break;  
474          }          }
475    
476          sad = lambda_vec16[data->iQuant] *  static void
477                          ( d_mv_bits(xf - data->predMV.x, yf - data->predMV.y, data->iFcode) +  CheckCandidateInt(const int xf, const int yf, const int Direction, int * const dir, const SearchData * const data)
478                            d_mv_bits(xb - data->bpredMV.x, yb - data->bpredMV.y, data->iFcode) );  {
479            int32_t sad, xb, yb, xcf, ycf, xcb, ycb;
480            uint32_t t;
481            const uint8_t *ReferenceF, *ReferenceB;
482            VECTOR *current;
483    
484            if ( (xf > data->max_dx) | (xf < data->min_dx)
485                    | (yf > data->max_dy) | (yf < data->min_dy) ) return;
486    
487          sad += sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);          if (!data->qpel_precision) {
488                    ReferenceF = GetReference(xf, yf, data);
489                    xb = data->currentMV[1].x; yb = data->currentMV[1].y;
490                    ReferenceB = GetReferenceB(xb, yb, 1, data);
491                    current = data->currentMV;
492                    xcf = xf; ycf = yf;
493                    xcb = xb; ycb = yb;
494            } else {
495                    ReferenceF = Interpolate16x16qpel(xf, yf, 0, data);
496                    xb = data->currentQMV[1].x; yb = data->currentQMV[1].y;
497                    current = data->currentQMV;
498                    ReferenceB = Interpolate16x16qpel(xb, yb, 1, data);
499                    xcf = xf/2; ycf = yf/2;
500                    xcb = xb/2; ycb = yb/2;
501            }
502    
503            t = d_mv_bits(xf, yf, data->predMV, data->iFcode, data->qpel^data->qpel_precision, 0)
504                     + d_mv_bits(xb, yb, data->bpredMV, data->iFcode, data->qpel^data->qpel_precision, 0);
505    
506            sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
507            sad += (data->lambda16 * t * sad)>>10;
508    
509            if (data->chroma) sad += ChromaSAD2((xcf >> 1) + roundtab_79[xcf & 0x3],
510                                                                                    (ycf >> 1) + roundtab_79[ycf & 0x3],
511                                                                                    (xcb >> 1) + roundtab_79[xcb & 0x3],
512                                                                                    (ycb >> 1) + roundtab_79[ycb & 0x3], data);
513    
514          if (sad < *(data->iMinSAD)) {          if (sad < *(data->iMinSAD)) {
515                  *(data->iMinSAD) = sad;                  *(data->iMinSAD) = sad;
516                  data->currentMV->x = xf; data->currentMV->y = yf;                  current->x = xf; current->y = yf;
517                  *dir = Direction; }                  *dir = Direction;
518            }
519  }  }
520    
521  static void  static void
522  CheckCandidateDirect(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)  CheckCandidateDirect(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
523  {  {
524          int32_t sad;          int32_t sad = 0, xcf = 0, ycf = 0, xcb = 0, ycb = 0;
525          int k;          uint32_t k;
526          const uint8_t *ReferenceF;          const uint8_t *ReferenceF;
527          const uint8_t *ReferenceB;          const uint8_t *ReferenceB;
528          VECTOR mvs, b_mvs;          VECTOR mvs, b_mvs;
529    
530          if (( x > 31) || ( x < -32) || ( y > 31) || (y < -32)) return;          if (( x > 31) | ( x < -32) | ( y > 31) | (y < -32)) return;
   
         sad = lambda_vec16[data->iQuant] * d_mv_bits(x, y, 1);  
531    
532          for (k = 0; k < 4; k++) {          for (k = 0; k < 4; k++) {
533                  mvs.x = data->directmvF[k].x + x;                  mvs.x = data->directmvF[k].x + x;
# Line 209  Line 540 
540                          data->directmvB[k].y                          data->directmvB[k].y
541                          : mvs.y - data->referencemv[k].y);                          : mvs.y - data->referencemv[k].y);
542    
543                  if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )                  if ( (mvs.x > data->max_dx) | (mvs.x < data->min_dx)
544                          || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )                          | (mvs.y > data->max_dy) | (mvs.y < data->min_dy)
545                          || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )                          | (b_mvs.x > data->max_dx) | (b_mvs.x < data->min_dx)
546                          || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;                          | (b_mvs.y > data->max_dy) | (b_mvs.y < data->min_dy) ) return;
547    
548                  switch ( ((mvs.x&1)<<1) + (mvs.y&1) ) {                  if (data->qpel) {
549                          case 0 : ReferenceF = data->Ref + mvs.x/2 + (mvs.y/2)*(data->iEdgedWidth); break;                          xcf += mvs.x/2; ycf += mvs.y/2;
550                          case 1 : ReferenceF = data->RefV + mvs.x/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;                          xcb += b_mvs.x/2; ycb += b_mvs.y/2;
551                          case 2 : ReferenceF = data->RefH + (mvs.x-1)/2 + (mvs.y/2)*(data->iEdgedWidth); break;                  } else {
552                          default : ReferenceF = data->RefHV + (mvs.x-1)/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;                          xcf += mvs.x; ycf += mvs.y;
553                  }                          xcb += b_mvs.x; ycb += b_mvs.y;
554                            mvs.x *= 2; mvs.y *= 2; //we move to qpel precision anyway
555                  switch ( ((b_mvs.x&1)<<1) + (b_mvs.y&1) ) {                          b_mvs.x *= 2; b_mvs.y *= 2;
                         case 0 : ReferenceB = data->bRef + b_mvs.x/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;  
                         case 1 : ReferenceB = data->bRefV + b_mvs.x/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;  
                         case 2 : ReferenceB = data->bRefH + (b_mvs.x-1)/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;  
                         default : ReferenceB = data->bRefHV + (b_mvs.x-1)/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;  
556                  }                  }
557    
558                    ReferenceF = Interpolate8x8qpel(mvs.x, mvs.y, k, 0, data);
559                    ReferenceB = Interpolate8x8qpel(b_mvs.x, b_mvs.y, k, 1, data);
560    
561                  sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),                  sad += sad8bi(data->Cur + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),
562                                                  ReferenceF + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),                                                  ReferenceF, ReferenceB, data->iEdgedWidth);
                                                 ReferenceB + 8*(k&1) + 8*(k>>1)*(data->iEdgedWidth),  
                                                 data->iEdgedWidth);  
563                  if (sad > *(data->iMinSAD)) return;                  if (sad > *(data->iMinSAD)) return;
564          }          }
565    
566            sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;
567    
568            if (data->chroma) sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],
569                                                                                    (ycf >> 3) + roundtab_76[ycf & 0xf],
570                                                                                    (xcb >> 3) + roundtab_76[xcb & 0xf],
571                                                                                    (ycb >> 3) + roundtab_76[ycb & 0xf], data);
572    
573          if (sad < *(data->iMinSAD)) {          if (sad < *(data->iMinSAD)) {
574                  *(data->iMinSAD) = sad;                  *(data->iMinSAD) = sad;
575                  data->currentMV->x = x; data->currentMV->y = y;                  data->currentMV->x = x; data->currentMV->y = y;
576                  *dir = Direction; }                  *dir = Direction;
577            }
578  }  }
579    
580  static void  static void
581  CheckCandidateDirectno4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)  CheckCandidateDirectno4v(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)
582  {  {
583          int32_t sad;          int32_t sad, xcf, ycf, xcb, ycb;
584          const uint8_t *ReferenceF;          const uint8_t *ReferenceF;
585          const uint8_t *ReferenceB;          const uint8_t *ReferenceB;
586          VECTOR mvs, b_mvs;          VECTOR mvs, b_mvs;
587    
588          if (( x > 31) || ( x < -31) || ( y > 31) || (y < -31)) return;          if (( x > 31) | ( x < -32) | ( y > 31) | (y < -32)) return;
   
                 sad = lambda_vec16[data->iQuant] * d_mv_bits(x, y, 1);  
589    
590          mvs.x = data->directmvF[0].x + x;          mvs.x = data->directmvF[0].x + x;
591          b_mvs.x = ((x == 0) ?          b_mvs.x = ((x == 0) ?
# Line 263  Line 597 
597                  data->directmvB[0].y                  data->directmvB[0].y
598                  : mvs.y - data->referencemv[0].y);                  : mvs.y - data->referencemv[0].y);
599    
600          if (( mvs.x > data->max_dx ) || ( mvs.x < data->min_dx )          if ( (mvs.x > data->max_dx) | (mvs.x < data->min_dx)
601                  || ( mvs.y > data->max_dy ) || ( mvs.y < data->min_dy )                  | (mvs.y > data->max_dy) | (mvs.y < data->min_dy)
602                  || ( b_mvs.x > data->max_dx ) || ( b_mvs.x < data->min_dx )                  | (b_mvs.x > data->max_dx) | (b_mvs.x < data->min_dx)
603                  || ( b_mvs.y > data->max_dy ) || ( b_mvs.y < data->min_dy )) return;                  | (b_mvs.y > data->max_dy) | (b_mvs.y < data->min_dy) ) return;
604    
605          switch ( ((mvs.x&1)<<1) + (mvs.y&1) ) {          if (data->qpel) {
606                  case 0 : ReferenceF = data->Ref + mvs.x/2 + (mvs.y/2)*(data->iEdgedWidth); break;                  xcf = 4*(mvs.x/2); ycf = 4*(mvs.y/2);
607                  case 1 : ReferenceF = data->RefV + mvs.x/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;                  xcb = 4*(b_mvs.x/2); ycb = 4*(b_mvs.y/2);
608                  case 2 : ReferenceF = data->RefH + (mvs.x-1)/2 + (mvs.y/2)*(data->iEdgedWidth); break;                  ReferenceF = Interpolate16x16qpel(mvs.x, mvs.y, 0, data);
609                  default : ReferenceF = data->RefHV + (mvs.x-1)/2 + ((mvs.y-1)/2)*(data->iEdgedWidth); break;                  ReferenceB = Interpolate16x16qpel(b_mvs.x, b_mvs.y, 1, data);
610          }          } else {
611                    xcf = 4*mvs.x; ycf = 4*mvs.y;
612          switch ( ((b_mvs.x&1)<<1) + (b_mvs.y&1) ) {                  xcb = 4*b_mvs.x; ycb = 4*b_mvs.y;
613                  case 0 : ReferenceB = data->bRef + b_mvs.x/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;                  ReferenceF = GetReference(mvs.x, mvs.y, data);
614                  case 1 : ReferenceB = data->bRefV + b_mvs.x/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;                  ReferenceB = GetReferenceB(b_mvs.x, b_mvs.y, 1, data);
                 case 2 : ReferenceB = data->bRefH + (b_mvs.x-1)/2 + (b_mvs.y/2)*(data->iEdgedWidth); break;  
                 default : ReferenceB = data->bRefHV + (b_mvs.x-1)/2 + ((b_mvs.y-1)/2)*(data->iEdgedWidth); break;  
615          }          }
616    
617          sad += sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);          sad = sad16bi(data->Cur, ReferenceF, ReferenceB, data->iEdgedWidth);
618            sad += (data->lambda16 * d_mv_bits(x, y, zeroMV, 1, 0, 0) * sad)>>10;
619    
620            if (data->chroma) sad += ChromaSAD2((xcf >> 3) + roundtab_76[xcf & 0xf],
621                                                                                    (ycf >> 3) + roundtab_76[ycf & 0xf],
622                                                                                    (xcb >> 3) + roundtab_76[xcb & 0xf],
623                                                                                    (ycb >> 3) + roundtab_76[ycb & 0xf], data);
624    
625          if (sad < *(data->iMinSAD)) {          if (sad < *(data->iMinSAD)) {
626                  *(data->iMinSAD) = sad;                  *(data->iMinSAD) = sad;
627                  data->currentMV->x = x; data->currentMV->y = y;                  data->currentMV->x = x; data->currentMV->y = y;
628                  *dir = Direction; }                  *dir = Direction;
629  }  }
   
 static void  
 CheckCandidate8(const int x, const int y, const int Direction, int * const dir, const SearchData * const data)  
 {  
         int32_t sad;  
         const uint8_t * Reference;  
   
         if (( x > data->max_dx) || ( x < data->min_dx)  
                 || ( y > data->max_dy) || (y < data->min_dy)) return;  
   
         switch ( ((x&1)<<1) + (y&1) )  
         {  
                 case 0 : Reference = data->Ref + x/2 + (y/2)*(data->iEdgedWidth); break;  
                 case 1 : Reference = data->RefV + x/2 + ((y-1)/2)*(data->iEdgedWidth); break;  
                 case 2 : Reference = data->RefH + (x-1)/2 + (y/2)*(data->iEdgedWidth); break;  
                 default : Reference = data->RefHV + (x-1)/2 + ((y-1)/2)*(data->iEdgedWidth); break;  
630          }          }
631    
632          sad = sad8(data->Cur, Reference, data->iEdgedWidth);  /* CHECK_CANDIATE FUNCTIONS END */
         sad += lambda_vec8[data->iQuant] * d_mv_bits(x - data->predMV.x, y - data->predMV.y, data->iFcode);  
   
         if (sad < *(data->iMinSAD)) {  
                 *(data->iMinSAD) = sad;  
                 data->currentMV->x = x; data->currentMV->y = y;  
                 *dir = Direction; }  
 }  
   
 /* CHACK_CANDIATE FUNCTIONS END */  
633    
634  /* MAINSEARCH FUNCTIONS START */  /* MAINSEARCH FUNCTIONS START */
635    
# Line 328  Line 641 
641    
642                  int iDirection;                  int iDirection;
643    
644                  do {          for(;;) { //forever
645                          iDirection = 0;                          iDirection = 0;
646                          if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);                          if (bDirection & 1) CHECK_CANDIDATE(x - iDiamondSize, y, 1);
647                          if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);                          if (bDirection & 2) CHECK_CANDIDATE(x + iDiamondSize, y, 2);
# Line 337  Line 650 
650    
651                          /* now we're doing diagonal checks near our candidate */                          /* now we're doing diagonal checks near our candidate */
652    
653                          if (iDirection) {               //checking if anything found                  if (iDirection) {               //if anything found
654                                  bDirection = iDirection;                                  bDirection = iDirection;
655                                  iDirection = 0;                                  iDirection = 0;
656                                  x = data->currentMV->x; y = data->currentMV->y;                                  x = data->currentMV->x; y = data->currentMV->y;
# Line 346  Line 659 
659                                          CHECK_CANDIDATE(x, y - iDiamondSize, 4);                                          CHECK_CANDIDATE(x, y - iDiamondSize, 4);
660                                  } else {                        // what remains here is up or down                                  } else {                        // what remains here is up or down
661                                          CHECK_CANDIDATE(x + iDiamondSize, y, 2);                                          CHECK_CANDIDATE(x + iDiamondSize, y, 2);
662                                          CHECK_CANDIDATE(x - iDiamondSize, y, 1); }                                  CHECK_CANDIDATE(x - iDiamondSize, y, 1);
663                            }
664    
665                                  if (iDirection) {                                  if (iDirection) {
666                                          bDirection += iDirection;                                          bDirection += iDirection;
667                                          x = data->currentMV->x; y = data->currentMV->y; }                                  x = data->currentMV->x; y = data->currentMV->y;
668                            }
669                          } else {                                //about to quit, eh? not so fast....                          } else {                                //about to quit, eh? not so fast....
670                                  switch (bDirection) {                                  switch (bDirection) {
671                                  case 2:                                  case 2:
# Line 401  Line 716 
716                                  x = data->currentMV->x; y = data->currentMV->y;                                  x = data->currentMV->x; y = data->currentMV->y;
717                          }                          }
718                  }                  }
                 while (1);                              //forever  
719  }  }
720    
721  static void  static void
# Line 451  Line 765 
765                                          CHECK_CANDIDATE(x, y - iDiamondSize, 4);                                          CHECK_CANDIDATE(x, y - iDiamondSize, 4);
766                                  } else {                        // what remains here is up or down                                  } else {                        // what remains here is up or down
767                                          CHECK_CANDIDATE(x + iDiamondSize, y, 2);                                          CHECK_CANDIDATE(x + iDiamondSize, y, 2);
768                                          CHECK_CANDIDATE(x - iDiamondSize, y, 1); }                                  CHECK_CANDIDATE(x - iDiamondSize, y, 1);
769                            }
770                                  bDirection += iDirection;                                  bDirection += iDirection;
771                                  x = data->currentMV->x; y = data->currentMV->y;                                  x = data->currentMV->x; y = data->currentMV->y;
772                          }                          }
# Line 462  Line 776 
776    
777  /* MAINSEARCH FUNCTIONS END */  /* MAINSEARCH FUNCTIONS END */
778    
 /* HALFPELREFINE COULD BE A MAINSEARCH FUNCTION, BUT THERE IS NO NEED FOR IT */  
   
779  static void  static void
780  HalfpelRefine(const SearchData * const data)  SubpelRefine(const SearchData * const data)
781  {  {
782  /* Do a half-pel refinement (or rather a "smallest possible amount" refinement) */  /* Do a half-pel or q-pel refinement */
783            const VECTOR centerMV = data->qpel_precision ? *data->currentQMV : *data->currentMV;
784          VECTOR backupMV = *(data->currentMV);          int iDirection; //only needed because macro expects it
785          int iDirection; //not needed  
786            CHECK_CANDIDATE(centerMV.x, centerMV.y - 1, 0);
787          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y - 1, 0);          CHECK_CANDIDATE(centerMV.x + 1, centerMV.y - 1, 0);
788          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y - 1, 0);          CHECK_CANDIDATE(centerMV.x + 1, centerMV.y, 0);
789          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y + 1, 0);          CHECK_CANDIDATE(centerMV.x + 1, centerMV.y + 1, 0);
790          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y + 1, 0);          CHECK_CANDIDATE(centerMV.x, centerMV.y + 1, 0);
791            CHECK_CANDIDATE(centerMV.x - 1, centerMV.y + 1, 0);
792          CHECK_CANDIDATE(backupMV.x - 1, backupMV.y, 0);          CHECK_CANDIDATE(centerMV.x - 1, centerMV.y, 0);
793          CHECK_CANDIDATE(backupMV.x + 1, backupMV.y, 0);          CHECK_CANDIDATE(centerMV.x - 1, centerMV.y - 1, 0);
   
         CHECK_CANDIDATE(backupMV.x, backupMV.y + 1, 0);  
         CHECK_CANDIDATE(backupMV.x, backupMV.y - 1, 0);  
794  }  }
795    
796  static __inline int  static __inline int
797  SkipDecisionP(const IMAGE * current, const IMAGE * reference,  SkipDecisionP(const IMAGE * current, const IMAGE * reference,
798                                                          const int x, const int y,                                                          const int x, const int y,
799                                                          const uint32_t iEdgedWidth, const uint32_t iQuant)                                                          const uint32_t stride, const uint32_t iQuant, int rrv)
800    
801  {  {
802  /*      keep repeating checks for all b-frames before this P frame,          if(!rrv) {
803          to make sure that SKIP is possible (todo)                  uint32_t sadC = sad8(current->u + x*8 + y*stride*8,
804          how: if skip is not possible set sad00 to a very high value */                                                  reference->u + x*8 + y*stride*8, stride);
   
         uint32_t sadC = sad8(current->u + x*8 + y*(iEdgedWidth/2)*8,  
                                         reference->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2);  
805          if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;          if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
806          sadC += sad8(current->v + x*8 + y*(iEdgedWidth/2)*8,                  sadC += sad8(current->v + (x + y*stride)*8,
807                                          reference->v + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2);                                                  reference->v + (x + y*stride)*8, stride);
808          if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;          if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP) return 0;
809                    return 1;
810    
811            } else {
812                    uint32_t sadC = sad16(current->u + x*16 + y*stride*16,
813                                                    reference->u + x*16 + y*stride*16, stride, 256*4096);
814                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
815                    sadC += sad16(current->v + (x + y*stride)*16,
816                                                    reference->v + (x + y*stride)*16, stride, 256*4096);
817                    if (sadC > iQuant * MAX_CHROMA_SAD_FOR_SKIP*4) return 0;
818          return 1;          return 1;
819  }  }
820    }
821    
822  static __inline void  static __inline void
823  SkipMacroblockP(MACROBLOCK *pMB, const int32_t sad)  SkipMacroblockP(MACROBLOCK *pMB, const int32_t sad)
824  {  {
825          pMB->mode = MODE_NOT_CODED;          pMB->mode = MODE_NOT_CODED;
826          pMB->mvs[0].x = pMB->mvs[1].x = pMB->mvs[2].x = pMB->mvs[3].x = pMB->mv16.x = 0;          pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = zeroMV;
827          pMB->mvs[0].y = pMB->mvs[1].y = pMB->mvs[2].y = pMB->mvs[3].y = pMB->mv16.y = 0;          pMB->qmvs[0] = pMB->qmvs[1] = pMB->qmvs[2] = pMB->qmvs[3] = zeroMV;
828          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;          pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = sad;
829  }  }
830    
# Line 526  Line 841 
841          const IMAGE *const pCurrent = &current->image;          const IMAGE *const pCurrent = &current->image;
842          const IMAGE *const pRef = &reference->image;          const IMAGE *const pRef = &reference->image;
843    
844          const VECTOR zeroMV = { 0, 0 };          uint32_t mb_width = pParam->mb_width;
845            uint32_t mb_height = pParam->mb_height;
846            const uint32_t iEdgedWidth = pParam->edged_width;
847    
848          uint32_t x, y;          uint32_t x, y;
849          uint32_t iIntra = 0;          uint32_t iIntra = 0;
850          int32_t InterBias;          int32_t InterBias, quant = current->quant, sad00;
851    
852          if (sadInit) (*sadInit) ();          // some pre-initialized thingies for SearchP
853            int32_t temp[8];
854            VECTOR currentMV[5];
855            VECTOR currentQMV[5];
856            int32_t iMinSAD[5];
857            SearchData Data;
858            memset(&Data, 0, sizeof(SearchData));
859            Data.iEdgedWidth = iEdgedWidth;
860            Data.currentMV = currentMV;
861            Data.currentQMV = currentQMV;
862            Data.iMinSAD = iMinSAD;
863            Data.temp = temp;
864            Data.iFcode = current->fcode;
865            Data.rounding = pParam->m_rounding_type;
866            Data.qpel = pParam->m_quarterpel;
867            Data.chroma = current->motion_flags & PMV_CHROMA16;
868            Data.rrv = current->global_flags & XVID_REDUCED;
869    
870            if ((current->global_flags & XVID_REDUCED)) {
871                    mb_width = (pParam->width + 31) / 32;
872                    mb_height = (pParam->height + 31) / 32;
873                    Data.qpel = Data.chroma = 0;
874            }
875    
876          for (y = 0; y < pParam->mb_height; y++) {          Data.RefQ = pRefV->u; // a good place, also used in MC (for similar purpose)
877                  for (x = 0; x < pParam->mb_width; x++)  {          if (sadInit) (*sadInit) ();
878    
879            for (y = 0; y < mb_height; y++) {
880                    for (x = 0; x < mb_width; x++)  {
881                          MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];                          MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];
882                          int32_t sad00 =  pMB->sad16  
883                                  = sad16v(pCurrent->y + (x + y * pParam->edged_width) * 16,                          if (!Data.rrv) pMB->sad16 =
884                                                          pRef->y + (x + y * pParam->edged_width) * 16,                                  sad16v(pCurrent->y + (x + y * iEdgedWidth) * 16,
885                                                            pRef->y + (x + y * iEdgedWidth) * 16,
886                                                            pParam->edged_width, pMB->sad8 );
887    
888                            else pMB->sad16 =
889                                    sad32v_c(pCurrent->y + (x + y * iEdgedWidth) * 32,
890                                                            pRef->y + (x + y * iEdgedWidth) * 32,
891                                                          pParam->edged_width, pMB->sad8 );                                                          pParam->edged_width, pMB->sad8 );
892    
893                            if (Data.chroma) {
894                                    Data.temp[7] = sad8(pCurrent->u + x*8 + y*(iEdgedWidth/2)*8,
895                                                                            pRef->u + x*8 + y*(iEdgedWidth/2)*8, iEdgedWidth/2)
896                                                                    + sad8(pCurrent->v + (x + y*(iEdgedWidth/2))*8,
897                                                                            pRef->v + (x + y*(iEdgedWidth/2))*8, iEdgedWidth/2);
898                                    pMB->sad16 += Data.temp[7];
899                            }
900    
901                            sad00 = pMB->sad16;
902    
903                          if (!(current->global_flags & XVID_LUMIMASKING)) {                          if (!(current->global_flags & XVID_LUMIMASKING)) {
904                                  pMB->dquant = NO_CHANGE;                                  pMB->dquant = NO_CHANGE;
905                                  pMB->quant = current->quant; }                          } else {
906                                    if (pMB->dquant != NO_CHANGE) {
907                                            quant += DQtab[pMB->dquant];
908                                            if (quant > 31) quant = 31;
909                                            else if (quant < 1) quant = 1;
910                                    }
911                            }
912                            pMB->quant = current->quant;
913    
914  //initial skip decision  //initial skip decision
915    /* no early skip for GMC (global vector = skip vector is unknown!)  */
916                          if ((pMB->dquant == NO_CHANGE) && (sad00 <= MAX_SAD00_FOR_SKIP * pMB->quant)                          if (!(current->global_flags & XVID_GMC))        { /* no fast SKIP for S(GMC)-VOPs */
917                                  && (SkipDecisionP(pCurrent, pRef, x, y, pParam->edged_width, pMB->quant)) ) {                                  if (pMB->dquant == NO_CHANGE && sad00 < pMB->quant * INITIAL_SKIP_THRESH * (Data.rrv ? 4:1) )
918                                  if (pMB->sad16 < pMB->quant * INITIAL_SKIP_THRESH) {                                          if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, iEdgedWidth/2, pMB->quant, Data.rrv)) {
919                                                  SkipMacroblockP(pMB, sad00);                                                  SkipMacroblockP(pMB, sad00);
920                                                  continue;                                                  continue;
921                                  }                                  }
922                          } else sad00 = 256*4096; // skip not allowed - for final skip decision                          }
923    
924                          SearchP(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,                          SearchP(pRef, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,
925                                                  y, current->motion_flags, pMB->quant,                                                  y, current->motion_flags, pMB->quant,
926                                                  current->fcode, pParam, pMBs, reference->mbs,                                                  &Data, pParam, pMBs, reference->mbs,
927                                                  current->global_flags & XVID_INTER4V, pMB);                                                  current->global_flags & XVID_INTER4V, pMB);
928    
929  /* final skip decision, a.k.a. "the vector you found, really that good?" */  /* final skip decision, a.k.a. "the vector you found, really that good?" */
930                          if (sad00 < pMB->quant * MAX_SAD00_FOR_SKIP)                          if (!(current->global_flags & XVID_GMC))        {
931                                  if ((100*pMB->sad16)/(sad00+1) > FINAL_SKIP_THRESH)                                  if ( (pMB->dquant == NO_CHANGE) && (sad00 < pMB->quant * MAX_SAD00_FOR_SKIP)
932                                  { SkipMacroblockP(pMB, sad00); continue; }                                          && ((100*pMB->sad16)/(sad00+1) > FINAL_SKIP_THRESH * (Data.rrv ? 4:1)) )
933                                            if (Data.chroma || SkipDecisionP(pCurrent, pRef, x, y, iEdgedWidth/2, pMB->quant, Data.rrv)) {
934                                                    SkipMacroblockP(pMB, sad00);
935                                                    continue;
936                                            }
937                            }
938    
939  /* finally, intra decision */  /* finally, intra decision */
940    
941                          InterBias = MV16_INTER_BIAS;                          InterBias = MV16_INTER_BIAS;
942                          if (pMB->quant > 8)  InterBias += 50 * (pMB->quant - 8); // to make high quants work                          if (pMB->quant > 8) InterBias += 100 * (pMB->quant - 8); // to make high quants work
943                          if (y != 0)                          if (y != 0)
944                                  if ((pMB - pParam->mb_width)->mode == MODE_INTER ) InterBias -= 50;                                  if ((pMB - pParam->mb_width)->mode == MODE_INTRA ) InterBias -= 80;
945                          if (x != 0)                          if (x != 0)
946                                  if ((pMB - 1)->mode == MODE_INTER ) InterBias -= 50;                                  if ((pMB - 1)->mode == MODE_INTRA ) InterBias -= 80;
947    
948                          if (InterBias < pMB->sad16)  {                          if (Data.chroma) InterBias += 50; // to compensate bigger SAD
949                                  const int32_t deviation =                          if (Data.rrv) InterBias *= 4;
                                         dev16(pCurrent->y + (x + y * pParam->edged_width) * 16,  
                                                   pParam->edged_width);  
950    
951                            if (InterBias < pMB->sad16) {
952                                    int32_t deviation;
953                                    if (!Data.rrv)
954                                            deviation = dev16(pCurrent->y + (x + y * iEdgedWidth) * 16, iEdgedWidth);
955                                    else {
956                                            deviation = dev16(pCurrent->y + (x + y * iEdgedWidth) * 32, iEdgedWidth)
957                                                    + dev16(pCurrent->y + (x + y * iEdgedWidth) * 32 + 16, iEdgedWidth)
958                                                    + dev16(pCurrent->y + (x + y * iEdgedWidth) * 32 + 16 * iEdgedWidth, iEdgedWidth)
959                                                    + dev16(pCurrent->y + (x + y * iEdgedWidth) * 32 + 16 * (iEdgedWidth+1), iEdgedWidth);
960                                    }
961                                  if (deviation < (pMB->sad16 - InterBias)) {                                  if (deviation < (pMB->sad16 - InterBias)) {
962                                          if (++iIntra >= iLimit) return 1;                                          if (++iIntra >= iLimit) return 1;
963                                            SkipMacroblockP(pMB, 0); //same thing
964                                          pMB->mode = MODE_INTRA;                                          pMB->mode = MODE_INTRA;
                                         pMB->mv16 = pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] =  
                                                 pMB->mvs[3] = zeroMV;  
                                         pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] =  
                                                 pMB->sad8[3] = 0;  
965                                  }                                  }
966                          }                          }
967                  }                  }
968          }          }
969          return 0;  
970            if (current->global_flags & XVID_GMC )  /* GMC only for S(GMC)-VOPs */
971            {
972                    current->warp = GlobalMotionEst( pMBs, pParam, current, reference, pRefH, pRefV, pRefHV);
973  }  }
974    
975            return 0;
976    }
977    
 #define PMV_HALFPEL16 (PMV_HALFPELDIAMOND16|PMV_HALFPELREFINE16)  
978    
979  static __inline int  static __inline int
980  make_mask(const VECTOR * const pmv, const int i)  make_mask(const VECTOR * const pmv, const int i)
981  {  {
982          int mask = 0xFF, j;          int mask = 255, j;
983          for (j = 0; j < i; j++) {          for (j = 0; j < i; j++) {
984                  if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already                  if (MVequal(pmv[i], pmv[j])) return 0; // same vector has been checked already
985                  if (pmv[i].x == pmv[j].x) {                  if (pmv[i].x == pmv[j].x) {
986                          if (pmv[i].y == pmv[j].y + iDiamondSize) { mask &= ~4; continue; }                          if (pmv[i].y == pmv[j].y + iDiamondSize) mask &= ~4;
987                          if (pmv[i].y == pmv[j].y - iDiamondSize) { mask &= ~8; continue; }                          else if (pmv[i].y == pmv[j].y - iDiamondSize) mask &= ~8;
988                  } else                  } else
989                          if (pmv[i].y == pmv[j].y) {                          if (pmv[i].y == pmv[j].y) {
990                                  if (pmv[i].x == pmv[j].x + iDiamondSize) { mask &= ~1; continue; }                                  if (pmv[i].x == pmv[j].x + iDiamondSize) mask &= ~1;
991                                  if (pmv[i].x == pmv[j].x - iDiamondSize) { mask &= ~2; continue; }                                  else if (pmv[i].x == pmv[j].x - iDiamondSize) mask &= ~2;
992                          }                          }
993          }          }
994          return mask;          return mask;
995  }  }
996    
997  static __inline void  static __inline void
998  PreparePredictionsP(VECTOR * const pmv, int x, int y, const int iWcount,  PreparePredictionsP(VECTOR * const pmv, int x, int y, int iWcount,
999                          const int iHcount, const MACROBLOCK * const prevMB)                          int iHcount, const MACROBLOCK * const prevMB, int rrv)
1000  {  {
1001    
1002  //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself  //this function depends on get_pmvdata which means that it sucks. It should get the predictions by itself
1003            if (rrv) { iWcount /= 2; iHcount /= 2; }
1004    
1005          if ( (y != 0) && (x != (iWcount-1)) ) {         // [5] top-right neighbour          if ( (y != 0) && (x < (iWcount-1)) ) {          // [5] top-right neighbour
1006                  pmv[5].x = EVEN(pmv[3].x);                  pmv[5].x = EVEN(pmv[3].x);
1007                  pmv[5].y = EVEN(pmv[3].y); }                  pmv[5].y = EVEN(pmv[3].y);
1008          else pmv[5].x = pmv[5].y = 0;          } else pmv[5].x = pmv[5].y = 0;
1009    
1010          if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }// pmv[3] is left neighbour          if (x != 0) { pmv[3].x = EVEN(pmv[1].x); pmv[3].y = EVEN(pmv[1].y); }// pmv[3] is left neighbour
1011          else pmv[3].x = pmv[3].y = 0;          else pmv[3].x = pmv[3].y = 0;
# Line 642  Line 1021 
1021          pmv[2].x = EVEN(prevMB->mvs[0].x); // [2] is last frame          pmv[2].x = EVEN(prevMB->mvs[0].x); // [2] is last frame
1022          pmv[2].y = EVEN(prevMB->mvs[0].y);          pmv[2].y = EVEN(prevMB->mvs[0].y);
1023    
1024          if ((x != iWcount-1) && (y != iHcount-1)) {          if ((x < iWcount-1) && (y < iHcount-1)) {
1025                  pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); //[6] right-down neighbour in last frame                  pmv[6].x = EVEN((prevMB+1+iWcount)->mvs[0].x); //[6] right-down neighbour in last frame
1026                  pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y); }                  pmv[6].y = EVEN((prevMB+1+iWcount)->mvs[0].y);
1027          else pmv[6].x = pmv[6].y = 0;          } else pmv[6].x = pmv[6].y = 0;
1028    
1029            if (rrv) {
1030                    int i;
1031                    for (i = 0; i < 7; i++) {
1032                            pmv[i].x = RRV_MV_SCALEUP(pmv[i].x);
1033                            pmv[i].y = RRV_MV_SCALEUP(pmv[i].y);
1034                    }
1035            }
1036  }  }
1037    
1038  static void  static void
1039  SearchP(const uint8_t * const pRef,  SearchP(const IMAGE * const pRef,
1040                  const uint8_t * const pRefH,                  const uint8_t * const pRefH,
1041                  const uint8_t * const pRefV,                  const uint8_t * const pRefV,
1042                  const uint8_t * const pRefHV,                  const uint8_t * const pRefHV,
# Line 658  Line 1045 
1045                  const int y,                  const int y,
1046                  const uint32_t MotionFlags,                  const uint32_t MotionFlags,
1047                  const uint32_t iQuant,                  const uint32_t iQuant,
1048                  const uint32_t iFcode,                  SearchData * const Data,
1049                  const MBParam * const pParam,                  const MBParam * const pParam,
1050                  const MACROBLOCK * const pMBs,                  const MACROBLOCK * const pMBs,
1051                  const MACROBLOCK * const prevMBs,                  const MACROBLOCK * const prevMBs,
# Line 666  Line 1053 
1053                  MACROBLOCK * const pMB)                  MACROBLOCK * const pMB)
1054  {  {
1055    
         const int32_t iEdgedWidth = pParam->edged_width;  
   
1056          int i, iDirection = 255, mask, threshA;          int i, iDirection = 255, mask, threshA;
1057          int32_t temp[5];          VECTOR pmv[7];
         VECTOR currentMV[5], pmv[7];  
         int32_t psad[4], iMinSAD[5];  
         MainSearchFunc * MainSearchPtr;  
         SearchData Data;  
1058    
1059          get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, psad);  //has to be changed to get_pmv(2)()          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1060          get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 16,                                                  pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
                                 pParam->width, pParam->height, iFcode);  
1061    
1062          Data.predMV = pmv[0];          get_pmvdata2(pMBs, pParam->mb_width, 0, x, y, 0, pmv, Data->temp);
         Data.Cur = pCur->y + (x + y * iEdgedWidth) * 16;  
         Data.iEdgedWidth = iEdgedWidth;  
         Data.currentMV = currentMV;  
         Data.iMinSAD = iMinSAD;  
         Data.Ref = pRef + (x + iEdgedWidth*y)*16;  
         Data.RefH = pRefH + (x + iEdgedWidth*y) * 16;  
         Data.RefV = pRefV + (x + iEdgedWidth*y) * 16;  
         Data.RefHV = pRefHV + (x + iEdgedWidth*y) * 16;  
         Data.temp = temp;  
   
         Data.iQuant = iQuant;  
         Data.iFcode = iFcode;  
1063    
1064          if (!(MotionFlags & PMV_HALFPEL16)) {          Data->temp[5] = Data->temp[6] = 0; // chroma-sad cache
1065                  Data.min_dx = EVEN(Data.min_dx);          i = Data->rrv ? 2 : 1;
1066                  Data.max_dx = EVEN(Data.max_dx);          Data->Cur = pCur->y + (x + y * Data->iEdgedWidth) * 16*i;
1067                  Data.min_dy = EVEN(Data.min_dy);          Data->CurV = pCur->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1068                  Data.max_dy = EVEN(Data.max_dy); }          Data->CurU = pCur->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1069    
1070          for(i = 0;  i < 5; i++) currentMV[i].x = currentMV[i].y = 0;          Data->Ref = pRef->y + (x + Data->iEdgedWidth*y) * 16*i;
1071            Data->RefH = pRefH + (x + Data->iEdgedWidth*y) * 16*i;
1072          i = d_mv_bits(pmv[0].x, pmv[0].y, iFcode);          Data->RefV = pRefV + (x + Data->iEdgedWidth*y) * 16*i;
1073            Data->RefHV = pRefHV + (x + Data->iEdgedWidth*y) * 16*i;
1074          iMinSAD[0] = pMB->sad16 + lambda_vec16[iQuant] * i;          Data->RefCV = pRef->v + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1075          iMinSAD[1] = pMB->sad8[0] + lambda_vec8[iQuant] * i;          Data->RefCU = pRef->u + (x + y * (Data->iEdgedWidth/2)) * 8*i;
1076          iMinSAD[2] = pMB->sad8[1];  
1077          iMinSAD[3] = pMB->sad8[2];          Data->lambda16 = lambda_vec16[iQuant];
1078          iMinSAD[4] = pMB->sad8[3];          Data->lambda8 = lambda_vec8[iQuant];
1079            Data->qpel_precision = 0;
1080    
1081          if (pMB->dquant != NO_CHANGE) inter4v = 0;          if (pMB->dquant != NO_CHANGE) inter4v = 0;
1082    
1083          if ((x == 0) && (y == 0)) threshA = 512;          for(i = 0; i < 5; i++)
1084          else {                  Data->currentMV[i].x = Data->currentMV[i].y = 0;
1085                  threshA = psad[0] + 20;  
1086            if (Data->qpel) Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x, y, 0);
1087            else Data->predMV = pmv[0];
1088    
1089            i = d_mv_bits(0, 0, Data->predMV, Data->iFcode, 0, 0);
1090            Data->iMinSAD[0] = pMB->sad16 + ((Data->lambda16 * i * pMB->sad16)>>10);
1091            Data->iMinSAD[1] = pMB->sad8[0] + ((Data->lambda8 * i * (pMB->sad8[0]+NEIGH_8X8_BIAS)) >> 10);
1092            Data->iMinSAD[2] = pMB->sad8[1];
1093            Data->iMinSAD[3] = pMB->sad8[2];
1094            Data->iMinSAD[4] = pMB->sad8[3];
1095    
1096            if (x | y) {
1097                    threshA = Data->temp[0]; // that's when we keep this SAD atm
1098                  if (threshA < 512) threshA = 512;                  if (threshA < 512) threshA = 512;
1099                  if (threshA > 1024) threshA = 1024; }                  else if (threshA > 1024) threshA = 1024;
1100            } else threshA = 512;
1101    
1102          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,          PreparePredictionsP(pmv, x, y, pParam->mb_width, pParam->mb_height,
1103                                          prevMBs + x + y * pParam->mb_width);                                          prevMBs + x + y * pParam->mb_width, Data->rrv);
1104    
1105          if (inter4v) CheckCandidate = CheckCandidate16;          if (!Data->rrv) {
1106          else CheckCandidate = CheckCandidate16no4v;                  if (inter4v | Data->chroma) CheckCandidate = CheckCandidate16;
1107                            else CheckCandidate = CheckCandidate16no4v; //for extra speed
1108            } else CheckCandidate = CheckCandidate32;
1109    
1110  /* main loop. checking all predictions */  /* main loop. checking all predictions (but first, which is 0,0 and has been checked in MotionEstimation())*/
1111    
1112          for (i = 1; i < 7; i++) {          for (i = 1; i < 7; i++) {
1113                  if (!(mask = make_mask(pmv, i)) ) continue;                  if (!(mask = make_mask(pmv, i)) ) continue;
1114                  CheckCandidate16(pmv[i].x, pmv[i].y, mask, &iDirection, &Data);                  CheckCandidate(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1115                  if (iMinSAD[0] < threshA) break;                  if (Data->iMinSAD[0] <= threshA) break;
1116          }          }
1117    
1118          if ((iMinSAD[0] <= threshA) ||          if ((Data->iMinSAD[0] <= threshA) ||
1119                          (MVequal(currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&                          (MVequal(Data->currentMV[0], (prevMBs+x+y*pParam->mb_width)->mvs[0]) &&
1120                          (iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16))) {                          (Data->iMinSAD[0] < (prevMBs+x+y*pParam->mb_width)->sad16)))
1121                  inter4v = 0;                  inter4v = 0;
1122                  if (MotionFlags & PMV_QUICKSTOP16) goto PMVfast16_Terminate_without_Refine;          else {
                 if (MotionFlags & PMV_EARLYSTOP16) {  
                         CheckCandidate = CheckCandidate16no4v; // I sure hope it's faster  
                         goto PMVfast16_Terminate_with_Refine;  
                 }  
         }  
1123    
1124          if (MotionFlags & PMV_USESQUARES16)                  MainSearchFunc * MainSearchPtr;
1125                  MainSearchPtr = SquareSearch;                  if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1126          else if (MotionFlags & PMV_ADVANCEDDIAMOND16)                  else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
                 MainSearchPtr = AdvDiamondSearch;  
1127                  else MainSearchPtr = DiamondSearch;                  else MainSearchPtr = DiamondSearch;
1128    
1129          (*MainSearchPtr)(currentMV->x, currentMV->y, &Data, iDirection);                  (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
1130    
1131  /* extended search, diamond starting in 0,0 and in prediction.  /* extended search, diamond starting in 0,0 and in prediction.
1132          note that this search is/might be done in halfpel positions,          note that this search is/might be done in halfpel positions,
# Line 756  Line 1134 
1134    
1135          if (MotionFlags & PMV_EXTSEARCH16) {          if (MotionFlags & PMV_EXTSEARCH16) {
1136                  int32_t bSAD;                  int32_t bSAD;
1137                  VECTOR startMV = Data.predMV, backupMV = currentMV[0];                          VECTOR startMV = Data->predMV, backupMV = Data->currentMV[0];
1138                            if (Data->rrv) {
1139                                    startMV.x = RRV_MV_SCALEUP(startMV.x);
1140                                    startMV.y = RRV_MV_SCALEUP(startMV.y);
1141                            } else
1142                  if (!(MotionFlags & PMV_HALFPELREFINE16)) // who's gonna use extsearch and no halfpel?                  if (!(MotionFlags & PMV_HALFPELREFINE16)) // who's gonna use extsearch and no halfpel?
1143                          startMV.x = EVEN(startMV.x); startMV.y = EVEN(startMV.y);                          startMV.x = EVEN(startMV.x); startMV.y = EVEN(startMV.y);
1144                  if (!(MVequal(startMV, backupMV))) {                  if (!(MVequal(startMV, backupMV))) {
1145                          bSAD = iMinSAD[0]; iMinSAD[0] = MV_MAX_ERROR;                                  bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1146    
1147                          CheckCandidate16(startMV.x, startMV.y, 255, &iDirection, &Data);                                  CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1148                          (*MainSearchPtr)(startMV.x, startMV.y, &Data, 255);                                  (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
1149                          if (bSAD < iMinSAD[0]) {                                  if (bSAD < Data->iMinSAD[0]) {
1150                                  currentMV[0] = backupMV;                                          Data->currentMV[0] = backupMV;
1151                                  iMinSAD[0] = bSAD; }                                          Data->iMinSAD[0] = bSAD; }
1152                  }                  }
1153    
1154                  backupMV = currentMV[0];                          backupMV = Data->currentMV[0];
1155                  if (MotionFlags & PMV_HALFPELREFINE16) startMV.x = startMV.y = 1;                          if (MotionFlags & PMV_HALFPELREFINE16 && !Data->rrv) startMV.x = startMV.y = 1;
1156                  else startMV.x = startMV.y = 0;                  else startMV.x = startMV.y = 0;
1157                  if (!(MVequal(startMV, backupMV))) {                  if (!(MVequal(startMV, backupMV))) {
1158                          bSAD = iMinSAD[0]; iMinSAD[0] = MV_MAX_ERROR;                                  bSAD = Data->iMinSAD[0]; Data->iMinSAD[0] = MV_MAX_ERROR;
1159    
1160                                    CheckCandidate(startMV.x, startMV.y, 255, &iDirection, Data);
1161                                    (*MainSearchPtr)(startMV.x, startMV.y, Data, 255);
1162                                    if (bSAD < Data->iMinSAD[0]) {
1163                                            Data->currentMV[0] = backupMV;
1164                                            Data->iMinSAD[0] = bSAD; }
1165                            }
1166                    }
1167            }
1168    
1169            if (MotionFlags & PMV_HALFPELREFINE16) SubpelRefine(Data);
1170    
1171                          CheckCandidate16(startMV.x, startMV.y, 255, &iDirection, &Data);          for(i = 0; i < 5; i++) {
1172                          (*MainSearchPtr)(startMV.x, startMV.y, &Data, 255);                  Data->currentQMV[i].x = 2 * Data->currentMV[i].x; // initialize qpel vectors
1173                          if (bSAD < iMinSAD[0]) {                  Data->currentQMV[i].y = 2 * Data->currentMV[i].y;
                                 currentMV[0] = backupMV;  
                                 iMinSAD[0] = bSAD; }  
1174                  }                  }
1175    
1176            if (Data->qpel && MotionFlags & PMV_QUARTERPELREFINE16) {
1177                    Data->qpel_precision = 1;
1178                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1179                                    pParam->width, pParam->height, Data->iFcode, 1, 0);
1180    
1181                    SubpelRefine(Data);
1182          }          }
1183    
1184  PMVfast16_Terminate_with_Refine:          if (Data->iMinSAD[0] < (int32_t)iQuant * 30) inter4v = 0;
1185            if (inter4v) {
1186                    SearchData Data8;
1187                    memcpy(&Data8, Data, sizeof(SearchData)); //quick copy of common data
1188    
1189                    Search8(Data, 2*x, 2*y, MotionFlags, pParam, pMB, pMBs, 0, &Data8);
1190                    Search8(Data, 2*x + 1, 2*y, MotionFlags, pParam, pMB, pMBs, 1, &Data8);
1191                    Search8(Data, 2*x, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 2, &Data8);
1192                    Search8(Data, 2*x + 1, 2*y + 1, MotionFlags, pParam, pMB, pMBs, 3, &Data8);
1193    
1194                    if (Data->chroma) {
1195                            int sumx = 0, sumy = 0;
1196                            const int div = 1 + Data->qpel;
1197                            const VECTOR * const mv = Data->qpel ? pMB->qmvs : pMB->mvs;
1198    
1199          if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(&Data);                          for (i = 0; i < 4; i++) {
1200                                    sumx += mv[i].x / div;
1201                                    sumy += mv[i].y / div;
1202                            }
1203    
1204  PMVfast16_Terminate_without_Refine:                          Data->iMinSAD[1] += ChromaSAD(  (sumx >> 3) + roundtab_76[sumx & 0xf],
1205                                                                                            (sumy >> 3) + roundtab_76[sumy & 0xf], Data);
1206                    }
1207            }
1208    
1209          if (inter4v)          if (Data->rrv) {
1210                  for(i = 0; i < 4; i++)                          Data->currentMV[0].x = RRV_MV_SCALEDOWN(Data->currentMV[0].x);
1211                          Search8(&Data, 2*x+(i&1), 2*y+(i>>1), MotionFlags, pParam, pMB, pMBs, i);                          Data->currentMV[0].y = RRV_MV_SCALEDOWN(Data->currentMV[0].y);
1212            }
1213    
1214          if (!(inter4v) ||          if (!(inter4v) ||
1215                  (iMinSAD[0] < iMinSAD[1] + iMinSAD[2] + iMinSAD[3] + iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {                  (Data->iMinSAD[0] < Data->iMinSAD[1] + Data->iMinSAD[2] +
1216                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {
1217  // INTER MODE  // INTER MODE
1218                  pMB->mode = MODE_INTER;                  pMB->mode = MODE_INTER;
1219                  pMB->mv16 = pMB->mvs[0] = pMB->mvs[1]                  pMB->mvs[0] = pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = Data->currentMV[0];
1220                          = pMB->mvs[2] = pMB->mvs[3] = currentMV[0];                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] = pMB->sad8[2] = pMB->sad8[3] = Data->iMinSAD[0];
1221    
1222                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =                  if(Data->qpel) {
1223                          pMB->sad8[2] = pMB->sad8[3] =  iMinSAD[0];                          pMB->qmvs[0] = pMB->qmvs[1]
1224                                    = pMB->qmvs[2] = pMB->qmvs[3] = Data->currentQMV[0];
1225                  pMB->pmvs[0].x = currentMV[0].x - Data.predMV.x;                          pMB->pmvs[0].x = Data->currentQMV[0].x - Data->predMV.x;
1226                  pMB->pmvs[0].y = currentMV[0].y - Data.predMV.y;                          pMB->pmvs[0].y = Data->currentQMV[0].y - Data->predMV.y;
1227                    } else {
1228                            pMB->pmvs[0].x = Data->currentMV[0].x - Data->predMV.x;
1229                            pMB->pmvs[0].y = Data->currentMV[0].y - Data->predMV.y;
1230                    }
1231          } else {          } else {
1232  // INTER4V MODE; all other things are already set in Search8  // INTER4V MODE; all other things are already set in Search8
1233                  pMB->mode = MODE_INTER4V;                  pMB->mode = MODE_INTER4V;
1234                  pMB->sad16 = iMinSAD[1] + iMinSAD[2] + iMinSAD[3] + iMinSAD[4] + IMV16X16 * iQuant;                  pMB->sad16 = Data->iMinSAD[1] + Data->iMinSAD[2] +
1235                            Data->iMinSAD[3] + Data->iMinSAD[4] + IMV16X16 * iQuant;
1236          }          }
   
1237  }  }
1238    
1239  static void  static void
# Line 820  Line 1243 
1243                  const MBParam * const pParam,                  const MBParam * const pParam,
1244                  MACROBLOCK * const pMB,                  MACROBLOCK * const pMB,
1245                  const MACROBLOCK * const pMBs,                  const MACROBLOCK * const pMBs,
1246                  const int block)                  const int block,
1247                    SearchData * const Data)
1248  {  {
1249          SearchData Data;          int i = 0;
1250            Data->iMinSAD = OldData->iMinSAD + 1 + block;
1251            Data->currentMV = OldData->currentMV + 1 + block;
1252            Data->currentQMV = OldData->currentQMV + 1 + block;
1253    
1254            if(Data->qpel) {
1255                    Data->predMV = get_qpmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1256                    if (block != 0) i = d_mv_bits(  Data->currentQMV->x, Data->currentQMV->y,
1257                                                                                    Data->predMV, Data->iFcode, 0, 0);
1258            } else {
1259                    Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2, y/2, block);
1260                    if (block != 0) i = d_mv_bits(  Data->currentMV->x, Data->currentMV->y,
1261                                                                                    Data->predMV, Data->iFcode, 0, Data->rrv);
1262            }
1263    
1264          Data.predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2 , y/2, block);          *(Data->iMinSAD) += (Data->lambda8 * i * (*Data->iMinSAD + NEIGH_8X8_BIAS))>>10;
         Data.iMinSAD = OldData->iMinSAD + 1 + block;  
         Data.currentMV = OldData->currentMV+1+block;  
         Data.iFcode = OldData->iFcode;  
         Data.iQuant = OldData->iQuant;  
   
         if (block != 0)  
                 *(Data.iMinSAD) += lambda_vec8[Data.iQuant] *  
                                                                 d_mv_bits(      Data.currentMV->x - Data.predMV.x,  
                                                                                         Data.currentMV->y - Data.predMV.y,  
                                                                                         Data.iFcode);  
   
   
         if (MotionFlags & (PMV_EXTSEARCH8|PMV_HALFPELREFINE8)) {  
   
                 Data.Ref = OldData->Ref + 8 * ((block&1) + pParam->edged_width*(block>>1));  
                 Data.RefH = OldData->RefH + 8 * ((block&1) + pParam->edged_width*(block>>1));  
                 Data.RefV = OldData->RefV + 8 * ((block&1) + pParam->edged_width*(block>>1));  
                 Data.RefHV = OldData->RefHV + 8 * ((block&1) + pParam->edged_width*(block>>1));  
1265    
1266                  Data.iEdgedWidth = pParam->edged_width;          if (MotionFlags & (PMV_EXTSEARCH8|PMV_HALFPELREFINE8|PMV_QUARTERPELREFINE8)) {
1267                    if (Data->rrv) i = 2; else i = 1;
1268    
1269                  Data.Cur = OldData->Cur + 8 * ((block&1) + pParam->edged_width*(block>>1));                  Data->Ref = OldData->Ref + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));
1270                    Data->RefH = OldData->RefH + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));
1271                    Data->RefV = OldData->RefV + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));
1272                    Data->RefHV = OldData->RefHV + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));
1273    
1274                  get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 8,                  Data->Cur = OldData->Cur + i * 8 * ((block&1) + Data->iEdgedWidth*(block>>1));
1275                                  pParam->width, pParam->height, OldData->iFcode);                  Data->qpel_precision = 0;
1276    
1277                  CheckCandidate = CheckCandidate8;                  get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1278                                            pParam->width, pParam->height, Data->iFcode - Data->qpel, 0, Data->rrv);
1279    
1280                    if (!Data->rrv) CheckCandidate = CheckCandidate8;
1281                    else CheckCandidate = CheckCandidate16no4v;
1282    
1283                  if (MotionFlags & PMV_EXTSEARCH8) {                  if (MotionFlags & PMV_EXTSEARCH8) {
1284                            int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
1285    
1286                          MainSearchFunc *MainSearchPtr;                          MainSearchFunc *MainSearchPtr;
1287                          if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;                          if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;
1288                                  else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;                                  else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;
1289                                          else MainSearchPtr = DiamondSearch;                                          else MainSearchPtr = DiamondSearch;
1290    
1291                          (*MainSearchPtr)(Data.currentMV->x, Data.currentMV->y, &Data, 255);     }                          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, 255);
1292    
1293                  if (MotionFlags & PMV_HALFPELREFINE8) HalfpelRefine(&Data);                          if(*(Data->iMinSAD) < temp_sad) {
1294                                            Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1295                                            Data->currentQMV->y = 2 * Data->currentMV->y;
1296          }          }
1297                    }
1298    
1299                    if (MotionFlags & PMV_HALFPELREFINE8) {
1300                            int32_t temp_sad = *(Data->iMinSAD); // store current MinSAD
1301    
1302          pMB->pmvs[block].x = Data.currentMV->x - Data.predMV.x;                          SubpelRefine(Data); // perform halfpel refine of current best vector
1303          pMB->pmvs[block].y = Data.currentMV->y - Data.predMV.y;  
1304          pMB->mvs[block] = *(Data.currentMV);                          if(*(Data->iMinSAD) < temp_sad) { // we have found a better match
1305          pMB->sad8[block] =  4 * (*(Data.iMinSAD));                                  Data->currentQMV->x = 2 * Data->currentMV->x; // update our qpel vector
1306                                    Data->currentQMV->y = 2 * Data->currentMV->y;
1307                            }
1308                    }
1309    
1310                    if (Data->qpel && MotionFlags & PMV_QUARTERPELREFINE8) {
1311                                    Data->qpel_precision = 1;
1312                                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 8,
1313                                            pParam->width, pParam->height, Data->iFcode, 1, 0);
1314                                    SubpelRefine(Data);
1315                    }
1316            }
1317    
1318            if (Data->rrv) {
1319                            Data->currentMV->x = RRV_MV_SCALEDOWN(Data->currentMV->x);
1320                            Data->currentMV->y = RRV_MV_SCALEDOWN(Data->currentMV->y);
1321            }
1322    
1323            if(Data->qpel) {
1324                    pMB->pmvs[block].x = Data->currentQMV->x - Data->predMV.x;
1325                    pMB->pmvs[block].y = Data->currentQMV->y - Data->predMV.y;
1326                    pMB->qmvs[block] = *Data->currentQMV;
1327            } else {
1328                    pMB->pmvs[block].x = Data->currentMV->x - Data->predMV.x;
1329                    pMB->pmvs[block].y = Data->currentMV->y - Data->predMV.y;
1330            }
1331    
1332            pMB->mvs[block] = *Data->currentMV;
1333            pMB->sad8[block] = 4 * *Data->iMinSAD;
1334  }  }
1335    
1336  /* B-frames code starts here */  /* motion estimation for B-frames */
1337    
1338  static __inline VECTOR  static __inline VECTOR
1339  ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)  ChoosePred(const MACROBLOCK * const pMB, const uint32_t mode)
1340  {  {
1341  /* the stupidiest function ever */  /* the stupidiest function ever */
1342          if (mode == MODE_FORWARD) return pMB->mvs[0];          return (mode == MODE_FORWARD ? pMB->mvs[0] : pMB->b_mvs[0]);
         else return pMB->b_mvs[0];  
1343  }  }
1344    
1345  static void __inline  static void __inline
# Line 896  Line 1357 
1357          pmv[2] = ChoosePred(pMB, mode_curr);          pmv[2] = ChoosePred(pMB, mode_curr);
1358          pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);          pmv[2].x = EVEN(pmv[2].x); pmv[2].y = EVEN(pmv[2].y);
1359    
         pmv[3].x = pmv[3].y = 0;  
1360          if ((y != 0)&&(x != (int)(iWcount+1))) {                        // [3] top-right neighbour          if ((y != 0)&&(x != (int)(iWcount+1))) {                        // [3] top-right neighbour
1361                  pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);                  pmv[3] = ChoosePred(pMB+1-iWcount, mode_curr);
1362                  pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y); }                  pmv[3].x = EVEN(pmv[3].x); pmv[3].y = EVEN(pmv[3].y);
1363            } else pmv[3].x = pmv[3].y = 0;
1364    
1365          if (y != 0) {          if (y != 0) {
1366                  pmv[4] = ChoosePred(pMB-iWcount, mode_curr);                  pmv[4] = ChoosePred(pMB-iWcount, mode_curr);
# Line 911  Line 1372 
1372                  pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);                  pmv[5].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);
1373          } else pmv[5].x = pmv[5].y = 0;          } else pmv[5].x = pmv[5].y = 0;
1374    
1375          if ((x != 0)&&(y != 0)) {          if (x != 0 && y != 0) {
1376                  pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);                  pmv[6] = ChoosePred(pMB-1-iWcount, mode_curr);
1377                  pmv[6].x = EVEN(pmv[5].x); pmv[5].y = EVEN(pmv[5].y);                  pmv[6].x = EVEN(pmv[6].x); pmv[6].y = EVEN(pmv[6].y);
1378          } else pmv[6].x = pmv[6].y = 0;          } else pmv[6].x = pmv[6].y = 0;
   
 // more?  
1379  }  }
1380    
1381    
1382  /* search backward or forward, for b-frames */  /* search backward or forward */
1383  static void  static void
1384  SearchBF(       const uint8_t * const pRef,  SearchBF(       const IMAGE * const pRef,
1385                          const uint8_t * const pRefH,                          const uint8_t * const pRefH,
1386                          const uint8_t * const pRefV,                          const uint8_t * const pRefV,
1387                          const uint8_t * const pRefHV,                          const uint8_t * const pRefHV,
1388                          const IMAGE * const pCur,                          const IMAGE * const pCur,
1389                          const int x, const int y,                          const int x, const int y,
1390                          const uint32_t MotionFlags,                          const uint32_t MotionFlags,
                         const uint32_t iQuant,  
1391                          const uint32_t iFcode,                          const uint32_t iFcode,
1392                          const MBParam * const pParam,                          const MBParam * const pParam,
1393                          MACROBLOCK * const pMB,                          MACROBLOCK * const pMB,
1394                          const VECTOR * const predMV,                          const VECTOR * const predMV,
1395                          int32_t * const best_sad,                          int32_t * const best_sad,
1396                          const int32_t mode_current)                          const int32_t mode_current,
1397                            SearchData * const Data)
1398  {  {
1399    
1400          const int32_t iEdgedWidth = pParam->edged_width;          int i, iDirection = 255, mask;
1401            VECTOR pmv[7];
         int i, iDirection, mask;  
         VECTOR currentMV, pmv[7];  
1402          MainSearchFunc *MainSearchPtr;          MainSearchFunc *MainSearchPtr;
1403          int32_t iMinSAD = MV_MAX_ERROR;          *Data->iMinSAD = MV_MAX_ERROR;
1404          SearchData Data;          Data->iFcode = iFcode;
1405            Data->qpel_precision = 0;
1406            Data->temp[5] = Data->temp[6] = Data->temp[7] = 256*4096; // reset chroma-sad cache
1407    
1408          Data.iMinSAD = &iMinSAD;          Data->Ref = pRef->y + (x + y * Data->iEdgedWidth) * 16;
1409          Data.Cur = pCur->y + (x + y * iEdgedWidth) * 16;          Data->RefH = pRefH + (x + y * Data->iEdgedWidth) * 16;
1410          Data.iEdgedWidth = iEdgedWidth;          Data->RefV = pRefV + (x + y * Data->iEdgedWidth) * 16;
1411          Data.currentMV = &currentMV;          Data->RefHV = pRefHV + (x + y * Data->iEdgedWidth) * 16;
1412          Data.iMinSAD = &iMinSAD;          Data->RefCU = pRef->u + (x + y * Data->iEdgedWidth/2) * 8;
1413          Data.Ref = pRef + (x + y * iEdgedWidth) * 16;          Data->RefCV = pRef->v + (x + y * Data->iEdgedWidth/2) * 8;
1414          Data.RefH = pRefH + (x + y * iEdgedWidth) * 16;  
1415          Data.RefV = pRefV + (x + y * iEdgedWidth) * 16;          Data->predMV = *predMV;
         Data.RefHV = pRefHV + (x + y * iEdgedWidth) * 16;  
   
         Data.iQuant = iQuant;  
         Data.iFcode = iFcode;  
         Data.predMV = *predMV;  
   
         get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 16,  
                                 pParam->width, pParam->height, iFcode);  
   
         if (!(MotionFlags & PMV_HALFPEL16)) {  
                 Data.min_dx = EVEN(Data.min_dx);  
                 Data.max_dx = EVEN(Data.max_dx);  
                 Data.min_dy = EVEN(Data.min_dy);  
                 Data.max_dy = EVEN(Data.max_dy); } // no-halpel and b-frames. do we need it?  
   
   
         pmv[0] = Data.predMV;  
         PreparePredictionsBF(pmv, x, y, pParam->mb_width,  
                                         pMB, mode_current);  
1416    
1417          currentMV.x = currentMV.y = 0;          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1418                                    pParam->width, pParam->height, iFcode - Data->qpel, 0, 0);
1419    
1420            pmv[0] = Data->predMV;
1421            if (Data->qpel) { pmv[0].x /= 2; pmv[0].y /= 2; }
1422    
1423            PreparePredictionsBF(pmv, x, y, pParam->mb_width, pMB, mode_current);
1424    
1425            Data->currentMV->x = Data->currentMV->y = 0;
1426          CheckCandidate = CheckCandidate16no4v;          CheckCandidate = CheckCandidate16no4v;
1427    
1428  // main loop. checking all predictions  // main loop. checking all predictions
1429          for (i = 0; i < 8; i++) {          for (i = 0; i < 7; i++) {
1430                  if (!(mask = make_mask(pmv, i)) ) continue;                  if (!(mask = make_mask(pmv, i)) ) continue;
1431                  CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, &Data);                  CheckCandidate16no4v(pmv[i].x, pmv[i].y, mask, &iDirection, Data);
1432          }          }
1433    
1434          if (MotionFlags & PMV_USESQUARES16)          if (MotionFlags & PMV_USESQUARES16) MainSearchPtr = SquareSearch;
1435                  MainSearchPtr = SquareSearch;          else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamondSearch;  
1436                  else MainSearchPtr = DiamondSearch;                  else MainSearchPtr = DiamondSearch;
1437    
1438          (*MainSearchPtr)(currentMV.x, currentMV.y, &Data, 255);          (*MainSearchPtr)(Data->currentMV->x, Data->currentMV->y, Data, iDirection);
1439    
1440          if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(&Data);          SubpelRefine(Data);
1441    
1442            if (Data->qpel && *Data->iMinSAD < *best_sad + 300) {
1443                    Data->currentQMV->x = 2*Data->currentMV->x;
1444                    Data->currentQMV->y = 2*Data->currentMV->y;
1445                    Data->qpel_precision = 1;
1446                    get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1447                                            pParam->width, pParam->height, iFcode, 1, 0);
1448                    SubpelRefine(Data);
1449            }
1450    
1451  // three bits are needed to code backward mode. four for forward  // three bits are needed to code backward mode. four for forward
 // we treat the bits just like they were vector's  
         if (mode_current == MODE_FORWARD) iMinSAD +=  4 * lambda_vec16[iQuant];  
         else iMinSAD +=  3 * lambda_vec16[iQuant];  
1452    
1453            if (mode_current == MODE_FORWARD) *Data->iMinSAD += 4 * Data->lambda16;
1454            else *Data->iMinSAD += 3 * Data->lambda16;
1455    
1456          if (iMinSAD < *best_sad) {          if (*Data->iMinSAD < *best_sad) {
1457                  *best_sad = iMinSAD;                  *best_sad = *Data->iMinSAD;
1458                  pMB->mode = mode_current;                  pMB->mode = mode_current;
1459                  pMB->pmvs[0].x = currentMV.x - predMV->x;                  if (Data->qpel) {
1460                  pMB->pmvs[0].y = currentMV.y - predMV->y;                          pMB->pmvs[0].x = Data->currentQMV->x - predMV->x;
1461                  if (mode_current == MODE_FORWARD) pMB->mvs[0] = currentMV;                          pMB->pmvs[0].y = Data->currentQMV->y - predMV->y;
1462                  else pMB->b_mvs[0] = currentMV;                          if (mode_current == MODE_FORWARD)
1463                                    pMB->qmvs[0] = *Data->currentQMV;
1464                            else
1465                                    pMB->b_qmvs[0] = *Data->currentQMV;
1466                    } else {
1467                            pMB->pmvs[0].x = Data->currentMV->x - predMV->x;
1468                            pMB->pmvs[0].y = Data->currentMV->y - predMV->y;
1469                    }
1470                    if (mode_current == MODE_FORWARD) pMB->mvs[0] = *Data->currentMV;
1471                    else pMB->b_mvs[0] = *Data->currentMV;
1472          }          }
1473    
1474            if (mode_current == MODE_FORWARD) *(Data->currentMV+2) = *Data->currentMV;
1475            else *(Data->currentMV+1) = *Data->currentMV; //we store currmv for interpolate search
1476  }  }
1477    
1478  static int32_t  static void
1479  SearchDirect(const uint8_t * const f_Ref,  SkipDecisionB(const IMAGE * const pCur,
1480                                    const IMAGE * const f_Ref,
1481                                    const IMAGE * const b_Ref,
1482                                    MACROBLOCK * const pMB,
1483                                    const uint32_t x, const uint32_t y,
1484                                    const SearchData * const Data)
1485    {
1486            int dx = 0, dy = 0, b_dx = 0, b_dy = 0;
1487            int32_t sum;
1488            const int div = 1 + Data->qpel;
1489            int k;
1490            const uint32_t stride = Data->iEdgedWidth/2;
1491    //this is not full chroma compensation, only it's fullpel approximation. should work though
1492    
1493            for (k = 0; k < 4; k++) {
1494                    dy += Data->directmvF[k].y / div;
1495                    dx += Data->directmvF[0].x / div;
1496                    b_dy += Data->directmvB[0].y / div;
1497                    b_dx += Data->directmvB[0].x / div;
1498            }
1499    
1500            dy = (dy >> 3) + roundtab_76[dy & 0xf];
1501            dx = (dx >> 3) + roundtab_76[dx & 0xf];
1502            b_dy = (b_dy >> 3) + roundtab_76[b_dy & 0xf];
1503            b_dx = (b_dx >> 3) + roundtab_76[b_dx & 0xf];
1504    
1505            sum = sad8bi(pCur->u + 8 * x + 8 * y * stride,
1506                                            f_Ref->u + (y*8 + dy/2) * stride + x*8 + dx/2,
1507                                            b_Ref->u + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1508                                            stride);
1509    
1510            if (sum >= 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) return; //no skip
1511    
1512            sum += sad8bi(pCur->v + 8*x + 8 * y * stride,
1513                                            f_Ref->v + (y*8 + dy/2) * stride + x*8 + dx/2,
1514                                            b_Ref->v + (y*8 + b_dy/2) * stride + x*8 + b_dx/2,
1515                                            stride);
1516    
1517            if (sum < 2 * MAX_CHROMA_SAD_FOR_SKIP * pMB->quant) pMB->mode = MODE_DIRECT_NONE_MV; //skipped
1518    }
1519    
1520    static __inline uint32_t
1521    SearchDirect(const IMAGE * const f_Ref,
1522                                  const uint8_t * const f_RefH,                                  const uint8_t * const f_RefH,
1523                                  const uint8_t * const f_RefV,                                  const uint8_t * const f_RefV,
1524                                  const uint8_t * const f_RefHV,                                  const uint8_t * const f_RefHV,
1525                                  const uint8_t * const b_Ref,                                  const IMAGE * const b_Ref,
1526                                  const uint8_t * const b_RefH,                                  const uint8_t * const b_RefH,
1527                                  const uint8_t * const b_RefV,                                  const uint8_t * const b_RefV,
1528                                  const uint8_t * const b_RefHV,                                  const uint8_t * const b_RefHV,
1529                                  const IMAGE * const pCur,                                  const IMAGE * const pCur,
1530                                  const int x, const int y,                                  const int x, const int y,
1531                                  const uint32_t MotionFlags,                                  const uint32_t MotionFlags,
                                 const uint32_t iQuant,  
1532                                  const int32_t TRB, const int32_t TRD,                                  const int32_t TRB, const int32_t TRD,
1533                                  const MBParam * const pParam,                                  const MBParam * const pParam,
1534                                  MACROBLOCK * const pMB,                                  MACROBLOCK * const pMB,
1535                                  const MACROBLOCK * const b_mb,                                  const MACROBLOCK * const b_mb,
1536                                  int32_t * const best_sad)                                  int32_t * const best_sad,
1537                                    SearchData * const Data)
1538    
1539  {  {
1540          const uint32_t iEdgedWidth = pParam->edged_width;          int32_t skip_sad;
1541          int32_t iMinSAD = 0, skip_sad;          int k = (x + Data->iEdgedWidth*y) * 16;
         int k;  
         VECTOR currentMV;  
1542          MainSearchFunc *MainSearchPtr;          MainSearchFunc *MainSearchPtr;
         SearchData Data;  
1543    
1544          Data.iMinSAD = &iMinSAD;          *Data->iMinSAD = 256*4096;
1545          Data.Cur = pCur->y + x * 16 + y * 16 * iEdgedWidth;          Data->Ref = f_Ref->y + k;
1546          Data.iEdgedWidth = iEdgedWidth;          Data->RefH = f_RefH + k;
1547          Data.currentMV = &currentMV;          Data->RefV = f_RefV + k;
1548          Data.iQuant = iQuant;          Data->RefHV = f_RefHV + k;
1549          Data.referencemv = b_mb->mvs;          Data->bRef = b_Ref->y + k;
1550            Data->bRefH = b_RefH + k;
1551          Data.Ref= f_Ref + (x + iEdgedWidth*y) * 16;          Data->bRefV = b_RefV + k;
1552          Data.RefH = f_RefH + (x + iEdgedWidth*y) * 16;          Data->bRefHV = b_RefHV + k;
1553          Data.RefV = f_RefV + (x + iEdgedWidth*y) * 16;          Data->RefCU = f_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1554          Data.RefHV = f_RefHV + (x + iEdgedWidth*y) * 16;          Data->RefCV = f_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1555          Data.bRef = b_Ref + (x + iEdgedWidth*y) * 16;          Data->b_RefCU = b_Ref->u + (x + (Data->iEdgedWidth/2) * y) * 8;
1556          Data.bRefH = b_RefH + (x + iEdgedWidth*y) * 16;          Data->b_RefCV = b_Ref->v + (x + (Data->iEdgedWidth/2) * y) * 8;
1557          Data.bRefV = b_RefV + (x + iEdgedWidth*y) * 16;  
1558          Data.bRefHV = b_RefHV + (x + iEdgedWidth*y) * 16;          k = Data->qpel ? 4 : 2;
1559  /*          Data->max_dx = k * (pParam->width - x * 16);
1560  //What we do here is a complicated version of CheckCandidateDirect(0,0);          Data->max_dy = k * (pParam->height - y * 16);
1561  get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 16, pParam->width, pParam->height, 19);          Data->min_dx = -k * (16 + x * 16);
1562            Data->min_dy = -k * (16 + y * 16);
1563    
1564  */          Data->referencemv = Data->qpel ? b_mb->qmvs : b_mb->mvs;
1565          Data.max_dx = 2 * pParam->width - 2 * (x) * 16;          Data->qpel_precision = 0;
         Data.max_dy = 2 * pParam->height - 2 * (y) * 16;  
         Data.min_dx = -(2 * 16 + 2 * (x) * 16);  
         Data.min_dy = -(2 * 16 + 2 * (y) * 16);  
1566    
1567          for (k = 0; k < 4; k++) {          for (k = 0; k < 4; k++) {
1568                  pMB->mvs[k].x = Data.directmvF[k].x = ((TRB * Data.referencemv[k].x) / TRD);                  pMB->mvs[k].x = Data->directmvF[k].x = ((TRB * Data->referencemv[k].x) / TRD);
1569                  pMB->b_mvs[k].x = Data.directmvB[k].x = ((TRB - TRD) * Data.referencemv[k].x) / TRD;                  pMB->b_mvs[k].x = Data->directmvB[k].x = ((TRB - TRD) * Data->referencemv[k].x) / TRD;
1570                  pMB->mvs[k].y = Data.directmvF[k].y = ((TRB * Data.referencemv[k].y) / TRD);                  pMB->mvs[k].y = Data->directmvF[k].y = ((TRB * Data->referencemv[k].y) / TRD);
1571                  pMB->b_mvs[k].y = Data.directmvB[k].y = ((TRB - TRD) * Data.referencemv[k].y) / TRD;                  pMB->b_mvs[k].y = Data->directmvB[k].y = ((TRB - TRD) * Data->referencemv[k].y) / TRD;
   
         if (( pMB->mvs[k].x > Data.max_dx ) || ( pMB->mvs[k].x < Data.min_dx )  
                         || ( pMB->mvs[k].y > Data.max_dy ) || ( pMB->mvs[k].y < Data.min_dy )  
                         || ( pMB->b_mvs[k].x > Data.max_dx ) || ( pMB->b_mvs[k].x < Data.min_dx )  
                         || ( pMB->b_mvs[k].y > Data.max_dy ) || ( pMB->b_mvs[k].y < Data.min_dy )) {  
 /*  
                 fprintf(debug, "\nERROR - out of range : vector %d,%d and %d,%d\n", pMB->mvs[k].x, pMB->mvs[k].y,pMB->b_mvs[k].x,pMB->b_mvs[k].y );  
                 fprintf(debug, " range is x: %d..%d y: %d..%d \n", Data.min_dx,Data.max_dx,Data.min_dy,Data.max_dy);  
                 fprintf(debug,"macroblock %d, %d \n", x, y);  
                 fprintf(debug, "direct MV is %d,%d \n", directmv[k].x, directmv[k].y);  
 */  
                 *best_sad = 256*4096; // in that case, we won't use direct mode  
                 pMB->mode = MODE_DIRECT; // just to make sure it doesn't say "MODE_DIRECT_NONE_MV"  
                 pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;  /* because backwards and interpol might rely on this */  
                 return 0; }  
1572    
1573                    if ( (pMB->b_mvs[k].x > Data->max_dx) | (pMB->b_mvs[k].x < Data->min_dx)
1574                            | (pMB->b_mvs[k].y > Data->max_dy) | (pMB->b_mvs[k].y < Data->min_dy) ) {
1575    
1576                            *best_sad = 256*4096; // in that case, we won't use direct mode
1577                            pMB->mode = MODE_DIRECT; // just to make sure it doesn't say "MODE_DIRECT_NONE_MV"
1578                            pMB->b_mvs[0].x = pMB->b_mvs[0].y = 0;
1579                            return 256*4096;
1580                    }
1581          if (b_mb->mode != MODE_INTER4V) {          if (b_mb->mode != MODE_INTER4V) {
1582                  iMinSAD = sad16bi(Data.Cur,                          pMB->mvs[1] = pMB->mvs[2] = pMB->mvs[3] = pMB->mvs[0];
1583                                                  get_ref_mv(f_Ref, f_RefH, f_RefV, f_RefHV,                          pMB->b_mvs[1] = pMB->b_mvs[2] = pMB->b_mvs[3] = pMB->b_mvs[0];
1584                                                                  x, y, 16, &pMB->mvs[0], iEdgedWidth),                          Data->directmvF[1] = Data->directmvF[2] = Data->directmvF[3] = Data->directmvF[0];
1585                                                  get_ref_mv(b_Ref, b_RefH, b_RefV, b_RefHV,                          Data->directmvB[1] = Data->directmvB[2] = Data->directmvB[3] = Data->directmvB[0];
1586                                                                  x, y, 16, &pMB->b_mvs[0], iEdgedWidth), iEdgedWidth);                          break;
   
                 Data.directmvF[1] = Data.directmvF[2] = Data.directmvF[3] = Data.directmvF[0];  
                 Data.directmvB[1] = Data.directmvB[2] = Data.directmvB[3] = Data.directmvB[0];  
                 break;  
         }  
         iMinSAD += sad8bi(Data.Cur + (k&1)*8 + (k>>1)* 8 * iEdgedWidth,  
                                                 get_ref_mv(f_Ref, f_RefH, f_RefV, f_RefHV,  
                                                                 (2*x+(k&1)), (2*y+(k>>1)), 8, &pMB->mvs[k], iEdgedWidth),  
                                                 get_ref_mv(b_Ref, b_RefH, b_RefV, b_RefHV,  
                                                                 (2*x+(k&1)), (2*y+(k>>1)), 8, &pMB->b_mvs[k], iEdgedWidth),  
                                                 iEdgedWidth);  
1587          }          }
1588            }
1589    
1590            CheckCandidate = b_mb->mode == MODE_INTER4V ? CheckCandidateDirect : CheckCandidateDirectno4v;
1591    
1592  // skip decision          CheckCandidate(0, 0, 255, &k, Data);
1593          if (iMinSAD < (int32_t)iQuant * SKIP_THRESH_B) {  
1594    // initial (fast) skip decision
1595            if (*Data->iMinSAD < pMB->quant * INITIAL_SKIP_THRESH * (2 + Data->chroma?1:0)) {
1596                    //possible skip
1597                    if (Data->chroma) {
1598                  pMB->mode = MODE_DIRECT_NONE_MV;                  pMB->mode = MODE_DIRECT_NONE_MV;
1599                  return iMinSAD; }                          return *Data->iMinSAD; // skip.
1600                    } else {
1601                            SkipDecisionB(pCur, f_Ref, b_Ref, pMB, x, y, Data);
1602                            if (pMB->mode == MODE_DIRECT_NONE_MV) return *Data->iMinSAD; // skip.
1603                    }
1604            }
1605    
1606          skip_sad = iMinSAD;          skip_sad = *Data->iMinSAD;
         iMinSAD += 2 * lambda_vec16[iQuant]; // 2 bits needed to code vector 0,0  
         currentMV.x = currentMV.y = 0;  
         if (b_mb->mode == MODE_INTER4V)  
                 CheckCandidate = CheckCandidateDirect;  
         else CheckCandidate = CheckCandidateDirectno4v;  
1607    
1608  //  DIRECT MODE DELTA VECTOR SEARCH.  //  DIRECT MODE DELTA VECTOR SEARCH.
1609  //      This has to be made more effective, but at the moment I'm happy it's running at all  //      This has to be made more effective, but at the moment I'm happy it's running at all
# Line 1123  Line 1612 
1612                  else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;                  else if (MotionFlags & PMV_ADVANCEDDIAMOND16) MainSearchPtr = AdvDiamondSearch;
1613                          else MainSearchPtr = DiamondSearch;                          else MainSearchPtr = DiamondSearch;
1614    
1615          (*MainSearchPtr)(0, 0, &Data, 255);          (*MainSearchPtr)(0, 0, Data, 255);
1616    
1617          HalfpelRefine(&Data);          SubpelRefine(Data);
1618    
1619          iMinSAD +=  1 * lambda_vec16[iQuant]; // one bit is needed to code direct mode. we treat this bit just like it was vector's          *best_sad = *Data->iMinSAD;
         *best_sad = iMinSAD;  
1620    
1621          if (b_mb->mode == MODE_INTER4V)          if (Data->qpel || b_mb->mode == MODE_INTER4V) pMB->mode = MODE_DIRECT;
                 pMB->mode = MODE_DIRECT;  
1622          else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation          else pMB->mode = MODE_DIRECT_NO4V; //for faster compensation
1623    
1624          pMB->pmvs[3] = currentMV;          pMB->pmvs[3] = *Data->currentMV;
1625    
1626          for (k = 0; k < 4; k++) {          for (k = 0; k < 4; k++) {
1627                  pMB->mvs[k].x = Data.directmvF[k].x + currentMV.x;                  pMB->mvs[k].x = Data->directmvF[k].x + Data->currentMV->x;
1628                  pMB->b_mvs[k].x = ((currentMV.x == 0)                  pMB->b_mvs[k].x = (     (Data->currentMV->x == 0)
1629                                                          ? Data.directmvB[k].x                                                          ? Data->directmvB[k].x
1630                                                          : pMB->mvs[k].x - Data.referencemv[k].x);                                                          :pMB->mvs[k].x - Data->referencemv[k].x);
1631                  pMB->mvs[k].y = (Data.directmvF[k].y + currentMV.y);                  pMB->mvs[k].y = (Data->directmvF[k].y + Data->currentMV->y);
1632                  pMB->b_mvs[k].y = ((currentMV.y == 0)                  pMB->b_mvs[k].y = ((Data->currentMV->y == 0)
1633                                                          ? Data.directmvB[k].y                                                          ? Data->directmvB[k].y
1634                                                          : pMB->mvs[k].y - Data.referencemv[k].y);                                                          : pMB->mvs[k].y - Data->referencemv[k].y);
1635                    if (Data->qpel) {
1636                            pMB->qmvs[k].x = pMB->mvs[k].x; pMB->mvs[k].x /= 2;
1637                            pMB->b_qmvs[k].x = pMB->b_mvs[k].x; pMB->b_mvs[k].x /= 2;
1638                            pMB->qmvs[k].y = pMB->mvs[k].y; pMB->mvs[k].y /= 2;
1639                            pMB->b_qmvs[k].y = pMB->b_mvs[k].y; pMB->b_mvs[k].y /= 2;
1640                    }
1641    
1642                  if (b_mb->mode != MODE_INTER4V) {                  if (b_mb->mode != MODE_INTER4V) {
1643                          pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];                          pMB->mvs[3] = pMB->mvs[2] = pMB->mvs[1] = pMB->mvs[0];
1644                          pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];                          pMB->b_mvs[3] = pMB->b_mvs[2] = pMB->b_mvs[1] = pMB->b_mvs[0];
1645                            pMB->qmvs[3] = pMB->qmvs[2] = pMB->qmvs[1] = pMB->qmvs[0];
1646                            pMB->b_qmvs[3] = pMB->b_qmvs[2] = pMB->b_qmvs[1] = pMB->b_qmvs[0];
1647                          break;                          break;
1648                  }                  }
1649          }          }
1650          return 0;//skip_sad;          return skip_sad;
1651  }  }
1652    
1653  static __inline void  static void
1654  SearchInterpolate(const uint8_t * const f_Ref,  SearchInterpolate(const IMAGE * const f_Ref,
1655                                  const uint8_t * const f_RefH,                                  const uint8_t * const f_RefH,
1656                                  const uint8_t * const f_RefV,                                  const uint8_t * const f_RefV,
1657                                  const uint8_t * const f_RefHV,                                  const uint8_t * const f_RefHV,
1658                                  const uint8_t * const b_Ref,                                  const IMAGE * const b_Ref,
1659                                  const uint8_t * const b_RefH,                                  const uint8_t * const b_RefH,
1660                                  const uint8_t * const b_RefV,                                  const uint8_t * const b_RefV,
1661                                  const uint8_t * const b_RefHV,                                  const uint8_t * const b_RefHV,
# Line 1168  Line 1664 
1664                                  const uint32_t fcode,                                  const uint32_t fcode,
1665                                  const uint32_t bcode,                                  const uint32_t bcode,
1666                                  const uint32_t MotionFlags,                                  const uint32_t MotionFlags,
                                 const uint32_t iQuant,  
1667                                  const MBParam * const pParam,                                  const MBParam * const pParam,
1668                                  const VECTOR * const f_predMV,                                  const VECTOR * const f_predMV,
1669                                  const VECTOR * const b_predMV,                                  const VECTOR * const b_predMV,
1670                                  MACROBLOCK * const pMB,                                  MACROBLOCK * const pMB,
1671                                  int32_t * const best_sad)                                  int32_t * const best_sad,
1672                                    SearchData * const fData)
1673    
1674  {  {
 /* 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". */  
   
         const int32_t iEdgedWidth = pParam->edged_width;  
1675    
1676          int iDirection, i, j;          int iDirection, i, j;
1677          int32_t iMinSAD = 256*4096;          SearchData bData;
         VECTOR currentMV[3];  
         SearchData fData, bData;  
   
   
         fData.iMinSAD = bData.iMinSAD = &iMinSAD;  
   
         fData.Cur = bData.Cur = pCur->y + (x + y * iEdgedWidth) * 16;  
         fData.iEdgedWidth = bData.iEdgedWidth = iEdgedWidth;  
         fData.currentMV = currentMV; bData.currentMV = currentMV + 1;  
         fData.iQuant = bData.iQuant = iQuant;  
         fData.iFcode = bData.bFcode = fcode; fData.bFcode = bData.iFcode = bcode;  
   
   
         bData.bRef = fData.Ref = f_Ref + (x + y * iEdgedWidth) * 16;  
         bData.bRefH = fData.RefH = f_RefH + (x + y * iEdgedWidth) * 16;  
         bData.bRefV = fData.RefV = f_RefV + (x + y * iEdgedWidth) * 16;  
         bData.bRefHV = fData.RefHV = f_RefHV + (x + y * iEdgedWidth) * 16;  
         bData.Ref = fData.bRef = b_Ref + (x + y * iEdgedWidth) * 16;  
         bData.RefH = fData.bRefH = b_RefH + (x + y * iEdgedWidth) * 16;  
         bData.RefV = fData.bRefV = b_RefV + (x + y * iEdgedWidth) * 16;  
         bData.RefHV = fData.bRefHV = b_RefHV + (x + y * iEdgedWidth) * 16;  
   
         bData.bpredMV = fData.predMV = *f_predMV;  
         fData.bpredMV = bData.predMV = *b_predMV;  
1678    
1679            fData->qpel_precision = 0;
1680            memcpy(&bData, fData, sizeof(SearchData)); //quick copy of common data
1681            *fData->iMinSAD = 4096*256;
1682            bData.currentMV++; bData.currentQMV++;
1683            fData->iFcode = bData.bFcode = fcode; fData->bFcode = bData.iFcode = bcode;
1684    
1685            i = (x + y * fData->iEdgedWidth) * 16;
1686            bData.bRef = fData->Ref = f_Ref->y + i;
1687            bData.bRefH = fData->RefH = f_RefH + i;
1688            bData.bRefV = fData->RefV = f_RefV + i;
1689            bData.bRefHV = fData->RefHV = f_RefHV + i;
1690            bData.Ref = fData->bRef = b_Ref->y + i;
1691            bData.RefH = fData->bRefH = b_RefH + i;
1692            bData.RefV = fData->bRefV = b_RefV + i;
1693            bData.RefHV = fData->bRefHV = b_RefHV + i;
1694            bData.b_RefCU = fData->RefCU = f_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
1695            bData.b_RefCV = fData->RefCV = f_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
1696            bData.RefCU = fData->b_RefCU = b_Ref->u + (x + (fData->iEdgedWidth/2) * y) * 8;
1697            bData.RefCV = fData->b_RefCV = b_Ref->v + (x + (fData->iEdgedWidth/2) * y) * 8;
1698    
1699    
1700            bData.bpredMV = fData->predMV = *f_predMV;
1701            fData->bpredMV = bData.predMV = *b_predMV;
1702            fData->currentMV[0] = fData->currentMV[2];
1703    
1704            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);
1705            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);
1706    
1707            if (fData->currentMV[0].x > fData->max_dx) fData->currentMV[0].x = fData->max_dx;
1708            if (fData->currentMV[0].x < fData->min_dx) fData->currentMV[0].x = fData->min_dx;
1709            if (fData->currentMV[0].y > fData->max_dy) fData->currentMV[0].y = fData->max_dy;
1710            if (fData->currentMV[0].y < fData->min_dy) fData->currentMV[0].y = fData->min_dy;
1711    
1712            if (fData->currentMV[1].x > bData.max_dx) fData->currentMV[1].x = bData.max_dx;
1713            if (fData->currentMV[1].x < bData.min_dx) fData->currentMV[1].x = bData.min_dx;
1714            if (fData->currentMV[1].y > bData.max_dy) fData->currentMV[1].y = bData.max_dy;
1715            if (fData->currentMV[1].y < bData.min_dy) fData->currentMV[1].y = bData.min_dy;
1716    
1717          currentMV[0] = pMB->mvs[0];          CheckCandidateInt(fData->currentMV[0].x, fData->currentMV[0].y, 255, &iDirection, fData);
         currentMV[1] = pMB->b_mvs[0];  
         get_range(&fData.min_dx, &fData.max_dx, &fData.min_dy, &fData.max_dy, x, y, 16, pParam->width, pParam->height, fcode);  
         get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode);  
   
         CheckCandidateInt(currentMV[0].x, currentMV[0].y, 255, &iDirection, &fData);  
   
 //diamond. I wish we could use normal mainsearch functions (square, advdiamond)  
1718    
1719    //diamond
1720          do {          do {
1721                  iDirection = 255;                  iDirection = 255;
1722                  // forward MV moves                  // forward MV moves
1723                  i = currentMV[0].x; j = currentMV[0].y;                  i = fData->currentMV[0].x; j = fData->currentMV[0].y;
1724    
1725                  CheckCandidateInt(i + 2, j, 0, &iDirection, &fData);                  CheckCandidateInt(i + 1, j, 0, &iDirection, fData);
1726                  CheckCandidateInt(i, j + 2, 0, &iDirection, &fData);                  CheckCandidateInt(i, j + 1, 0, &iDirection, fData);
1727                  CheckCandidateInt(i - 2, j, 0, &iDirection, &fData);                  CheckCandidateInt(i - 1, j, 0, &iDirection, fData);
1728                  CheckCandidateInt(i, j - 2, 0, &iDirection, &fData);                  CheckCandidateInt(i, j - 1, 0, &iDirection, fData);
1729    
1730                  // backward MV moves                  // backward MV moves
1731                  i = currentMV[1].x; j = currentMV[1].y;                  i = fData->currentMV[1].x; j = fData->currentMV[1].y;
1732                  currentMV[2] = currentMV[0];                  fData->currentMV[2] = fData->currentMV[0];
1733                    CheckCandidateInt(i + 1, j, 0, &iDirection, &bData);
1734                  CheckCandidateInt(i + 2, j, 0, &iDirection, &bData);                  CheckCandidateInt(i, j + 1, 0, &iDirection, &bData);
1735                  CheckCandidateInt(i, j + 2, 0, &iDirection, &bData);                  CheckCandidateInt(i - 1, j, 0, &iDirection, &bData);
1736                  CheckCandidateInt(i - 2, j, 0, &iDirection, &bData);                  CheckCandidateInt(i, j - 1, 0, &iDirection, &bData);
                 CheckCandidateInt(i, j - 2, 0, &iDirection, &bData);  
1737    
1738          } while (!(iDirection));          } while (!(iDirection));
1739    
1740  /* halfpel refinement. luckly we can use normal halfpel function for it */  //qpel refinement
1741            if (fData->qpel) {
1742          if (MotionFlags & PMV_HALFPELREFINE16) {                  if (*fData->iMinSAD > *best_sad + 500) return;
1743                  CheckCandidate = CheckCandidateInt;                  CheckCandidate = CheckCandidateInt;
1744                  HalfpelRefine(&fData);                  fData->qpel_precision = bData.qpel_precision = 1;
1745                  currentMV[2] = currentMV[0];                  get_range(&fData->min_dx, &fData->max_dx, &fData->min_dy, &fData->max_dy, x, y, 16, pParam->width, pParam->height, fcode, 1, 0);
1746                  HalfpelRefine(&bData);                  get_range(&bData.min_dx, &bData.max_dx, &bData.min_dy, &bData.max_dy, x, y, 16, pParam->width, pParam->height, bcode, 1, 0);
1747          }                  fData->currentQMV[2].x = fData->currentQMV[0].x = 2 * fData->currentMV[0].x;
1748                    fData->currentQMV[2].y = fData->currentQMV[0].y = 2 * fData->currentMV[0].y;
1749  // two bits are needed to code interpolate mode. we treat the bits just like they were vector's                  fData->currentQMV[1].x = 2 * fData->currentMV[1].x;
1750          iMinSAD +=  2 * lambda_vec16[iQuant];                  fData->currentQMV[1].y = 2 * fData->currentMV[1].y;
1751          if (iMinSAD < *best_sad) {                  SubpelRefine(fData);
1752                  *best_sad = iMinSAD;                  if (*fData->iMinSAD > *best_sad + 300) return;
1753                  pMB->mvs[0] = currentMV[0];                  fData->currentQMV[2] = fData->currentQMV[0];
1754                  pMB->b_mvs[0] = currentMV[1];                  SubpelRefine(&bData);
1755            }
1756    
1757            *fData->iMinSAD += (2+3) * fData->lambda16; // two bits are needed to code interpolate mode.
1758    
1759            if (*fData->iMinSAD < *best_sad) {
1760                    *best_sad = *fData->iMinSAD;
1761                    pMB->mvs[0] = fData->currentMV[0];
1762                    pMB->b_mvs[0] = fData->currentMV[1];
1763                  pMB->mode = MODE_INTERPOLATE;                  pMB->mode = MODE_INTERPOLATE;
1764                    if (fData->qpel) {
1765                            pMB->qmvs[0] = fData->currentQMV[0];
1766                            pMB->b_qmvs[0] = fData->currentQMV[1];
1767                            pMB->pmvs[1].x = pMB->qmvs[0].x - f_predMV->x;
1768                            pMB->pmvs[1].y = pMB->qmvs[0].y - f_predMV->y;
1769                            pMB->pmvs[0].x = pMB->b_qmvs[0].x - b_predMV->x;
1770                            pMB->pmvs[0].y = pMB->b_qmvs[0].y - b_predMV->y;
1771                    } else {
1772                  pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;                  pMB->pmvs[1].x = pMB->mvs[0].x - f_predMV->x;
1773                  pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;                  pMB->pmvs[1].y = pMB->mvs[0].y - f_predMV->y;
1774                  pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;                  pMB->pmvs[0].x = pMB->b_mvs[0].x - b_predMV->x;
1775                  pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;                  pMB->pmvs[0].y = pMB->b_mvs[0].y - b_predMV->y;
1776          }          }
1777  }  }
1778    }
1779    
1780  void  void
1781  MotionEstimationBVOP(MBParam * const pParam,  MotionEstimationBVOP(MBParam * const pParam,
# Line 1277  Line 1789 
1789                                           const IMAGE * const f_refV,                                           const IMAGE * const f_refV,
1790                                           const IMAGE * const f_refHV,                                           const IMAGE * const f_refHV,
1791                                           // backward (future) reference                                           // backward (future) reference
1792                                           const MACROBLOCK * const b_mbs,                                           const FRAMEINFO * const b_reference,
1793                                           const IMAGE * const b_ref,                                           const IMAGE * const b_ref,
1794                                           const IMAGE * const b_refH,                                           const IMAGE * const b_refH,
1795                                           const IMAGE * const b_refV,                                           const IMAGE * const b_refV,
1796                                           const IMAGE * const b_refHV)                                           const IMAGE * const b_refHV)
1797  {  {
1798          uint32_t i, j;          uint32_t i, j;
1799          int32_t best_sad, skip_sad;          int32_t best_sad;
1800            uint32_t skip_sad;
1801          int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;          int f_count = 0, b_count = 0, i_count = 0, d_count = 0, n_count = 0;
1802          static const VECTOR zeroMV={0,0};          const MACROBLOCK * const b_mbs = b_reference->mbs;
1803    
1804          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/          VECTOR f_predMV, b_predMV;      /* there is no prediction for direct mode*/
1805    
1806          const int32_t TRB = time_pp - time_bp;          const int32_t TRB = time_pp - time_bp;
1807          const int32_t TRD = time_pp;          const int32_t TRD = time_pp;
1808    
1809          // note: i==horizontal, j==vertical  // some pre-inintialized data for the rest of the search
1810    
1811            SearchData Data;
1812            int32_t iMinSAD;
1813            VECTOR currentMV[3];
1814            VECTOR currentQMV[3];
1815            int32_t temp[8];
1816            memset(&Data, 0, sizeof(SearchData));
1817            Data.iEdgedWidth = pParam->edged_width;
1818            Data.currentMV = currentMV; Data.currentQMV = currentQMV;
1819            Data.iMinSAD = &iMinSAD;
1820            Data.lambda16 = lambda_vec16[frame->quant];
1821            Data.qpel = pParam->m_quarterpel;
1822            Data.rounding = 0;
1823            Data.chroma = frame->motion_flags & PMV_CHROMA8;
1824            Data.temp = temp;
1825    
1826            Data.RefQ = f_refV->u; // a good place, also used in MC (for similar purpose)
1827            // note: i==horizontal, j==vertical
1828          for (j = 0; j < pParam->mb_height; j++) {          for (j = 0; j < pParam->mb_height; j++) {
1829    
1830                  f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */                  f_predMV = b_predMV = zeroMV;   /* prediction is reset at left boundary */
# Line 1303  Line 1833 
1833                          MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;                          MACROBLOCK * const pMB = frame->mbs + i + j * pParam->mb_width;
1834                          const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;                          const MACROBLOCK * const b_mb = b_mbs + i + j * pParam->mb_width;
1835    
1836  /* special case, if collocated block is SKIPed: encoding is forward (0,0), cpb=0 without further ado */  /* special case, if collocated block is SKIPed in P-VOP: encoding is forward (0,0), cpb=0 without further ado */
1837                            if (b_reference->coding_type != S_VOP)
1838                          if (b_mb->mode == MODE_NOT_CODED) {                          if (b_mb->mode == MODE_NOT_CODED) {
1839                                  pMB->mode = MODE_NOT_CODED;                                  pMB->mode = MODE_NOT_CODED;
1840                                  continue;                                  continue;
1841                          }                          }
1842    
1843                            Data.Cur = frame->image.y + (j * Data.iEdgedWidth + i) * 16;
1844                            Data.CurU = frame->image.u + (j * Data.iEdgedWidth/2 + i) * 8;
1845                            Data.CurV = frame->image.v + (j * Data.iEdgedWidth/2 + i) * 8;
1846                            pMB->quant = frame->quant;
1847    
1848  /* direct search comes first, because it (1) checks for SKIP-mode  /* direct search comes first, because it (1) checks for SKIP-mode
1849          and (2) sets very good predictions for forward and backward search */          and (2) sets very good predictions for forward and backward search */
1850                            skip_sad = SearchDirect(f_ref, f_refH->y, f_refV->y, f_refHV->y,
1851                          skip_sad = SearchDirect(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,                                                                          b_ref, b_refH->y, b_refV->y, b_refHV->y,
                                                                         b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
1852                                                                          &frame->image,                                                                          &frame->image,
1853                                                                          i, j,                                                                          i, j,
1854                                                                          frame->motion_flags,                                                                          frame->motion_flags,
                                                                         frame->quant,  
1855                                                                          TRB, TRD,                                                                          TRB, TRD,
1856                                                                          pParam,                                                                          pParam,
1857                                                                          pMB, b_mb,                                                                          pMB, b_mb,
1858                                                                          &best_sad);                                                                          &best_sad,
1859                                                                            &Data);
1860    
                         if (!(frame->global_flags & XVID_HALFPEL)) best_sad = skip_sad = 256*4096;  
                         else  
1861                                  if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }                                  if (pMB->mode == MODE_DIRECT_NONE_MV) { n_count++; continue; }
1862    
 //                      best_sad = 256*4096; //uncomment to disable Directsearch.  
 //      To disable any other mode, just comment the function call  
   
1863                          // forward search                          // forward search
1864                          SearchBF(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,                          SearchBF(f_ref, f_refH->y, f_refV->y, f_refHV->y,
1865                                                  &frame->image, i, j,                                                  &frame->image, i, j,
1866                                                  frame->motion_flags,                                                  frame->motion_flags,
1867                                                  frame->quant, frame->fcode, pParam,                                                  frame->fcode, pParam,
1868                                                  pMB, &f_predMV, &best_sad,                                                  pMB, &f_predMV, &best_sad,
1869                                                  MODE_FORWARD);                                                  MODE_FORWARD, &Data);
1870    
1871                          // backward search                          // backward search
1872                          SearchBF(b_ref->y, b_refH->y, b_refV->y, b_refHV->y,                          SearchBF(b_ref, b_refH->y, b_refV->y, b_refHV->y,
1873                                                  &frame->image, i, j,                                                  &frame->image, i, j,
1874                                                  frame->motion_flags,                                                  frame->motion_flags,
1875                                                  frame->quant, frame->bcode, pParam,                                                  frame->bcode, pParam,
1876                                                  pMB, &b_predMV, &best_sad,                                                  pMB, &b_predMV, &best_sad,
1877                                                  MODE_BACKWARD);                                                  MODE_BACKWARD, &Data);
1878    
1879                          // interpolate search comes last, because it uses data from forward and backward as prediction                          // interpolate search comes last, because it uses data from forward and backward as prediction
1880                            SearchInterpolate(f_ref, f_refH->y, f_refV->y, f_refHV->y,
1881                          SearchInterpolate(f_ref->y, f_refH->y, f_refV->y, f_refHV->y,                                                  b_ref, b_refH->y, b_refV->y, b_refHV->y,
                                                 b_ref->y, b_refH->y, b_refV->y, b_refHV->y,  
1882                                                  &frame->image,                                                  &frame->image,
1883                                                  i, j,                                                  i, j,
1884                                                  frame->fcode, frame->bcode,                                                  frame->fcode, frame->bcode,
1885                                                  frame->motion_flags,                                                  frame->motion_flags,
1886                                                  frame->quant, pParam,                                                  pParam,
1887                                                  &f_predMV, &b_predMV,                                                  &f_predMV, &b_predMV,
1888                                                  pMB, &best_sad);                                                  pMB, &best_sad,
1889                                                    &Data);
1890    
1891    // final skip decision
1892                            if ( (skip_sad < frame->quant * MAX_SAD00_FOR_SKIP * 2)
1893                                            && ((100*best_sad)/(skip_sad+1) > FINAL_SKIP_THRESH) )
1894                                    SkipDecisionB(&frame->image, f_ref, b_ref, pMB, i, j, &Data);
1895    
1896                          switch (pMB->mode) {                          switch (pMB->mode) {
1897                                  case MODE_FORWARD:                                  case MODE_FORWARD:
1898                                          f_count++;                                          f_count++;
1899                                          f_predMV = pMB->mvs[0];                                          f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
1900                                          break;                                          break;
1901                                  case MODE_BACKWARD:                                  case MODE_BACKWARD:
1902                                          b_count++;                                          b_count++;
1903                                          b_predMV = pMB->b_mvs[0];                                          b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
1904                                          break;                                          break;
1905                                  case MODE_INTERPOLATE:                                  case MODE_INTERPOLATE:
1906                                          i_count++;                                          i_count++;
1907                                          f_predMV = pMB->mvs[0];                                          f_predMV = Data.qpel ? pMB->qmvs[0] : pMB->mvs[0];
1908                                          b_predMV = pMB->b_mvs[0];                                          b_predMV = Data.qpel ? pMB->b_qmvs[0] : pMB->b_mvs[0];
1909                                          break;                                          break;
1910                                  case MODE_DIRECT:                                  case MODE_DIRECT:
1911                                  case MODE_DIRECT_NO4V:                                  case MODE_DIRECT_NO4V:
1912                                          d_count++;                                          d_count++;
                                         break;  
1913                                  default:                                  default:
1914                                          break;                                          break;
1915                          }                          }
1916                  }                  }
1917          }          }
   
 //      fprintf(debug,"B-Stat: F: %04d   B: %04d   I: %04d  D: %04d, N: %04d\n",  
 //                              f_count,b_count,i_count,d_count,n_count);  
   
1918  }  }
1919    
 /* Hinted ME starts here */  
   
1920  static __inline void  static __inline void
1921  Search8hinted(  const SearchData * const OldData,  MEanalyzeMB (   const uint8_t * const pRef,
1922                                  const int x, const int y,                                  const uint8_t * const pCur,
1923                                  const uint32_t MotionFlags,                                  const int x,
1924                                    const int y,
1925                                  const MBParam * const pParam,                                  const MBParam * const pParam,
1926                                  MACROBLOCK * const pMB,                                  MACROBLOCK * const pMBs,
1927                                  const MACROBLOCK * const pMBs,                                  SearchData * const Data)
                                 const int block)  
1928  {  {
         SearchData Data;  
         MainSearchFunc *MainSearchPtr;  
1929    
1930          Data.predMV = get_pmv2(pMBs, pParam->mb_width, 0, x/2 , y/2, block);          int i, mask;
1931          Data.iMinSAD = OldData->iMinSAD + 1 + block;          VECTOR pmv[3];
1932          Data.currentMV = OldData->currentMV+1+block;          MACROBLOCK * pMB = &pMBs[x + y * pParam->mb_width];
1933          Data.iFcode = OldData->iFcode;  
1934          Data.iQuant = OldData->iQuant;          for (i = 0; i < 5; i++) Data->iMinSAD[i] = MV_MAX_ERROR;
   
         Data.Ref = OldData->Ref + 8 * ((block&1) + pParam->edged_width*(block>>1));  
         Data.RefH = OldData->RefH + 8 * ((block&1) + pParam->edged_width*(block>>1));  
         Data.RefV = OldData->RefV + 8 * ((block&1) + pParam->edged_width*(block>>1));  
         Data.RefHV = OldData->RefHV + 8 * ((block&1) + pParam->edged_width*(block>>1));  
         Data.iEdgedWidth = pParam->edged_width;  
         Data.Cur = OldData->Cur + 8 * ((block&1) + pParam->edged_width*(block>>1));  
1935    
1936          CheckCandidate = CheckCandidate8;          //median is only used as prediction. it doesn't have to be real
1937            if (x == 1 && y == 1) Data->predMV.x = Data->predMV.y = 0;
1938            else
1939                    if (x == 1) //left macroblock does not have any vector now
1940                            Data->predMV = (pMB - pParam->mb_width)->mvs[0]; // top instead of median
1941                    else if (y == 1) // top macroblock doesn't have it's vector
1942                            Data->predMV = (pMB - 1)->mvs[0]; // left instead of median
1943                            else Data->predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0); //else median
1944    
1945          if (block != 0)          get_range(&Data->min_dx, &Data->max_dx, &Data->min_dy, &Data->max_dy, x, y, 16,
1946                  *(Data.iMinSAD) += lambda_vec8[Data.iQuant] *                                  pParam->width, pParam->height, Data->iFcode - pParam->m_quarterpel, 0, Data->rrv);
                                                                 d_mv_bits(      Data.currentMV->x - Data.predMV.x,  
                                                                                         Data.currentMV->y - Data.predMV.y,  
                                                                                         Data.iFcode);  
1947    
1948            Data->Cur = pCur + (x + y * pParam->edged_width) * 16;
1949            Data->Ref = pRef + (x + y * pParam->edged_width) * 16;
1950    
1951          get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 8,          pmv[1].x = EVEN(pMB->mvs[0].x);
1952                                  pParam->width, pParam->height, OldData->iFcode);          pmv[1].y = EVEN(pMB->mvs[0].y);
1953            pmv[2].x = EVEN(Data->predMV.x);
1954            pmv[2].y = EVEN(Data->predMV.y);
1955            pmv[0].x = pmv[0].y = 0;
1956    
1957          if (pMB->mode == MODE_INTER4V) {          CheckCandidate32I(0, 0, 255, &i, Data);
                 int dummy;  
                 CheckCandidate8(pMB->mvs[block].x, pMB->mvs[block].y, 0, &dummy, &Data); }  
1958    
1959          if (MotionFlags & PMV_USESQUARES8) MainSearchPtr = SquareSearch;          if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP * 4) {
                 else if (MotionFlags & PMV_ADVANCEDDIAMOND8) MainSearchPtr = AdvDiamondSearch;  
                         else MainSearchPtr = DiamondSearch;  
1960    
1961          (*MainSearchPtr)(Data.currentMV->x, Data.currentMV->y, &Data, 255);                  if (!(mask = make_mask(pmv, 1)))
1962                            CheckCandidate32I(pmv[1].x, pmv[1].y, mask, &i, Data);
1963                    if (!(mask = make_mask(pmv, 2)))
1964                            CheckCandidate32I(pmv[2].x, pmv[2].y, mask, &i, Data);
1965    
1966          if (MotionFlags & PMV_HALFPELREFINE8) HalfpelRefine(&Data);                  if (*Data->iMinSAD > 4 * MAX_SAD00_FOR_SKIP * 4) // diamond only if needed
1967                            DiamondSearch(Data->currentMV->x, Data->currentMV->y, Data, i);
1968    
1969          pMB->pmvs[block].x = Data.currentMV->x - Data.predMV.x;                  for (i = 0; i < 4; i++) {
1970          pMB->pmvs[block].y = Data.currentMV->y - Data.predMV.y;                          MACROBLOCK * MB = &pMBs[x + (i&1) + (y+(i>>1)) * pParam->mb_width];
1971          pMB->mvs[block] = *(Data.currentMV);                          MB->mvs[0] = MB->mvs[1] = MB->mvs[2] = MB->mvs[3] = Data->currentMV[i];
1972          pMB->sad8[block] =  4 * (*(Data.iMinSAD));                          MB->mode = MODE_INTER;
1973                            MB->sad16 = Data->iMinSAD[i+1];
1974                    }
1975            }
1976  }  }
1977    
1978    #define INTRA_BIAS              2500
1979    #define INTRA_THRESH    1500
1980    #define INTER_THRESH    1400
1981    
1982  static void  int
1983  SearchPhinted ( const uint8_t * const pRef,  MEanalysis(     const IMAGE * const pRef,
1984                                  const uint8_t * const pRefH,                          FRAMEINFO * const Current,
1985                                  const uint8_t * const pRefV,                          MBParam * const pParam,
1986                                  const uint8_t * const pRefHV,                          int maxIntra, //maximum number if non-I frames
1987                                  const IMAGE * const pCur,                          int intraCount, //number of non-I frames after last I frame; 0 if we force P/B frame
1988                                  const int x,                          int bCount) // number of B frames in a row
                                 const int y,  
                                 const uint32_t MotionFlags,  
                                 const uint32_t iQuant,  
                                 const uint32_t iFcode,  
                                 const MBParam * const pParam,  
                                 const MACROBLOCK * const pMBs,  
                                 int inter4v,  
                                 MACROBLOCK * const pMB)  
1989  {  {
1990            uint32_t x, y, intra = 0;
1991            int sSAD = 0;
1992            MACROBLOCK * const pMBs = Current->mbs;
1993            const IMAGE * const pCurrent = &Current->image;
1994            int IntraThresh = INTRA_THRESH, InterThresh = INTER_THRESH;
1995    
1996          const int32_t iEdgedWidth = pParam->edged_width;          int32_t iMinSAD[5], temp[5];
   
         int i;  
1997          VECTOR currentMV[5];          VECTOR currentMV[5];
         int32_t iMinSAD[5];  
         int32_t temp[5];  
         MainSearchFunc * MainSearchPtr;  
1998          SearchData Data;          SearchData Data;
1999            Data.iEdgedWidth = pParam->edged_width;
         Data.predMV = get_pmv2(pMBs, pParam->mb_width, 0, x, y, 0);  
         get_range(&Data.min_dx, &Data.max_dx, &Data.min_dy, &Data.max_dy, x, y, 16,  
                                 pParam->width, pParam->height, iFcode);  
   
         Data.Cur = pCur->y + (x + y * iEdgedWidth) * 16;  
         Data.iEdgedWidth = iEdgedWidth;  
2000          Data.currentMV = currentMV;          Data.currentMV = currentMV;
2001          Data.iMinSAD = iMinSAD;          Data.iMinSAD = iMinSAD;
2002          Data.Ref = pRef + (x + iEdgedWidth*y)*16;          Data.iFcode = Current->fcode;
2003          Data.RefH = pRefH + (x + iEdgedWidth*y) * 16;          Data.rrv = Current->global_flags & XVID_REDUCED;
         Data.RefV = pRefV + (x + iEdgedWidth*y) * 16;  
         Data.RefHV = pRefHV + (x + iEdgedWidth*y) * 16;  
2004          Data.temp = temp;          Data.temp = temp;
2005          Data.iQuant = iQuant;          CheckCandidate = CheckCandidate32I;
         Data.iFcode = iFcode;  
2006    
2007          if (!(MotionFlags & PMV_HALFPEL16)) {          if (intraCount != 0 && intraCount < 10) // we're right after an I frame
2008                  Data.min_dx = EVEN(Data.min_dx);                  IntraThresh += 4 * (intraCount - 10) * (intraCount - 10);
2009                  Data.max_dx = EVEN(Data.max_dx);          else
2010                  Data.min_dy = EVEN(Data.min_dy);                  if ( 5*(maxIntra - intraCount) < maxIntra) // we're close to maximum. 2 sec when max is 10 sec
2011                  Data.max_dy = EVEN(Data.max_dy);                          IntraThresh -= (IntraThresh * (maxIntra - 5*(maxIntra - intraCount)))/maxIntra;
2012    
2013            InterThresh += 400 * (1 - bCount);
2014            if (InterThresh < 300) InterThresh = 300;
2015    
2016            if (sadInit) (*sadInit) ();
2017    
2018            for (y = 1; y < pParam->mb_height-1; y += 2) {
2019                    for (x = 1; x < pParam->mb_width-1; x += 2) {
2020                            int i;
2021    
2022                            if (bCount == 0) pMBs[x + y * pParam->mb_width].mvs[0] = zeroMV;
2023    
2024                            MEanalyzeMB(pRef->y, pCurrent->y, x, y, pParam, pMBs, &Data);
2025    
2026                            for (i = 0; i < 4; i++) {
2027                                    int dev;
2028                                    MACROBLOCK *pMB = &pMBs[x+(i&1) + (y+(i>>1)) * pParam->mb_width];
2029                                    if (pMB->sad16 > IntraThresh) {
2030                                            dev = dev16(pCurrent->y + (x + (i&1) + (y + (i>>1)) * pParam->edged_width) * 16,
2031                                                                            pParam->edged_width);
2032                                            if (dev + IntraThresh < pMB->sad16) {
2033                                                    pMB->mode = MODE_INTRA;
2034                                                    if (++intra > (pParam->mb_height-2)*(pParam->mb_width-2)/2) return I_VOP;
2035          }          }
2036                                    }
2037                                    sSAD += pMB->sad16;
2038                            }
2039                    }
2040            }
2041            sSAD /= (pParam->mb_height-2)*(pParam->mb_width-2);
2042    //      if (sSAD > IntraThresh + INTRA_BIAS) return I_VOP;
2043            if (sSAD > InterThresh ) return P_VOP;
2044            emms();
2045            return B_VOP;
2046    
2047          for(i = 0; i < 5; i++) iMinSAD[i] = MV_MAX_ERROR;  }
2048    
         if (pMB->dquant != NO_CHANGE) inter4v = 0;  
2049    
2050          if (inter4v)  static WARPPOINTS
2051                  CheckCandidate = CheckCandidate16;  GlobalMotionEst(const MACROBLOCK * const pMBs,
2052          else CheckCandidate = CheckCandidate16no4v;                                  const MBParam * const pParam,
2053                                    const FRAMEINFO * const current,
2054                                    const FRAMEINFO * const reference,
2055                                    const IMAGE * const pRefH,
2056                                    const IMAGE * const pRefV,
2057                                    const IMAGE * const pRefHV      )
2058    {
2059    
2060            const int deltax=8;             // upper bound for difference between a MV and it's neighbour MVs
2061            const int deltay=8;
2062            const int grad=512;             // lower bound for deviation in MB
2063    
2064          pMB->mvs[0].x = EVEN(pMB->mvs[0].x);          WARPPOINTS gmc;
         pMB->mvs[0].y = EVEN(pMB->mvs[0].y);  
         if (pMB->mvs[0].x > Data.max_dx) pMB->mvs[0].x = Data.max_dx; // this is in case iFcode changed  
         if (pMB->mvs[0].x < Data.min_dx) pMB->mvs[0].x = Data.min_dx;  
         if (pMB->mvs[0].y > Data.max_dy) pMB->mvs[0].y = Data.max_dy;  
         if (pMB->mvs[0].y < Data.min_dy) pMB->mvs[0].y = Data.min_dy;  
   
         CheckCandidate16(pMB->mvs[0].x, pMB->mvs[0].y, 0, &i, &Data);  
   
         if (pMB->mode == MODE_INTER4V)  
                 for (i = 1; i < 4; i++) { // all four vectors will be used as four predictions for 16x16 search  
                         pMB->mvs[i].x = EVEN(pMB->mvs[i].x);  
                         pMB->mvs[i].y = EVEN(pMB->mvs[i].y);  
                         if (!(make_mask(pMB->mvs, i)))  
                                 CheckCandidate16(pMB->mvs[i].x, pMB->mvs[i].y, 0, &i, &Data);  
                 }  
   
         if (MotionFlags & PMV_USESQUARES16)  
                 MainSearchPtr = SquareSearch;  
         else if (MotionFlags & PMV_ADVANCEDDIAMOND16)  
                 MainSearchPtr = AdvDiamondSearch;  
                 else MainSearchPtr = DiamondSearch;  
2065    
2066          (*MainSearchPtr)(currentMV->x, currentMV->y, &Data, 255);          uint32_t mx, my;
2067    
2068          if (MotionFlags & PMV_HALFPELREFINE16) HalfpelRefine(&Data);          int MBh = pParam->mb_height;
2069            int MBw = pParam->mb_width;
2070    
2071          if (inter4v)          int *MBmask= calloc(MBh*MBw,sizeof(int));
2072                  for(i = 0; i < 4; i++)          double DtimesF[4] = { 0.,0., 0., 0. };
2073                          Search8hinted(&Data, 2*x+(i&1), 2*y+(i>>1), MotionFlags, pParam, pMB, pMBs, i);          double sol[4] = { 0., 0., 0., 0. };
2074            double a,b,c,n,denom;
2075            double meanx,meany;
2076            int num,oldnum;
2077    
2078          if (!(inter4v) ||          if (!MBmask) { fprintf(stderr,"Mem error\n"); return gmc;}
                 (iMinSAD[0] < iMinSAD[1] + iMinSAD[2] + iMinSAD[3] + iMinSAD[4] + IMV16X16 * (int32_t)iQuant )) {  
 // INTER MODE  
2079    
2080                  pMB->mode = MODE_INTER;  // filter mask of all blocks
                 pMB->mv16 = pMB->mvs[0] = pMB->mvs[1]  
                         = pMB->mvs[2] = pMB->mvs[3] = currentMV[0];  
2081    
2082                  pMB->sad16 = pMB->sad8[0] = pMB->sad8[1] =          for (my = 1; my < MBh-1; my++)
2083                          pMB->sad8[2] = pMB->sad8[3] =  iMinSAD[0];          for (mx = 1; mx < MBw-1; mx++)
2084            {
2085                    const int mbnum = mx + my * MBw;
2086                    const MACROBLOCK *pMB = &pMBs[mbnum];
2087                    const VECTOR mv = pMB->mvs[0];
2088    
2089                  pMB->pmvs[0].x = currentMV[0].x - Data.predMV.x;                  if (pMB->mode == MODE_INTRA || pMB->mode == MODE_NOT_CODED)
2090                  pMB->pmvs[0].y = currentMV[0].y - Data.predMV.y;                          continue;
         } else {  
 // INTER4V MODE; all other things are already set in Search8hinted  
                 pMB->mode = MODE_INTER4V;  
                 pMB->sad16 = iMinSAD[1] + iMinSAD[2] + iMinSAD[3] + iMinSAD[4] + IMV16X16 * iQuant;  
         }  
2091    
2092                    if ( ( (ABS(mv.x -   (pMB-1)->mvs[0].x) < deltax) && (ABS(mv.y -   (pMB-1)->mvs[0].y) < deltay) )
2093                    &&   ( (ABS(mv.x -   (pMB+1)->mvs[0].x) < deltax) && (ABS(mv.y -   (pMB+1)->mvs[0].y) < deltay) )
2094                    &&   ( (ABS(mv.x - (pMB-MBw)->mvs[0].x) < deltax) && (ABS(mv.y - (pMB-MBw)->mvs[0].y) < deltay) )
2095                    &&   ( (ABS(mv.x - (pMB+MBw)->mvs[0].x) < deltax) && (ABS(mv.y - (pMB+MBw)->mvs[0].y) < deltay) ) )
2096                            MBmask[mbnum]=1;
2097  }  }
2098    
2099  void          for (my = 1; my < MBh-1; my++)
2100  MotionEstimationHinted( MBParam * const pParam,          for (mx = 1; mx < MBw-1; mx++)
                                                 FRAMEINFO * const current,  
                                                 FRAMEINFO * const reference,  
                                                 const IMAGE * const pRefH,  
                                                 const IMAGE * const pRefV,  
                                                 const IMAGE * const pRefHV)  
2101  {  {
2102          MACROBLOCK *const pMBs = current->mbs;                  const uint8_t *const pCur = current->image.y + 16*my*pParam->edged_width + 16*mx;
         const IMAGE *const pCurrent = &current->image;  
         const IMAGE *const pRef = &reference->image;  
2103    
2104          uint32_t x, y;                  const int mbnum = mx + my * MBw;
2105                    if (!MBmask[mbnum])
2106                            continue;
2107    
2108          if (sadInit) (*sadInit) ();                  if (sad16 ( pCur, pCur+1 , pParam->edged_width, 65536) <= grad )
2109                            MBmask[mbnum] = 0;
2110                    if (sad16 ( pCur, pCur+pParam->edged_width, pParam->edged_width, 65536) <= grad )
2111                            MBmask[mbnum] = 0;
2112    
2113          for (y = 0; y < pParam->mb_height; y++) {          }
                 for (x = 0; x < pParam->mb_width; x++)  {  
                         int32_t sad00;  
2114    
2115                          MACROBLOCK *pMB = &pMBs[x + y * pParam->mb_width];          emms();
2116    
2117  //intra mode is copied from the first pass. At least for the time being          do {            /* until convergence */
                         if  ((pMB->mode == MODE_INTRA) || (pMB->mode == MODE_NOT_CODED) ) continue;  
2118    
2119                          if (!(current->global_flags & XVID_LUMIMASKING)) {          a = b = c = n = 0;
2120                                  pMB->dquant = NO_CHANGE;          DtimesF[0] = DtimesF[1] = DtimesF[2] = DtimesF[3] = 0.;
2121                                  pMB->quant = current->quant; }          for (my = 0; my < MBh; my++)
2122                    for (mx = 0; mx < MBw; mx++)
2123                    {
2124                            const int mbnum = mx + my * MBw;
2125                            const MACROBLOCK *pMB = &pMBs[mbnum];
2126                            const VECTOR mv = pMB->mvs[0];
2127    
2128                          if (pMB->dquant == NO_CHANGE) //no skip otherwise, anyway                          if (!MBmask[mbnum])
2129                                  sad00 = pMB->sad16                                  continue;
                                         = sad16(pCurrent->y + (x + y * pParam->edged_width) * 16,  
                                                                 pRef->y + (x + y * pParam->edged_width) * 16,  
                                                                 pParam->edged_width, 256*4096 );  
                         else sad00 = 256*4096;  
2130    
2131                            n++;
2132                            a += 16*mx+8;
2133                            b += 16*my+8;
2134                            c += (16*mx+8)*(16*mx+8)+(16*my+8)*(16*my+8);
2135    
2136                            DtimesF[0] += (double)mv.x;
2137                            DtimesF[1] += (double)mv.x*(16*mx+8) + (double)mv.y*(16*my+8);
2138                            DtimesF[2] += (double)mv.x*(16*my+8) - (double)mv.y*(16*mx+8);
2139                            DtimesF[3] += (double)mv.y;
2140                    }
2141    
2142            denom = a*a+b*b-c*n;
2143    
2144    /* Solve the system:     sol = (D'*E*D)^{-1} D'*E*F   */
2145    /* D'*E*F has been calculated in the same loop as matrix */
2146    
2147            sol[0] = -c*DtimesF[0] + a*DtimesF[1] + b*DtimesF[2];
2148            sol[1] =  a*DtimesF[0] - n*DtimesF[1]                + b*DtimesF[3];
2149            sol[2] =  b*DtimesF[0]                - n*DtimesF[2] - a*DtimesF[3];
2150            sol[3] =                 b*DtimesF[1] - a*DtimesF[2] - c*DtimesF[3];
2151    
2152            sol[0] /= denom;
2153            sol[1] /= denom;
2154            sol[2] /= denom;
2155            sol[3] /= denom;
2156    
2157            meanx = meany = 0.;
2158            oldnum = 0;
2159            for (my = 0; my < MBh; my++)
2160                    for (mx = 0; mx < MBw; mx++)
2161                    {
2162                            const int mbnum = mx + my * MBw;
2163                            const MACROBLOCK *pMB = &pMBs[mbnum];
2164                            const VECTOR mv = pMB->mvs[0];
2165    
2166  //initial skip decision                          if (!MBmask[mbnum])
2167                                    continue;
2168    
2169                          if ( (pMB->dquant == NO_CHANGE) && (sad00 <= MAX_SAD00_FOR_SKIP * pMB->quant)                          oldnum++;
2170                                  && ( //(pMB->mode == MODE_NOT_CODED) ||                          meanx += ABS(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - mv.x );
2171                                          (SkipDecisionP(pCurrent, pRef, x, y, pParam->edged_width, pMB->quant) )) ) {                          meany += ABS(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - mv.y );
                                 if (sad00 < pMB->quant * INITIAL_SKIP_THRESH) {  
                                         SkipMacroblockP(pMB, sad00);  
                                         continue; } //skipped  
2172                          }                          }
                         else sad00 = 256*4096;  
2173    
2174                          if (pMB->mode == MODE_NOT_CODED)          if (4*meanx > oldnum)   /* better fit than 0.25 is useless */
2175                                  SearchP(        pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,                  meanx /= oldnum;
2176                                                          y, current->motion_flags, pMB->quant,          else
2177                                                          current->fcode, pParam, pMBs, reference->mbs,                  meanx = 0.25;
                                                         current->global_flags & XVID_INTER4V, pMB);  
2178    
2179            if (4*meany > oldnum)
2180                    meany /= oldnum;
2181                          else                          else
2182                                  SearchPhinted(pRef->y, pRefH->y, pRefV->y, pRefHV->y, pCurrent, x,                  meany = 0.25;
                                                         y, current->motion_flags, pMB->quant,  
                                                         current->fcode, pParam, pMBs,  
                                                         current->global_flags & XVID_INTER4V, pMB);  
2183    
2184  /* final skip decision, a.k.a. "the vector you found, really that good?" */  /*      fprintf(stderr,"sol = (%8.5f, %8.5f, %8.5f, %8.5f)\n",sol[0],sol[1],sol[2],sol[3]);
2185                          if (sad00 < pMB->quant * MAX_SAD00_FOR_SKIP)          fprintf(stderr,"meanx = %8.5f  meany = %8.5f   %d\n",meanx,meany, oldnum);
2186                                  if ((100*pMB->sad16)/(sad00+1) > FINAL_SKIP_THRESH)  */
2187                                  SkipMacroblockP(pMB, sad00);          num = 0;
2188            for (my = 0; my < MBh; my++)
2189                    for (mx = 0; mx < MBw; mx++)
2190                    {
2191                            const int mbnum = mx + my * MBw;
2192                            const MACROBLOCK *pMB = &pMBs[mbnum];
2193                            const VECTOR mv = pMB->mvs[0];
2194    
2195                            if (!MBmask[mbnum])
2196                                    continue;
2197    
2198                            if  ( ( ABS(( sol[0] + (16*mx+8)*sol[1] + (16*my+8)*sol[2] ) - mv.x ) > meanx )
2199                               || ( ABS(( sol[3] - (16*mx+8)*sol[2] + (16*my+8)*sol[1] ) - mv.y ) > meany ) )
2200                                    MBmask[mbnum]=0;
2201                            else
2202                                    num++;
2203                  }                  }
2204    
2205            } while ( (oldnum != num) && (num>=4) );
2206    
2207            if (num < 4)
2208            {
2209                    gmc.duv[0].x= gmc.duv[0].y= gmc.duv[1].x= gmc.duv[1].y= gmc.duv[2].x= gmc.duv[2].y=0;
2210            } else {
2211    
2212                    gmc.duv[0].x=(int)(sol[0]+0.5);
2213                    gmc.duv[0].y=(int)(sol[3]+0.5);
2214    
2215                    gmc.duv[1].x=(int)(sol[1]*pParam->width+0.5);
2216                    gmc.duv[1].y=(int)(-sol[2]*pParam->width+0.5);
2217    
2218                    gmc.duv[2].x=0;
2219                    gmc.duv[2].y=0;
2220          }          }
2221  }  //      fprintf(stderr,"wp1 = ( %4d, %4d)  wp2 = ( %4d, %4d) \n", gmc.duv[0].x, gmc.duv[0].y, gmc.duv[1].x, gmc.duv[1].y);
2222    
2223            free(MBmask);
2224    
2225            return gmc;
2226    }

Legend:
Removed from v.530  
changed lines
  Added in v.819

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