comparison motion_est.c @ 277:5cb2978e701f libavcodec

new motion estimation (epzs) not complete yet but allready pretty good :) unlimited mv search range minor bugfix in the mpeg4 header parser reset picture in gop counter if scene change is detected
author michaelni
date Fri, 22 Mar 2002 02:21:17 +0000
parents 7ebb3f9aaf3b
children 3dc1ca4ba717
comparison
equal deleted inserted replaced
276:1e2f9ef286d4 277:5cb2978e701f
14 * GNU General Public License for more details. 14 * GNU General Public License for more details.
15 * 15 *
16 * You should have received a copy of the GNU General Public License 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 17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 * new Motion Estimation (X1/EPZS) by Michael Niedermayer <michaelni@gmx.at>
19 */ 21 */
20 #include <stdlib.h> 22 #include <stdlib.h>
21 #include <stdio.h> 23 #include <stdio.h>
22 #include "avcodec.h" 24 #include "avcodec.h"
23 #include "dsputil.h" 25 #include "dsputil.h"
24 #include "mpegvideo.h" 26 #include "mpegvideo.h"
25 27
26 static void halfpel_motion_search(MpegEncContext * s, 28 static void halfpel_motion_search(MpegEncContext * s,
27 int *mx_ptr, int *my_ptr, int dmin, 29 int *mx_ptr, int *my_ptr, int dmin,
28 int xmin, int ymin, int xmax, int ymax); 30 int xmin, int ymin, int xmax, int ymax,
31 int pred_x, int pred_y);
29 32
30 /* config it to test motion vector encoding (send random vectors) */ 33 /* config it to test motion vector encoding (send random vectors) */
31 //#define CONFIG_TEST_MV_ENCODE 34 //#define CONFIG_TEST_MV_ENCODE
32 35
33 static int pix_sum(UINT8 * pix, int line_size) 36 static int pix_sum(UINT8 * pix, int line_size)
326 *mx_ptr = mx; 329 *mx_ptr = mx;
327 *my_ptr = my; 330 *my_ptr = my;
328 return dminy; 331 return dminy;
329 } 332 }
330 333
334
335 #define Z_THRESHOLD 256
336
337 #define CHECK_MV(x,y)\
338 d = pix_abs16x16(new_pic, old_pic + (x) + (y)*pic_stride, pic_stride, 16);\
339 d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*quant;\
340 if(d<dmin){\
341 best[0]=x;\
342 best[1]=y;\
343 dmin=d;\
344 }
345
346 #define CHECK_MV_DIR(x,y,new_dir)\
347 {\
348 d = pix_abs16x16(new_pic, old_pic + (x) + (y)*pic_stride, pic_stride, 16);\
349 d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*quant;\
350 if(d<dmin){\
351 best[0]=x;\
352 best[1]=y;\
353 dmin=d;\
354 next_dir= new_dir;\
355 }\
356 }
357
358 static inline int small_diamond_search(MpegEncContext * s, int *best, int dmin,
359 UINT8 *new_pic, UINT8 *old_pic, int pic_stride,
360 int pred_x, int pred_y, UINT16 *mv_penalty, int quant,
361 int xmin, int ymin, int xmax, int ymax, int shift)
362 {
363 int next_dir=-1;
364
365 for(;;){
366 int d;
367 const int dir= next_dir;
368 const int x= best[0];
369 const int y= best[1];
370 next_dir=-1;
371
372 //printf("%d", dir);
373 if(dir!=2 && x-1>=xmin) CHECK_MV_DIR(x-1, y , 0)
374 if(dir!=3 && y-1>=ymin) CHECK_MV_DIR(x , y-1, 1)
375 if(dir!=0 && x+1<=xmax) CHECK_MV_DIR(x+1, y , 2)
376 if(dir!=1 && y+1<=ymax) CHECK_MV_DIR(x , y+1, 3)
377
378 if(next_dir==-1){
379 return dmin;
380 }
381 }
382 }
383
384 static int epzs_motion_search(MpegEncContext * s,
385 int *mx_ptr, int *my_ptr,
386 int *px_ptr, int *py_ptr,
387 int xmin, int ymin, int xmax, int ymax)
388 {
389 INT16 P_left[2], P_top[2], P_topright[2], P_last[2];
390 static const int off[4]= {2, 1, 1, -1};
391 int best[2]={0, 0};
392 int d, dmin;
393 UINT8 *new_pic, *old_pic;
394 const int pic_stride= s->linesize;
395 const int pic_xy= (s->mb_y*pic_stride + s->mb_x)*16;
396 const int mot_stride = s->block_wrap[0];
397 const int mot_xy = s->block_index[0];
398 UINT16 *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame
399 int quant= s->qscale; // qscale of the prev frame
400 int pred_x, pred_y;
401 const int shift= 1+s->quarter_sample;
402
403 new_pic = s->new_picture[0] + pic_xy;
404 old_pic = s->last_picture[0] + pic_xy;
405
406 xmin-=s->mb_x*16;
407 xmax-=s->mb_x*16;
408 ymin-=s->mb_y*16;
409 ymax-=s->mb_y*16;
410
411 dmin = pix_abs16x16(new_pic, old_pic, pic_stride, 16);
412 if(dmin<Z_THRESHOLD){
413 *mx_ptr= 0;
414 *my_ptr= 0;
415 //printf("Z");
416 return dmin;
417 }
418
419 P_last[0] = s->motion_val[mot_xy ][0];
420 P_last[1] = s->motion_val[mot_xy ][1];
421 P_left[0] = s->motion_val[mot_xy - 1][0];
422 P_left[1] = s->motion_val[mot_xy - 1][1];
423 if(P_left[0] > (xmax<<shift)) P_left[0]= (xmax<<shift);
424
425 /* special case for first line */
426 if ((s->mb_y == 0 || s->first_slice_line || s->first_gob_line)) {
427 *px_ptr= pred_x = P_left[0];
428 *py_ptr= pred_y = P_left[1];
429 CHECK_MV(pred_x>>shift, pred_y>>shift)
430 if(dmin<Z_THRESHOLD){
431 *mx_ptr= pred_x>>shift;
432 *my_ptr= pred_y>>shift;
433 //printf("M");
434 return dmin;
435 }
436 } else {
437 P_top [0] = s->motion_val[mot_xy - mot_stride ][0];
438 P_top [1] = s->motion_val[mot_xy - mot_stride ][1];
439 P_topright[0] = s->motion_val[mot_xy - mot_stride + off[0] ][0];
440 P_topright[1] = s->motion_val[mot_xy - mot_stride + off[0] ][1];
441 if(P_top [1] > (ymax<<shift)) P_top [1]= (ymax<<shift);
442 if(P_topright[0] < (xmin<<shift)) P_topright[0]= (xmin<<shift);
443 if(P_topright[1] > (ymax<<shift)) P_topright[1]= (ymax<<shift);
444
445 *px_ptr= pred_x = mid_pred(P_left[0], P_top[0], P_topright[0]);
446 *py_ptr= pred_y = mid_pred(P_left[1], P_top[1], P_topright[1]);
447
448 CHECK_MV(pred_x>>shift, pred_y>>shift)
449 if(dmin<Z_THRESHOLD){
450 *mx_ptr= pred_x>>shift;
451 *my_ptr= pred_y>>shift;
452 //printf("M");
453 return dmin;
454 }
455
456 CHECK_MV(P_left [0]>>shift, P_left [1]>>shift)
457 CHECK_MV(P_top [0]>>shift, P_top [1]>>shift)
458 CHECK_MV(P_topright[0]>>shift, P_topright[1]>>shift)
459 CHECK_MV(P_last [0]>>shift, P_last [1]>>shift)
460 }
461
462 dmin= small_diamond_search(s, best, dmin, new_pic, old_pic, pic_stride,
463 pred_x, pred_y, mv_penalty, quant, xmin, ymin, xmax, ymax, shift);
464 *mx_ptr= best[0];
465 *my_ptr= best[1];
466
467 // printf("%d %d %d \n", best[0], best[1], dmin);
468
469 return dmin;
470 }
471
472 #define CHECK_HALF_MV(suffix, x, y) \
473 d= pix_abs16x16_ ## suffix(pix, ptr+((x)>>1), s->linesize, 16);\
474 d += (mv_penalty[pen_x + x] + mv_penalty[pen_y + y])*quant;\
475 if(d<dminh){\
476 dminh= d;\
477 mx= mx1 + x;\
478 my= my1 + y;\
479 }
480
331 /* The idea would be to make half pel ME after Inter/Intra decision to 481 /* The idea would be to make half pel ME after Inter/Intra decision to
332 save time. */ 482 save time. */
333 static void halfpel_motion_search(MpegEncContext * s, 483 static inline void halfpel_motion_search(MpegEncContext * s,
334 int *mx_ptr, int *my_ptr, int dmin, 484 int *mx_ptr, int *my_ptr, int dmin,
335 int xmin, int ymin, int xmax, int ymax) 485 int xmin, int ymin, int xmax, int ymax,
336 { 486 int pred_x, int pred_y)
487 {
488 UINT16 *mv_penalty= s->mv_penalty[s->f_code] + MAX_MV; // f_code of the prev frame
489 const int quant= s->qscale;
490 int pen_x, pen_y;
337 int mx, my, mx1, my1, d, xx, yy, dminh; 491 int mx, my, mx1, my1, d, xx, yy, dminh;
338 UINT8 *pix; 492 UINT8 *pix, *ptr;
339 493
340 mx = *mx_ptr << 1; 494
341 my = *my_ptr << 1; 495 mx = *mx_ptr;
496 my = *my_ptr;
497 ptr = s->last_picture[0] + (my * s->linesize) + mx;
342 498
343 xx = 16 * s->mb_x; 499 xx = 16 * s->mb_x;
344 yy = 16 * s->mb_y; 500 yy = 16 * s->mb_y;
345 501 pix = s->new_picture[0] + (yy * s->linesize) + xx;
502
346 dminh = dmin; 503 dminh = dmin;
347 504
348 /* Half pixel search */ 505 if (mx > xmin && mx < xmax &&
349 mx1 = mx; 506 my > ymin && my < ymax) {
350 my1 = my; 507
351 508 mx= mx1= 2*(mx - xx);
352 pix = s->new_picture[0] + (yy * s->linesize) + xx; 509 my= my1= 2*(my - yy);
353 510 if(dmin < Z_THRESHOLD && mx==0 && my==0){
354 if ((mx > (xmin << 1)) && mx < (xmax << 1) && 511 *mx_ptr = 0;
355 (my > (ymin << 1)) && my < (ymax << 1)) { 512 *my_ptr = 0;
356 int dx, dy, px, py; 513 return;
357 UINT8 *ptr;
358 for (dy = -1; dy <= 1; dy++) {
359 for (dx = -1; dx <= 1; dx++) {
360 if (dx != 0 || dy != 0) {
361 px = mx1 + dx;
362 py = my1 + dy;
363 ptr = s->last_picture[0] + ((py >> 1) * s->linesize) + (px >> 1);
364 switch (((py & 1) << 1) | (px & 1)) {
365 default:
366 case 0:
367 d = pix_abs16x16(pix, ptr, s->linesize, 16);
368 break;
369 case 1:
370 d = pix_abs16x16_x2(pix, ptr, s->linesize, 16);
371 break;
372 case 2:
373 d = pix_abs16x16_y2(pix, ptr, s->linesize, 16);
374 break;
375 case 3:
376 d = pix_abs16x16_xy2(pix, ptr, s->linesize, 16);
377 break;
378 }
379 if (d < dminh) {
380 dminh = d;
381 mx = px;
382 my = py;
383 }
384 }
385 }
386 } 514 }
387 } 515
388 516 pen_x= pred_x + mx;
389 *mx_ptr = mx - (xx << 1); 517 pen_y= pred_y + my;
390 *my_ptr = my - (yy << 1); 518
391 //fprintf(stderr,"half - MX: %d\tMY: %d\n",*mx_ptr ,*my_ptr); 519 ptr-= s->linesize;
520 CHECK_HALF_MV(xy2, -1, -1)
521 CHECK_HALF_MV(y2 , 0, -1)
522 CHECK_HALF_MV(xy2, +1, -1)
523
524 ptr+= s->linesize;
525 CHECK_HALF_MV(x2 , -1, 0)
526 CHECK_HALF_MV(x2 , +1, 0)
527 CHECK_HALF_MV(xy2, -1, +1)
528 CHECK_HALF_MV(y2 , 0, +1)
529 CHECK_HALF_MV(xy2, +1, +1)
530 }else{
531 mx= 2*(mx - xx);
532 my= 2*(my - yy);
533 }
534
535 *mx_ptr = mx;
536 *my_ptr = my;
392 } 537 }
393 538
394 #ifndef CONFIG_TEST_MV_ENCODE 539 #ifndef CONFIG_TEST_MV_ENCODE
395 540
396 int estimate_motion(MpegEncContext * s, 541 int estimate_motion(MpegEncContext * s,
398 int *mx_ptr, int *my_ptr) 543 int *mx_ptr, int *my_ptr)
399 { 544 {
400 UINT8 *pix, *ppix; 545 UINT8 *pix, *ppix;
401 int sum, varc, vard, mx, my, range, dmin, xx, yy; 546 int sum, varc, vard, mx, my, range, dmin, xx, yy;
402 int xmin, ymin, xmax, ymax; 547 int xmin, ymin, xmax, ymax;
548 int pred_x=0, pred_y=0;
403 549
404 range = 8 * (1 << (s->f_code - 1)); 550 range = 8 * (1 << (s->f_code - 1));
405 /* XXX: temporary kludge to avoid overflow for msmpeg4 */ 551 /* XXX: temporary kludge to avoid overflow for msmpeg4 */
406 if (s->out_format == FMT_H263 && !s->h263_msmpeg4) 552 if (s->out_format == FMT_H263 && !s->h263_msmpeg4)
407 range = range * 2; 553 range = range * 2;
424 xmin = 0; 570 xmin = 0;
425 ymin = 0; 571 ymin = 0;
426 xmax = s->mb_width*16 - 16; 572 xmax = s->mb_width*16 - 16;
427 ymax = s->mb_height*16 - 16; 573 ymax = s->mb_height*16 - 16;
428 } 574 }
429
430 switch(s->full_search) { 575 switch(s->full_search) {
431 case ME_ZERO: 576 case ME_ZERO:
432 default: 577 default:
433 no_motion_search(s, &mx, &my); 578 no_motion_search(s, &mx, &my);
434 dmin = 0; 579 dmin = 0;
440 dmin = log_motion_search(s, &mx, &my, range / 2, xmin, ymin, xmax, ymax); 585 dmin = log_motion_search(s, &mx, &my, range / 2, xmin, ymin, xmax, ymax);
441 break; 586 break;
442 case ME_PHODS: 587 case ME_PHODS:
443 dmin = phods_motion_search(s, &mx, &my, range / 2, xmin, ymin, xmax, ymax); 588 dmin = phods_motion_search(s, &mx, &my, range / 2, xmin, ymin, xmax, ymax);
444 break; 589 break;
445 } 590 case ME_X1: // just reserving some space for experiments ...
446 emms_c(); 591 case ME_EPZS:
592 dmin = epzs_motion_search(s, &mx, &my, &pred_x, &pred_y, xmin, ymin, xmax, ymax);
593 mx+= s->mb_x*16;
594 my+= s->mb_y*16;
595 break;
596 }
447 597
448 /* intra / predictive decision */ 598 /* intra / predictive decision */
449 xx = mb_x * 16; 599 xx = mb_x * 16;
450 yy = mb_y * 16; 600 yy = mb_y * 16;
451 601
468 printf("varc=%4d avg_var=%4d (sum=%4d) vard=%4d mx=%2d my=%2d\n", 618 printf("varc=%4d avg_var=%4d (sum=%4d) vard=%4d mx=%2d my=%2d\n",
469 varc, s->avg_mb_var, sum, vard, mx - xx, my - yy); 619 varc, s->avg_mb_var, sum, vard, mx - xx, my - yy);
470 #endif 620 #endif
471 if (vard <= 64 || vard < varc) { 621 if (vard <= 64 || vard < varc) {
472 if (s->full_search != ME_ZERO) { 622 if (s->full_search != ME_ZERO) {
473 halfpel_motion_search(s, &mx, &my, dmin, xmin, ymin, xmax, ymax); 623 halfpel_motion_search(s, &mx, &my, dmin, xmin, ymin, xmax, ymax, pred_x, pred_y);
474 } else { 624 } else {
475 mx -= 16 * s->mb_x; 625 mx -= 16 * s->mb_x;
476 my -= 16 * s->mb_y; 626 my -= 16 * s->mb_y;
477 } 627 }
478 *mx_ptr = mx; 628 *mx_ptr = mx;