Mercurial > libavcodec.hg
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; |