]> git.sesse.net Git - ffmpeg/blob - libavcodec/motion_est.c
5d6ae7baadc4d4663c6c8fc37eba65cf30cfe62e
[ffmpeg] / libavcodec / motion_est.c
1 /*
2  * Motion estimation 
3  * Copyright (c) 2000,2001 Gerard Lantau.
4  * 
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  * new Motion Estimation (X1/EPZS) by Michael Niedermayer <michaelni@gmx.at>
21  */
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include "avcodec.h"
25 #include "dsputil.h"
26 #include "mpegvideo.h"
27
28 #define ABS(a) ((a)>0 ? (a) : -(a))
29 #define INTER_BIAS      257
30
31 static void halfpel_motion_search(MpegEncContext * s,
32                                   int *mx_ptr, int *my_ptr, int dmin,
33                                   int xmin, int ymin, int xmax, int ymax,
34                                   int pred_x, int pred_y);
35
36 /* config it to test motion vector encoding (send random vectors) */
37 //#define CONFIG_TEST_MV_ENCODE
38
39 static int pix_sum(UINT8 * pix, int line_size)
40 {
41     int s, i, j;
42
43     s = 0;
44     for (i = 0; i < 16; i++) {
45         for (j = 0; j < 16; j += 8) {
46             s += pix[0];
47             s += pix[1];
48             s += pix[2];
49             s += pix[3];
50             s += pix[4];
51             s += pix[5];
52             s += pix[6];
53             s += pix[7];
54             pix += 8;
55         }
56         pix += line_size - 16;
57     }
58     return s;
59 }
60
61 static int pix_dev(UINT8 * pix, int line_size, int mean)
62 {
63     int s, i, j;
64
65     s = 0;
66     for (i = 0; i < 16; i++) {
67         for (j = 0; j < 16; j += 8) {
68             s += ABS(pix[0]-mean);
69             s += ABS(pix[1]-mean);
70             s += ABS(pix[2]-mean);
71             s += ABS(pix[3]-mean);
72             s += ABS(pix[4]-mean);
73             s += ABS(pix[5]-mean);
74             s += ABS(pix[6]-mean);
75             s += ABS(pix[7]-mean);
76             pix += 8;
77         }
78         pix += line_size - 16;
79     }
80     return s;
81 }
82
83 static int pix_norm1(UINT8 * pix, int line_size)
84 {
85     int s, i, j;
86     UINT32 *sq = squareTbl + 256;
87
88     s = 0;
89     for (i = 0; i < 16; i++) {
90         for (j = 0; j < 16; j += 8) {
91             s += sq[pix[0]];
92             s += sq[pix[1]];
93             s += sq[pix[2]];
94             s += sq[pix[3]];
95             s += sq[pix[4]];
96             s += sq[pix[5]];
97             s += sq[pix[6]];
98             s += sq[pix[7]];
99             pix += 8;
100         }
101         pix += line_size - 16;
102     }
103     return s;
104 }
105
106 static int pix_norm(UINT8 * pix1, UINT8 * pix2, int line_size)
107 {
108     int s, i, j;
109     UINT32 *sq = squareTbl + 256;
110
111     s = 0;
112     for (i = 0; i < 16; i++) {
113         for (j = 0; j < 16; j += 8) {
114             s += sq[pix1[0] - pix2[0]];
115             s += sq[pix1[1] - pix2[1]];
116             s += sq[pix1[2] - pix2[2]];
117             s += sq[pix1[3] - pix2[3]];
118             s += sq[pix1[4] - pix2[4]];
119             s += sq[pix1[5] - pix2[5]];
120             s += sq[pix1[6] - pix2[6]];
121             s += sq[pix1[7] - pix2[7]];
122             pix1 += 8;
123             pix2 += 8;
124         }
125         pix1 += line_size - 16;
126         pix2 += line_size - 16;
127     }
128     return s;
129 }
130
131 static void no_motion_search(MpegEncContext * s,
132                              int *mx_ptr, int *my_ptr)
133 {
134     *mx_ptr = 16 * s->mb_x;
135     *my_ptr = 16 * s->mb_y;
136 }
137
138 static int full_motion_search(MpegEncContext * s,
139                               int *mx_ptr, int *my_ptr, int range,
140                               int xmin, int ymin, int xmax, int ymax)
141 {
142     int x1, y1, x2, y2, xx, yy, x, y;
143     int mx, my, dmin, d;
144     UINT8 *pix;
145
146     xx = 16 * s->mb_x;
147     yy = 16 * s->mb_y;
148     x1 = xx - range + 1;        /* we loose one pixel to avoid boundary pb with half pixel pred */
149     if (x1 < xmin)
150         x1 = xmin;
151     x2 = xx + range - 1;
152     if (x2 > xmax)
153         x2 = xmax;
154     y1 = yy - range + 1;
155     if (y1 < ymin)
156         y1 = ymin;
157     y2 = yy + range - 1;
158     if (y2 > ymax)
159         y2 = ymax;
160     pix = s->new_picture[0] + (yy * s->linesize) + xx;
161     dmin = 0x7fffffff;
162     mx = 0;
163     my = 0;
164     for (y = y1; y <= y2; y++) {
165         for (x = x1; x <= x2; x++) {
166             d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x,
167                              s->linesize, 16);
168             if (d < dmin ||
169                 (d == dmin &&
170                  (abs(x - xx) + abs(y - yy)) <
171                  (abs(mx - xx) + abs(my - yy)))) {
172                 dmin = d;
173                 mx = x;
174                 my = y;
175             }
176         }
177     }
178
179     *mx_ptr = mx;
180     *my_ptr = my;
181
182 #if 0
183     if (*mx_ptr < -(2 * range) || *mx_ptr >= (2 * range) ||
184         *my_ptr < -(2 * range) || *my_ptr >= (2 * range)) {
185         fprintf(stderr, "error %d %d\n", *mx_ptr, *my_ptr);
186     }
187 #endif
188     return dmin;
189 }
190
191
192 static int log_motion_search(MpegEncContext * s,
193                              int *mx_ptr, int *my_ptr, int range,
194                              int xmin, int ymin, int xmax, int ymax)
195 {
196     int x1, y1, x2, y2, xx, yy, x, y;
197     int mx, my, dmin, d;
198     UINT8 *pix;
199
200     xx = s->mb_x << 4;
201     yy = s->mb_y << 4;
202
203     /* Left limit */
204     x1 = xx - range;
205     if (x1 < xmin)
206         x1 = xmin;
207
208     /* Right limit */
209     x2 = xx + range;
210     if (x2 > xmax)
211         x2 = xmax;
212
213     /* Upper limit */
214     y1 = yy - range;
215     if (y1 < ymin)
216         y1 = ymin;
217
218     /* Lower limit */
219     y2 = yy + range;
220     if (y2 > ymax)
221         y2 = ymax;
222
223     pix = s->new_picture[0] + (yy * s->linesize) + xx;
224     dmin = 0x7fffffff;
225     mx = 0;
226     my = 0;
227
228     do {
229         for (y = y1; y <= y2; y += range) {
230             for (x = x1; x <= x2; x += range) {
231                 d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x, s->linesize, 16);
232                 if (d < dmin || (d == dmin && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) {
233                     dmin = d;
234                     mx = x;
235                     my = y;
236                 }
237             }
238         }
239
240         range = range >> 1;
241
242         x1 = mx - range;
243         if (x1 < xmin)
244             x1 = xmin;
245
246         x2 = mx + range;
247         if (x2 > xmax)
248             x2 = xmax;
249
250         y1 = my - range;
251         if (y1 < ymin)
252             y1 = ymin;
253
254         y2 = my + range;
255         if (y2 > ymax)
256             y2 = ymax;
257
258     } while (range >= 1);
259
260 #ifdef DEBUG
261     fprintf(stderr, "log       - MX: %d\tMY: %d\n", mx, my);
262 #endif
263     *mx_ptr = mx;
264     *my_ptr = my;
265     return dmin;
266 }
267
268 static int phods_motion_search(MpegEncContext * s,
269                                int *mx_ptr, int *my_ptr, int range,
270                                int xmin, int ymin, int xmax, int ymax)
271 {
272     int x1, y1, x2, y2, xx, yy, x, y, lastx, d;
273     int mx, my, dminx, dminy;
274     UINT8 *pix;
275
276     xx = s->mb_x << 4;
277     yy = s->mb_y << 4;
278
279     /* Left limit */
280     x1 = xx - range;
281     if (x1 < xmin)
282         x1 = xmin;
283
284     /* Right limit */
285     x2 = xx + range;
286     if (x2 > xmax)
287         x2 = xmax;
288
289     /* Upper limit */
290     y1 = yy - range;
291     if (y1 < ymin)
292         y1 = ymin;
293
294     /* Lower limit */
295     y2 = yy + range;
296     if (y2 > ymax)
297         y2 = ymax;
298
299     pix = s->new_picture[0] + (yy * s->linesize) + xx;
300     mx = 0;
301     my = 0;
302
303     x = xx;
304     y = yy;
305     do {
306         dminx = 0x7fffffff;
307         dminy = 0x7fffffff;
308
309         lastx = x;
310         for (x = x1; x <= x2; x += range) {
311             d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x, s->linesize, 16);
312             if (d < dminx || (d == dminx && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) {
313                 dminx = d;
314                 mx = x;
315             }
316         }
317
318         x = lastx;
319         for (y = y1; y <= y2; y += range) {
320             d = pix_abs16x16(pix, s->last_picture[0] + (y * s->linesize) + x, s->linesize, 16);
321             if (d < dminy || (d == dminy && (abs(x - xx) + abs(y - yy)) < (abs(mx - xx) + abs(my - yy)))) {
322                 dminy = d;
323                 my = y;
324             }
325         }
326
327         range = range >> 1;
328
329         x = mx;
330         y = my;
331         x1 = mx - range;
332         if (x1 < xmin)
333             x1 = xmin;
334
335         x2 = mx + range;
336         if (x2 > xmax)
337             x2 = xmax;
338
339         y1 = my - range;
340         if (y1 < ymin)
341             y1 = ymin;
342
343         y2 = my + range;
344         if (y2 > ymax)
345             y2 = ymax;
346
347     } while (range >= 1);
348
349 #ifdef DEBUG
350     fprintf(stderr, "phods     - MX: %d\tMY: %d\n", mx, my);
351 #endif
352
353     /* half pixel search */
354     *mx_ptr = mx;
355     *my_ptr = my;
356     return dminy;
357 }
358
359
360 #define Z_THRESHOLD 256
361
362 #define CHECK_MV(x,y)\
363 {\
364     d = pix_abs16x16(new_pic, old_pic + (x) + (y)*pic_stride, pic_stride, 16);\
365     d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*quant;\
366     if(d<dmin){\
367         best[0]=x;\
368         best[1]=y;\
369         dmin=d;\
370     }\
371 }
372
373 #define CHECK_MV_DIR(x,y,new_dir)\
374 {\
375     d = pix_abs16x16(new_pic, old_pic + (x) + (y)*pic_stride, pic_stride, 16);\
376     d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*quant;\
377     if(d<dmin){\
378         best[0]=x;\
379         best[1]=y;\
380         dmin=d;\
381         next_dir= new_dir;\
382     }\
383 }
384
385 #define check(x,y,S,v)\
386 if( (x)<(xmin<<(S)) ) printf("%d %d %d %d xmin" #v, (x), (y), s->mb_x, s->mb_y);\
387 if( (x)>(xmax<<(S)) ) printf("%d %d %d %d xmax" #v, (x), (y), s->mb_x, s->mb_y);\
388 if( (y)<(ymin<<(S)) ) printf("%d %d %d %d ymin" #v, (x), (y), s->mb_x, s->mb_y);\
389 if( (y)>(ymax<<(S)) ) printf("%d %d %d %d ymax" #v, (x), (y), s->mb_x, s->mb_y);\
390
391
392 static inline int small_diamond_search(MpegEncContext * s, int *best, int dmin,
393                                        UINT8 *new_pic, UINT8 *old_pic, int pic_stride,
394                                        int pred_x, int pred_y, UINT16 *mv_penalty, int quant,
395                                        int xmin, int ymin, int xmax, int ymax, int shift)
396 {
397     int next_dir=-1;
398
399     for(;;){
400         int d;
401         const int dir= next_dir;
402         const int x= best[0];
403         const int y= best[1];
404         next_dir=-1;
405
406 //printf("%d", dir);
407         if(dir!=2 && x>xmin) CHECK_MV_DIR(x-1, y  , 0)
408         if(dir!=3 && y>ymin) CHECK_MV_DIR(x  , y-1, 1)
409         if(dir!=0 && x<xmax) CHECK_MV_DIR(x+1, y  , 2)
410         if(dir!=1 && y<ymax) CHECK_MV_DIR(x  , y+1, 3)
411
412         if(next_dir==-1){
413             return dmin;
414         }
415     }
416
417 /*    for(;;){
418         int d;
419         const int x= best[0];
420         const int y= best[1];
421         const int last_min=dmin;
422         if(x>xmin) CHECK_MV(x-1, y  )
423         if(y>xmin) CHECK_MV(x  , y-1)
424         if(x<xmax) CHECK_MV(x+1, y  )
425         if(y<xmax) CHECK_MV(x  , y+1)
426         if(x>xmin && y>ymin) CHECK_MV(x-1, y-1)
427         if(x>xmin && y<ymax) CHECK_MV(x-1, y+1)
428         if(x<xmax && y>ymin) CHECK_MV(x+1, y-1)
429         if(x<xmax && y<ymax) CHECK_MV(x+1, y+1)
430         if(x-1>xmin) CHECK_MV(x-2, y  )
431         if(y-1>xmin) CHECK_MV(x  , y-2)
432         if(x+1<xmax) CHECK_MV(x+2, y  )
433         if(y+1<xmax) CHECK_MV(x  , y+2)
434         if(x-1>xmin && y-1>ymin) CHECK_MV(x-2, y-2)
435         if(x-1>xmin && y+1<ymax) CHECK_MV(x-2, y+2)
436         if(x+1<xmax && y-1>ymin) CHECK_MV(x+2, y-2)
437         if(x+1<xmax && y+1<ymax) CHECK_MV(x+2, y+2)
438         if(dmin==last_min) return dmin;
439     }
440     */
441 }
442
443 static inline int snake_search(MpegEncContext * s, int *best, int dmin,
444                                        UINT8 *new_pic, UINT8 *old_pic, int pic_stride,
445                                        int pred_x, int pred_y, UINT16 *mv_penalty, int quant,
446                                        int xmin, int ymin, int xmax, int ymax, int shift)
447 {
448     int dir=0;
449     int c=1;
450     static int x_dir[8]= {1,1,0,-1,-1,-1, 0, 1};
451     static int y_dir[8]= {0,1,1, 1, 0,-1,-1,-1};
452     int fails=0;
453     int last_d[2]={dmin, dmin};
454
455 /*static int good=0;
456 static int bad=0;
457 static int point=0;
458
459 point++;
460 if(256*256*256*64%point==0)
461 {
462     printf("%d %d %d\n", good, bad, point);
463 }*/
464
465     for(;;){
466         int x= best[0];
467         int y= best[1];
468         int d;
469         x+=x_dir[dir];
470         y+=y_dir[dir];
471         if(x>=xmin && x<=xmax && y>=ymin && y<=ymax){
472             d = pix_abs16x16(new_pic, old_pic + (x) + (y)*pic_stride, pic_stride, 16);
473             d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*quant;
474         }else{
475             d = dmin + 10000; //FIXME smarter boundary handling
476         }
477         if(d<dmin){
478             best[0]=x;
479             best[1]=y;
480             dmin=d;
481
482             if(last_d[1] - last_d[0] > last_d[0] - d) c= -c;
483             dir+=c;
484
485             fails=0;
486 //good++;
487             last_d[1]=last_d[0];
488             last_d[0]=d;
489         }else{
490 //bad++;
491             if(fails){
492                 if(fails>=3) return dmin;
493             }else{
494                 c= -c;
495             }
496             dir+=c*2;
497             fails++;
498         }
499         dir&=7;
500     }
501 }
502
503 static int epzs_motion_search(MpegEncContext * s,
504                              int *mx_ptr, int *my_ptr,
505                              int P[5][2], int pred_x, int pred_y,
506                              int xmin, int ymin, int xmax, int ymax)
507 {
508     int best[2]={0, 0};
509     int d, dmin; 
510     UINT8 *new_pic, *old_pic;
511     const int pic_stride= s->linesize;
512     const int pic_xy= (s->mb_y*pic_stride + s->mb_x)*16;
513     UINT16 *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame
514     int quant= s->qscale; // qscale of the prev frame
515     const int shift= 1+s->quarter_sample;
516
517     new_pic = s->new_picture[0] + pic_xy;
518     old_pic = s->last_picture[0] + pic_xy;
519    
520     dmin = pix_abs16x16(new_pic, old_pic, pic_stride, 16);
521     if(dmin<Z_THRESHOLD){
522         *mx_ptr= 0;
523         *my_ptr= 0;
524 //printf("Z");
525         return dmin;
526     }
527
528     /* first line */
529     if ((s->mb_y == 0 || s->first_slice_line || s->first_gob_line)) {
530         CHECK_MV(P[1][0]>>shift, P[1][1]>>shift)
531     }else{
532         CHECK_MV(P[4][0]>>shift, P[4][1]>>shift)
533         if(dmin<Z_THRESHOLD){
534             *mx_ptr= P[4][0]>>shift;
535             *my_ptr= P[4][1]>>shift;
536 //printf("M\n");
537             return dmin;
538         }
539         CHECK_MV(P[1][0]>>shift, P[1][1]>>shift)
540         CHECK_MV(P[2][0]>>shift, P[2][1]>>shift)
541         CHECK_MV(P[3][0]>>shift, P[3][1]>>shift)
542     }
543     CHECK_MV(P[0][0]>>shift, P[0][1]>>shift)
544
545 //check(best[0],best[1],0, b0)
546     if(s->full_search==ME_EPZS)
547         dmin= small_diamond_search(s, best, dmin, new_pic, old_pic, pic_stride, 
548                                    pred_x, pred_y, mv_penalty, quant, xmin, ymin, xmax, ymax, shift);
549     else
550         dmin=         snake_search(s, best, dmin, new_pic, old_pic, pic_stride, 
551                                    pred_x, pred_y, mv_penalty, quant, xmin, ymin, xmax, ymax, shift);
552 //check(best[0],best[1],0, b1)
553     *mx_ptr= best[0];
554     *my_ptr= best[1];    
555
556 //    printf("%d %d %d \n", best[0], best[1], dmin);
557     return dmin;
558 }
559
560 #define CHECK_HALF_MV(suffix, x, y) \
561     d= pix_abs16x16_ ## suffix(pix, ptr+((x)>>1), s->linesize, 16);\
562     d += (mv_penalty[pen_x + x] + mv_penalty[pen_y + y])*quant;\
563     if(d<dminh){\
564         dminh= d;\
565         mx= mx1 + x;\
566         my= my1 + y;\
567     }
568
569 /* The idea would be to make half pel ME after Inter/Intra decision to 
570    save time. */
571 static inline void halfpel_motion_search(MpegEncContext * s,
572                                   int *mx_ptr, int *my_ptr, int dmin,
573                                   int xmin, int ymin, int xmax, int ymax,
574                                   int pred_x, int pred_y)
575 {
576     UINT16 *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame
577     const int quant= s->qscale;
578     int pen_x, pen_y;
579     int mx, my, mx1, my1, d, xx, yy, dminh;
580     UINT8 *pix, *ptr;
581
582     
583     mx = *mx_ptr;
584     my = *my_ptr;
585     ptr = s->last_picture[0] + (my * s->linesize) + mx;
586
587     xx = 16 * s->mb_x;
588     yy = 16 * s->mb_y;
589     pix =  s->new_picture[0] + (yy * s->linesize) + xx;
590     
591     dminh = dmin;
592
593     if (mx > xmin && mx < xmax && 
594         my > ymin && my < ymax) {
595
596         mx= mx1= 2*(mx - xx);
597         my= my1= 2*(my - yy);
598         if(dmin < Z_THRESHOLD && mx==0 && my==0){
599             *mx_ptr = 0;
600             *my_ptr = 0;
601             return;
602         }
603         
604         pen_x= pred_x + mx;
605         pen_y= pred_y + my;
606
607         ptr-= s->linesize;
608         CHECK_HALF_MV(xy2, -1, -1)
609         CHECK_HALF_MV(y2 ,  0, -1)
610         CHECK_HALF_MV(xy2, +1, -1)
611         
612         ptr+= s->linesize;
613         CHECK_HALF_MV(x2 , -1,  0)
614         CHECK_HALF_MV(x2 , +1,  0)
615         CHECK_HALF_MV(xy2, -1, +1)
616         CHECK_HALF_MV(y2 ,  0, +1)
617         CHECK_HALF_MV(xy2, +1, +1)
618     }else{
619         mx= 2*(mx - xx);
620         my= 2*(my - yy);
621     }
622
623     *mx_ptr = mx;
624     *my_ptr = my;
625 }
626
627 #ifndef CONFIG_TEST_MV_ENCODE
628
629 int estimate_motion(MpegEncContext * s,
630                     int mb_x, int mb_y,
631                     int *mx_ptr, int *my_ptr)
632 {
633     UINT8 *pix, *ppix;
634     int sum, varc, vard, mx, my, range, dmin, xx, yy;
635     int xmin, ymin, xmax, ymax;
636     int rel_xmin, rel_ymin, rel_xmax, rel_ymax;
637     int pred_x=0, pred_y=0;
638     int P[5][2];
639     const int shift= 1+s->quarter_sample;
640     
641     range = 8 * (1 << (s->f_code - 1));
642     /* XXX: temporary kludge to avoid overflow for msmpeg4 */
643     if (s->out_format == FMT_H263 && !s->h263_msmpeg4)
644         range = range * 2;
645
646     if (s->unrestricted_mv) {
647         xmin = -16;
648         ymin = -16;
649         if (s->h263_plus)
650             range *= 2;
651         if(s->avctx==NULL || s->avctx->codec->id!=CODEC_ID_MPEG4){
652             xmax = s->mb_width*16;
653             ymax = s->mb_height*16;
654         }else {
655             /* XXX: dunno if this is correct but ffmpeg4 decoder wont like it otherwise 
656                     (cuz the drawn edge isnt large enough))*/
657             xmax = s->width;
658             ymax = s->height;
659         }
660     } else {
661         xmin = 0;
662         ymin = 0;
663         xmax = s->mb_width*16 - 16;
664         ymax = s->mb_height*16 - 16;
665     }
666     switch(s->full_search) {
667     case ME_ZERO:
668     default:
669         no_motion_search(s, &mx, &my);
670         dmin = 0;
671         break;
672     case ME_FULL:
673         dmin = full_motion_search(s, &mx, &my, range, xmin, ymin, xmax, ymax);
674         break;
675     case ME_LOG:
676         dmin = log_motion_search(s, &mx, &my, range / 2, xmin, ymin, xmax, ymax);
677         break;
678     case ME_PHODS:
679         dmin = phods_motion_search(s, &mx, &my, range / 2, xmin, ymin, xmax, ymax);
680         break;
681     case ME_X1: // just reserving some space for experiments ...
682     case ME_EPZS:
683         rel_xmin= xmin - s->mb_x*16;
684         rel_xmax= xmax - s->mb_x*16;
685         rel_ymin= ymin - s->mb_y*16;
686         rel_ymax= ymax - s->mb_y*16;
687         if(s->out_format == FMT_H263){
688             static const int off[4]= {2, 1, 1, -1};
689             const int mot_stride = s->mb_width*2 + 2;
690             const int mot_xy = (s->mb_y*2 + 1)*mot_stride + s->mb_x*2 + 1;
691          
692             P[0][0] = s->motion_val[mot_xy    ][0];
693             P[0][1] = s->motion_val[mot_xy    ][1];
694             P[1][0] = s->motion_val[mot_xy - 1][0];
695             P[1][1] = s->motion_val[mot_xy - 1][1];
696             if(P[1][0] > (rel_xmax<<shift)) P[1][0]= (rel_xmax<<shift);
697
698             /* special case for first line */
699             if ((s->mb_y == 0 || s->first_slice_line || s->first_gob_line)) {
700                 pred_x = P[1][0];
701                 pred_y = P[1][1];
702             } else {
703                 P[2][0] = s->motion_val[mot_xy - mot_stride             ][0];
704                 P[2][1] = s->motion_val[mot_xy - mot_stride             ][1];
705                 P[3][0] = s->motion_val[mot_xy - mot_stride + off[0]    ][0];
706                 P[3][1] = s->motion_val[mot_xy - mot_stride + off[0]    ][1];
707                 if(P[2][1] > (rel_ymax<<shift)) P[2][1]= (rel_ymax<<shift);
708                 if(P[3][0] < (rel_xmin<<shift)) P[3][0]= (rel_xmin<<shift);
709                 if(P[3][1] > (rel_ymax<<shift)) P[3][1]= (rel_ymax<<shift);
710         
711                 P[4][0]= pred_x = mid_pred(P[1][0], P[2][0], P[3][0]);
712                 P[4][1]= pred_y = mid_pred(P[1][1], P[2][1], P[3][1]);
713             }
714         }else {
715             const int xy= s->mb_y*s->mb_width + s->mb_x;
716             pred_x= s->last_mv[0][0][0];
717             pred_y= s->last_mv[0][0][1];
718
719             P[0][0]= s->mv_table[0][xy  ];
720             P[0][1]= s->mv_table[1][xy  ];
721             if(s->mb_x == 0){
722                 P[1][0]= 0;
723                 P[1][1]= 0;
724             }else{
725                 P[1][0]= s->mv_table[0][xy-1];
726                 P[1][1]= s->mv_table[1][xy-1];
727                 if(P[1][0] > (rel_xmax<<shift)) P[1][0]= (rel_xmax<<shift);
728             }
729     
730             if (!(s->mb_y == 0 || s->first_slice_line || s->first_gob_line)) {
731                 P[2][0] = s->mv_table[0][xy - s->mb_width];
732                 P[2][1] = s->mv_table[1][xy - s->mb_width];
733                 P[3][0] = s->mv_table[0][xy - s->mb_width+1];
734                 P[3][1] = s->mv_table[1][xy - s->mb_width+1];
735                 if(P[2][1] > (rel_ymax<<shift)) P[2][1]= (rel_ymax<<shift);
736                 if(P[3][0] > (rel_xmax<<shift)) P[3][0]= (rel_xmax<<shift);
737                 if(P[3][0] < (rel_xmin<<shift)) P[3][0]= (rel_xmin<<shift);
738                 if(P[3][1] > (rel_ymax<<shift)) P[3][1]= (rel_ymax<<shift);
739         
740                 P[4][0]= mid_pred(P[1][0], P[2][0], P[3][0]);
741                 P[4][1]= mid_pred(P[1][1], P[2][1], P[3][1]);
742             }
743         }
744         dmin = epzs_motion_search(s, &mx, &my, P, pred_x, pred_y, rel_xmin, rel_ymin, rel_xmax, rel_ymax);
745  
746         mx+= s->mb_x*16;
747         my+= s->mb_y*16;
748         break;
749     }
750
751     /* intra / predictive decision */
752     xx = mb_x * 16;
753     yy = mb_y * 16;
754
755     pix = s->new_picture[0] + (yy * s->linesize) + xx;
756     /* At this point (mx,my) are full-pell and the absolute displacement */
757     ppix = s->last_picture[0] + (my * s->linesize) + mx;
758
759     sum = pix_sum(pix, s->linesize);
760     varc = pix_dev(pix, s->linesize, (sum+128)>>8);
761     vard = pix_abs16x16(pix, ppix, s->linesize, 16);
762
763     s->mb_var[s->mb_width * mb_y + mb_x] = varc;
764     s->avg_mb_var += varc;
765     s->mc_mb_var += vard;
766
767 #if 0
768     printf("varc=%4d avg_var=%4d (sum=%4d) vard=%4d mx=%2d my=%2d\n",
769            varc, s->avg_mb_var, sum, vard, mx - xx, my - yy);
770 #endif
771     if (vard <= 64 || vard < varc + INTER_BIAS) {
772         if (s->full_search != ME_ZERO) {
773             halfpel_motion_search(s, &mx, &my, dmin, xmin, ymin, xmax, ymax, pred_x, pred_y);
774         } else {
775             mx -= 16 * s->mb_x;
776             my -= 16 * s->mb_y;
777         }
778 //        check(mx + 32*s->mb_x, my + 32*s->mb_y, 1, end)
779
780         *mx_ptr = mx;
781         *my_ptr = my;
782         return 0;
783     } else {
784         *mx_ptr = 0;
785         *my_ptr = 0;
786         return 1;
787     }
788 }
789
790 #else
791
792 /* test version which generates valid random vectors */
793 int estimate_motion(MpegEncContext * s,
794                     int mb_x, int mb_y,
795                     int *mx_ptr, int *my_ptr)
796 {
797     int xx, yy, x1, y1, x2, y2, range;
798
799     if ((random() % 10) >= 5) {
800         range = 8 * (1 << (s->f_code - 1));
801         if (s->out_format == FMT_H263 && !s->h263_msmpeg4)
802             range = range * 2;
803
804         xx = 16 * s->mb_x;
805         yy = 16 * s->mb_y;
806         x1 = xx - range;
807         if (x1 < 0)
808             x1 = 0;
809         x2 = xx + range - 1;
810         if (x2 > (s->width - 16))
811             x2 = s->width - 16;
812         y1 = yy - range;
813         if (y1 < 0)
814             y1 = 0;
815         y2 = yy + range - 1;
816         if (y2 > (s->height - 16))
817             y2 = s->height - 16;
818
819         *mx_ptr = (random() % (2 * (x2 - x1 + 1))) + 2 * (x1 - xx);
820         *my_ptr = (random() % (2 * (y2 - y1 + 1))) + 2 * (y1 - yy);
821         return 0;
822     } else {
823         *mx_ptr = 0;
824         *my_ptr = 0;
825         return 1;
826     }
827 }
828
829 #endif