Unified · Split
| @@ -77,10 +77,12 @@ typedef struct ShowWavesContext { · 76 unmodified lines | |||
| 77 | char *colors; | 77 | char *colors; |
| 78 | int buf_idx; | 78 | int buf_idx; |
| 79 | int16_t *buf_idy; /* y coordinate of previous sample for each channel */ | 79 | int16_t *buf_idy; /* y coordinate of previous sample for each channel */ |
| 80 | int16_t *history; | ||
| 81 | int history_nb_samples; | ||
| 82 | int history_index; | ||
| 80 | AVFrame *outpicref; | 83 | AVFrame *outpicref; |
| 81 | int n; | 84 | AVRational n, q, c; |
| 82 | int pixstep; | 85 | int pixstep; |
| 83 | int sample_count_mod; | ||
| 84 | int mode; ///< ShowWavesMode | 86 | int mode; ///< ShowWavesMode |
| 85 | int scale; ///< ShowWavesScale | 87 | int scale; ///< ShowWavesScale |
| 86 | int draw_mode; ///< ShowWavesDrawMode | 88 | int draw_mode; ///< ShowWavesDrawMode |
| @@ -111,7 +113,7 @@ static const AVOption showwaves_options[] = { · 24 unmodified lines | |||
| 111 | { "line", "draw a line for each sample", 0, AV_OPT_TYPE_CONST, {.i64=MODE_LINE}, .flags=FLAGS, .unit="mode"}, | 113 | { "line", "draw a line for each sample", 0, AV_OPT_TYPE_CONST, {.i64=MODE_LINE}, .flags=FLAGS, .unit="mode"}, |
| 112 | { "p2p", "draw a line between samples", 0, AV_OPT_TYPE_CONST, {.i64=MODE_P2P}, .flags=FLAGS, .unit="mode"}, | 114 | { "p2p", "draw a line between samples", 0, AV_OPT_TYPE_CONST, {.i64=MODE_P2P}, .flags=FLAGS, .unit="mode"}, |
| 113 | { "cline", "draw a centered line for each sample", 0, AV_OPT_TYPE_CONST, {.i64=MODE_CENTERED_LINE}, .flags=FLAGS, .unit="mode"}, | 115 | { "cline", "draw a centered line for each sample", 0, AV_OPT_TYPE_CONST, {.i64=MODE_CENTERED_LINE}, .flags=FLAGS, .unit="mode"}, |
| 114 | { "n", "set how many samples to show in the same point", OFFSET(n), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS }, | 116 | { "n", "set how many samples to show in the same point", OFFSET(n), AV_OPT_TYPE_RATIONAL, {.i64 = 0}, 0, INT_MAX, FLAGS }, |
| 115 | { "rate", "set video rate", OFFSET(rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, FLAGS }, | 117 | { "rate", "set video rate", OFFSET(rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, FLAGS }, |
| 116 | { "r", "set video rate", OFFSET(rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, FLAGS }, | 118 | { "r", "set video rate", OFFSET(rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, FLAGS }, |
| 117 | { "split_channels", "draw channels separately", OFFSET(split_channels), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS }, | 119 | { "split_channels", "draw channels separately", OFFSET(split_channels), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS }, |
| @@ -135,6 +137,7 @@ static av_cold void uninit(AVFilterContext *ctx) · 17 unmodified lines | |||
| 135 | 137 | ||
| 136 | av_frame_free(&showwaves->outpicref); | 138 | av_frame_free(&showwaves->outpicref); |
| 137 | av_freep(&showwaves->buf_idy); | 139 | av_freep(&showwaves->buf_idy); |
| 140 | av_freep(&showwaves->history); | ||
| 138 | av_freep(&showwaves->fg); | 141 | av_freep(&showwaves->fg); |
| 139 | 142 | ||
| 140 | if (showwaves->single_pic) { | 143 | if (showwaves->single_pic) { |
| @@ -422,29 +425,42 @@ static int config_output(AVFilterLink *outlink) · 281 unmodified lines | |||
| 422 | uint8_t x; | 425 | uint8_t x; |
| 423 | int ch; | 426 | int ch; |
| 424 | 427 | ||
| 425 | if (showwaves->single_pic) | 428 | showwaves->q = av_make_q(0, 1); |
| 426 | showwaves->n = 1; | 429 | showwaves->c = av_make_q(0, 1); |
| 427 | 430 | ||
| 428 | if (!showwaves->n) | 431 | if (showwaves->single_pic) { |
| 429 | showwaves->n = FFMAX(1, av_rescale_q(inlink->sample_rate, av_make_q(1, showwaves->w), showwaves->rate)); | 432 | showwaves->n = av_make_q(1, 1); |
| 433 | outlink->frame_rate = av_make_q(1, 1); | ||
| 434 | } else { | ||
| 435 | if (!showwaves->n.num || !showwaves->n.den) { | ||
| 436 | showwaves->n = av_mul_q(av_make_q(inlink->sample_rate, | ||
| 437 | showwaves->w), av_inv_q(showwaves->rate)); | ||
| 438 | outlink->frame_rate = showwaves->rate; | ||
| 439 | } else { | ||
| 440 | outlink->frame_rate = av_div_q(av_make_q(inlink->sample_rate, showwaves->w), showwaves->n); | ||
| 441 | } | ||
| 442 | } | ||
| 430 | 443 | ||
| 431 | showwaves->buf_idx = 0; | 444 | showwaves->buf_idx = 0; |
| 432 | if (!FF_ALLOCZ_TYPED_ARRAY(showwaves->buf_idy, nb_channels)) { | 445 | if (!FF_ALLOCZ_TYPED_ARRAY(showwaves->buf_idy, nb_channels)) { |
| 433 | av_log(ctx, AV_LOG_ERROR, "Could not allocate showwaves buffer\n"); | 446 | av_log(ctx, AV_LOG_ERROR, "Could not allocate showwaves buffer\n"); |
| 434 | return AVERROR(ENOMEM); | 447 | return AVERROR(ENOMEM); |
| 435 | } | 448 | } |
| 449 | |||
| 450 | showwaves->history_nb_samples = av_rescale(showwaves->w * nb_channels * 2, | ||
| 451 | showwaves->n.num, showwaves->n.den); | ||
| 452 | showwaves->history = av_calloc(showwaves->history_nb_samples, | ||
| 453 | sizeof(*showwaves->history)); | ||
| 454 | if (!showwaves->history) | ||
| 455 | return AVERROR(ENOMEM); | ||
| 456 | |||
| 457 | outlink->time_base = av_inv_q(outlink->frame_rate); | ||
| 436 | outlink->w = showwaves->w; | 458 | outlink->w = showwaves->w; |
| 437 | outlink->h = showwaves->h; | 459 | outlink->h = showwaves->h; |
| 438 | outlink->sample_aspect_ratio = (AVRational){1,1}; | 460 | outlink->sample_aspect_ratio = (AVRational){1,1}; |
| 439 | 461 | ||
| 440 | if (showwaves->single_pic) | 462 | av_log(ctx, AV_LOG_VERBOSE, "s:%dx%d r:%f n:%f\n", |
| 441 | outlink->frame_rate = av_make_q(1, 1); | 463 | showwaves->w, showwaves->h, av_q2d(outlink->frame_rate), av_q2d(showwaves->n)); |
| 442 | else | ||
| 443 | outlink->frame_rate = av_div_q((AVRational){inlink->sample_rate,showwaves->n}, | ||
| 444 | (AVRational){showwaves->w,1}); | ||
| 445 | |||
| 446 | av_log(ctx, AV_LOG_VERBOSE, "s:%dx%d r:%f n:%d\n", | ||
| 447 | showwaves->w, showwaves->h, av_q2d(outlink->frame_rate), showwaves->n); | ||
| 448 | 464 | ||
| 449 | switch (outlink->format) { | 465 | switch (outlink->format) { |
| 450 | case AV_PIX_FMT_GRAY8: | 466 | case AV_PIX_FMT_GRAY8: |
| @@ -524,7 +540,7 @@ static int config_output(AVFilterLink *outlink) · 73 unmodified lines | |||
| 524 | 540 | ||
| 525 | if (showwaves->draw_mode == DRAW_SCALE) { | 541 | if (showwaves->draw_mode == DRAW_SCALE) { |
| 526 | /* multiplication factor, pre-computed to avoid in-loop divisions */ | 542 | /* multiplication factor, pre-computed to avoid in-loop divisions */ |
| 527 | x = 255 / ((showwaves->split_channels ? 1 : nb_channels) * showwaves->n); | 543 | x = (showwaves->n.den * 255) / ((showwaves->split_channels ? 1 : nb_channels) * showwaves->n.num); |
| 528 | } else { | 544 | } else { |
| 529 | x = 255; | 545 | x = 255; |
| 530 | } | 546 | } |
| @@ -551,18 +567,23 @@ static int config_output(AVFilterLink *outlink) · 20 unmodified lines | |||
| 551 | return 0; | 567 | return 0; |
| 552 | } | 568 | } |
| 553 | 569 | ||
| 554 | inline static int push_frame(AVFilterLink *outlink) | 570 | inline static int push_frame(AVFilterLink *outlink, int i, int64_t pts) |
| 555 | { | 571 | { |
| 556 | AVFilterContext *ctx = outlink->src; | 572 | AVFilterContext *ctx = outlink->src; |
| 557 | AVFilterLink *inlink = ctx->inputs[0]; | 573 | AVFilterLink *inlink = ctx->inputs[0]; |
| 558 | ShowWavesContext *showwaves = outlink->src->priv; | 574 | ShowWavesContext *showwaves = outlink->src->priv; |
| 559 | int nb_channels = inlink->ch_layout.nb_channels; | 575 | int nb_channels = inlink->ch_layout.nb_channels; |
| 560 | int ret, i; | 576 | int ret; |
| 577 | |||
| 578 | showwaves->outpicref->duration = 1; | ||
| 579 | showwaves->outpicref->pts = av_rescale_q(pts + i, | ||
| 580 | inlink->time_base, | ||
| 581 | outlink->time_base); | ||
| 561 | 582 | ||
| 562 | ret = ff_filter_frame(outlink, showwaves->outpicref); | 583 | ret = ff_filter_frame(outlink, showwaves->outpicref); |
| 563 | showwaves->outpicref = NULL; | 584 | showwaves->outpicref = NULL; |
| 564 | showwaves->buf_idx = 0; | 585 | showwaves->buf_idx = 0; |
| 565 | for (i = 0; i < nb_channels; i++) | 586 | for (int i = 0; i < nb_channels; i++) |
| 566 | showwaves->buf_idy[i] = 0; | 587 | showwaves->buf_idy[i] = 0; |
| 567 | return ret; | 588 | return ret; |
| 568 | } | 589 | } |
| @@ -633,7 +654,7 @@ static int push_single_pic(AVFilterLink *outlink) · 64 unmodified lines | |||
| 633 | } | 654 | } |
| 634 | } | 655 | } |
| 635 | 656 | ||
| 636 | return push_frame(outlink); | 657 | return push_frame(outlink, 0, 0); |
| 637 | } | 658 | } |
| 638 | 659 | ||
| 639 | 660 | ||
| @@ -645,31 +666,23 @@ static int request_frame(AVFilterLink *outlink) · 5 unmodified lines | |||
| 645 | 666 | ||
| 646 | ret = ff_request_frame(inlink); | 667 | ret = ff_request_frame(inlink); |
| 647 | if (ret == AVERROR_EOF && showwaves->outpicref) { | 668 | if (ret == AVERROR_EOF && showwaves->outpicref) { |
| 648 | if (showwaves->single_pic) | 669 | push_single_pic(outlink); |
| 649 | push_single_pic(outlink); | ||
| 650 | else | ||
| 651 | push_frame(outlink); | ||
| 652 | } | 670 | } |
| 653 | 671 | ||
| 654 | return ret; | 672 | return ret; |
| 655 | } | 673 | } |
| 656 | 674 | ||
| 657 | static int alloc_out_frame(ShowWavesContext *showwaves, const int16_t *p, | 675 | static int alloc_out_frame(ShowWavesContext *showwaves, |
| 658 | const AVFilterLink *inlink, AVFilterLink *outlink, | 676 | AVFilterLink *outlink) |
| 659 | const AVFrame *in) | ||
| 660 | { | 677 | { |
| 661 | if (!showwaves->outpicref) { | 678 | if (!showwaves->outpicref) { |
| 662 | int j; | ||
| 663 | AVFrame *out = showwaves->outpicref = | 679 | AVFrame *out = showwaves->outpicref = |
| 664 | ff_get_video_buffer(outlink, outlink->w, outlink->h); | 680 | ff_get_video_buffer(outlink, outlink->w, outlink->h); |
| 665 | if (!out) | 681 | if (!out) |
| 666 | return AVERROR(ENOMEM); | 682 | return AVERROR(ENOMEM); |
| 667 | out->width = outlink->w; | 683 | out->width = outlink->w; |
| 668 | out->height = outlink->h; | 684 | out->height = outlink->h; |
| 669 | out->pts = in->pts + av_rescale_q((p - (int16_t *)in->data[0]) / inlink->ch_layout.nb_channels, | 685 | for (int j = 0; j < outlink->h; j++) |
| 670 | av_make_q(1, inlink->sample_rate), | ||
| 671 | outlink->time_base); | ||
| 672 | for (j = 0; j < outlink->h; j++) | ||
| 673 | memset(out->data[0] + j*out->linesize[0], 0, outlink->w * showwaves->pixstep); | 686 | memset(out->data[0] + j*out->linesize[0], 0, outlink->w * showwaves->pixstep); |
| 674 | } | 687 | } |
| 675 | return 0; | 688 | return 0; |
| @@ -696,45 +709,67 @@ static int showwaves_filter_frame(AVFilterLink *inlink, AVFrame *insamples) · 20 unmodified lines | |||
| 696 | ShowWavesContext *showwaves = ctx->priv; | 709 | ShowWavesContext *showwaves = ctx->priv; |
| 697 | const int nb_samples = insamples->nb_samples; | 710 | const int nb_samples = insamples->nb_samples; |
| 698 | AVFrame *outpicref = showwaves->outpicref; | 711 | AVFrame *outpicref = showwaves->outpicref; |
| 699 | int16_t *p = (int16_t *)insamples->data[0]; | 712 | const int16_t *p = (const int16_t *)insamples->data[0]; |
| 700 | int nb_channels = inlink->ch_layout.nb_channels; | 713 | int16_t *history = showwaves->history; |
| 701 | int i, j, ret = 0; | 714 | const int nb_channels = inlink->ch_layout.nb_channels; |
| 715 | int i, j, ret = 0, linesize; | ||
| 702 | const int pixstep = showwaves->pixstep; | 716 | const int pixstep = showwaves->pixstep; |
| 703 | const int n = showwaves->n; | ||
| 704 | const int ch_height = showwaves->split_channels ? outlink->h / nb_channels : outlink->h; | 717 | const int ch_height = showwaves->split_channels ? outlink->h / nb_channels : outlink->h; |
| 718 | const int history_nb_samples = showwaves->history_nb_samples; | ||
| 719 | const int split_channels = showwaves->split_channels; | ||
| 720 | const AVRational i_n = av_inv_q(showwaves->n); | ||
| 721 | const AVRational u_q = av_make_q(1, 1); | ||
| 722 | const AVRational z_q = av_make_q(0, 1); | ||
| 723 | int16_t *buf_idy = showwaves->buf_idy; | ||
| 724 | int idx = showwaves->history_index; | ||
| 725 | int buf_idx = showwaves->buf_idx; | ||
| 726 | const uint8_t *fg = showwaves->fg; | ||
| 727 | const int w = showwaves->w; | ||
| 728 | uint8_t *dst; | ||
| 729 | |||
| 730 | for (int n = 0; n < nb_samples * nb_channels; n++) { | ||
| 731 | history[idx++] = p[n]; | ||
| 732 | if (idx >= history_nb_samples) | ||
| 733 | idx = 0; | ||
| 734 | } | ||
| 735 | showwaves->history_index = idx; | ||
| 705 | 736 | ||
| 706 | /* draw data in the buffer */ | 737 | ret = alloc_out_frame(showwaves, outlink); |
| 707 | for (i = 0; i < nb_samples; i++) { | 738 | if (ret < 0) |
| 708 | 739 | goto end; | |
| 709 | ret = alloc_out_frame(showwaves, p, inlink, outlink, insamples); | 740 | outpicref = showwaves->outpicref; |
| 710 | if (ret < 0) | 741 | linesize = outpicref->linesize[0]; |
| 711 | goto end; | ||
| 712 | outpicref = showwaves->outpicref; | ||
| 713 | 742 | ||
| 743 | /* draw data in the buffer */ | ||
| 744 | dst = outpicref->data[0]; | ||
| 745 | for (i = 0; i < history_nb_samples; i++) { | ||
| 714 | for (j = 0; j < nb_channels; j++) { | 746 | for (j = 0; j < nb_channels; j++) { |
| 715 | uint8_t *buf = outpicref->data[0] + showwaves->buf_idx * pixstep; | 747 | uint8_t *buf = dst + buf_idx * pixstep; |
| 716 | const int linesize = outpicref->linesize[0]; | ||
| 717 | int h; | 748 | int h; |
| 718 | 749 | ||
| 719 | if (showwaves->split_channels) | 750 | if (split_channels) |
| 720 | buf += j*ch_height*linesize; | 751 | buf += j*ch_height*linesize; |
| 721 | h = showwaves->get_h(*p++, ch_height); | 752 | h = showwaves->get_h(history[idx++], ch_height); |
| 753 | if (idx >= history_nb_samples) | ||
| 754 | idx = 0; | ||
| 722 | showwaves->draw_sample(buf, ch_height, linesize, | 755 | showwaves->draw_sample(buf, ch_height, linesize, |
| 723 | &showwaves->buf_idy[j], &showwaves->fg[j * 4], h); | 756 | &buf_idy[j], &fg[j * 4], h); |
| 724 | } | 757 | } |
| 725 | 758 | ||
| 726 | showwaves->sample_count_mod++; | 759 | showwaves->c = av_add_q(showwaves->c, i_n); |
| 727 | if (showwaves->sample_count_mod == n) { | 760 | if (av_cmp_q(showwaves->c, u_q) >= 0) { |
| 728 | showwaves->sample_count_mod = 0; | 761 | showwaves->c = z_q; |
| 729 | showwaves->buf_idx++; | 762 | buf_idx++; |
| 730 | } | 763 | } |
| 731 | if (showwaves->buf_idx == showwaves->w || | 764 | if (buf_idx == w) |
| 732 | (ff_outlink_get_status(inlink) && i == nb_samples - 1)) | 765 | break; |
| 733 | if ((ret = push_frame(outlink)) < 0) | ||
| 734 | break; | ||
| 735 | outpicref = showwaves->outpicref; | ||
| 736 | } | 766 | } |
| 737 | 767 | ||
| 768 | showwaves->buf_idx = buf_idx; | ||
| 769 | |||
| 770 | if ((ret = push_frame(outlink, history_nb_samples - i - 1, insamples->pts)) < 0) | ||
| 771 | goto end; | ||
| 772 | outpicref = showwaves->outpicref; | ||
| 738 | end: | 773 | end: |
| 739 | av_frame_free(&insamples); | 774 | av_frame_free(&insamples); |
| 740 | return ret; | 775 | return ret; |
| @@ -745,17 +780,22 @@ static int activate(AVFilterContext *ctx) · 4 unmodified lines | |||
| 745 | AVFilterLink *inlink = ctx->inputs[0]; | 780 | AVFilterLink *inlink = ctx->inputs[0]; |
| 746 | AVFilterLink *outlink = ctx->outputs[0]; | 781 | AVFilterLink *outlink = ctx->outputs[0]; |
| 747 | ShowWavesContext *showwaves = ctx->priv; | 782 | ShowWavesContext *showwaves = ctx->priv; |
| 783 | AVRational q; | ||
| 748 | AVFrame *in; | 784 | AVFrame *in; |
| 749 | const int nb_samples = showwaves->n * outlink->w; | 785 | int nb_samples; |
| 750 | int ret; | 786 | int ret; |
| 751 | 787 | ||
| 752 | FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); | 788 | FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); |
| 753 | 789 | ||
| 790 | q = av_add_q(showwaves->q, av_mul_q(av_make_q(outlink->w, 1), showwaves->n)); | ||
| 791 | nb_samples = (q.num + (q.den / 2)) / q.den; | ||
| 754 | ret = ff_inlink_consume_samples(inlink, nb_samples, nb_samples, &in); | 792 | ret = ff_inlink_consume_samples(inlink, nb_samples, nb_samples, &in); |
| 755 | if (ret < 0) | 793 | if (ret < 0) |
| 756 | return ret; | 794 | return ret; |
| 757 | if (ret > 0) | 795 | if (ret > 0) { |
| 796 | showwaves->q = av_sub_q(q, av_make_q(nb_samples, 1)); | ||
| 758 | return showwaves_filter_frame(inlink, in); | 797 | return showwaves_filter_frame(inlink, in); |
| 798 | } | ||
| 759 | 799 | ||
| 760 | FF_FILTER_FORWARD_STATUS(inlink, outlink); | 800 | FF_FILTER_FORWARD_STATUS(inlink, outlink); |
| 761 | FF_FILTER_FORWARD_WANTED(outlink, inlink); | 801 | FF_FILTER_FORWARD_WANTED(outlink, inlink); |
| @@ -838,13 +878,12 @@ static int showwavespic_filter_frame(AVFilterLink *inlink, AVFrame *insamples) · 76 unmodified lines | |||
| 838 | AVFilterContext *ctx = inlink->dst; | 878 | AVFilterContext *ctx = inlink->dst; |
| 839 | AVFilterLink *outlink = ctx->outputs[0]; | 879 | AVFilterLink *outlink = ctx->outputs[0]; |
| 840 | ShowWavesContext *showwaves = ctx->priv; | 880 | ShowWavesContext *showwaves = ctx->priv; |
| 841 | int16_t *p = (int16_t *)insamples->data[0]; | ||
| 842 | int ret = 0; | 881 | int ret = 0; |
| 843 | 882 | ||
| 844 | if (showwaves->single_pic) { | 883 | if (showwaves->single_pic) { |
| 845 | struct frame_node *f; | 884 | struct frame_node *f; |
| 846 | 885 | ||
| 847 | ret = alloc_out_frame(showwaves, p, inlink, outlink, insamples); | 886 | ret = alloc_out_frame(showwaves, outlink); |
| 848 | if (ret < 0) | 887 | if (ret < 0) |
| 849 | goto end; | 888 | goto end; |
| 850 | 889 | ||