The new logic should be easier to follow. It also uses ff_inlink_consume_frame() for all simple passthrough operations making custom get_audio_buffer callback unnecessary. Fate changes are because the new logic does not repacketize input audio up until the crossfade. Content is the same.
Showing the changes to libavfilter (1 of 2 files). Show all
Unified · Split
| @@ -42,9 +42,8 @@ typedef struct AudioFadeContext { · 41 unmodified lines | ||
| 42 | 42 | double silence; |
| 43 | 43 | double unity; |
| 44 | 44 | int overlap; |
| 45 | − int status[2]; | |
| 46 | − int passthrough; | |
| 47 | 45 | int64_t pts; |
| 46 | + int xfade_status; | |
| 48 | 47 | |
| 49 | 48 | void (*fade_samples)(uint8_t **dst, uint8_t * const *src, |
| 50 | 49 | int nb_samples, int channels, int direction, |
| @@ -598,7 +597,6 @@ static int pass_crossfade(AVFilterContext *ctx) · 547 unmodified lines | ||
| 598 | 597 | out->pts = s->pts; |
| 599 | 598 | s->pts += av_rescale_q(s->nb_samples, |
| 600 | 599 | (AVRational){ 1, outlink->sample_rate }, outlink->time_base); |
| 601 | − s->passthrough = 1; | |
| 602 | 600 | av_frame_free(&cf[0]); |
| 603 | 601 | av_frame_free(&cf[1]); |
| 604 | 602 | return ff_filter_frame(outlink, out); |
| @@ -638,7 +636,6 @@ static int pass_crossfade(AVFilterContext *ctx) · 33 unmodified lines | ||
| 638 | 636 | out->pts = s->pts; |
| 639 | 637 | s->pts += av_rescale_q(s->nb_samples, |
| 640 | 638 | (AVRational){ 1, outlink->sample_rate }, outlink->time_base); |
| 641 | − s->passthrough = 1; | |
| 642 | 639 | av_frame_free(&cf[1]); |
| 643 | 640 | return ff_filter_frame(outlink, out); |
| 644 | 641 | } |
| @@ -648,42 +645,50 @@ static int activate(AVFilterContext *ctx) · 3 unmodified lines | ||
| 648 | 645 | { |
| 649 | 646 | AudioFadeContext *s = ctx->priv; |
| 650 | 647 | AVFilterLink *outlink = ctx->outputs[0]; |
| 651 | − int ret = 0, nb_samples; | |
| 652 | 648 | |
| 653 | 649 | FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx); |
| 654 | 650 | |
| 655 | − if (s->passthrough && s->status[0]) { | |
| 651 | + // Read first input until EOF | |
| 652 | + if (s->xfade_status == 0) { | |
| 653 | + int queued_samples = ff_inlink_queued_samples(ctx->inputs[0]); | |
| 654 | + if (queued_samples > s->nb_samples) { | |
| 655 | + AVFrame *frame = ff_inlink_peek_frame(ctx->inputs[0], 0); | |
| 656 | + if (queued_samples - s->nb_samples >= frame->nb_samples) | |
| 657 | + return pass_frame(ctx->inputs[0], outlink, &s->pts); | |
| 658 | + } | |
| 659 | + if (ff_outlink_get_status(ctx->inputs[0])) { | |
| 660 | + if (queued_samples > s->nb_samples) | |
| 661 | + return pass_samples(ctx->inputs[0], outlink, queued_samples - s->nb_samples, &s->pts); | |
| 662 | + s->xfade_status = 1; | |
| 663 | + } else { | |
| 664 | + FF_FILTER_FORWARD_WANTED(outlink, ctx->inputs[0]); | |
| 665 | + } | |
| 666 | + } | |
| 667 | + // Read second input until enough data is ready or EOF | |
| 668 | + if (s->xfade_status == 1) { | |
| 669 | + if (ff_inlink_queued_samples(ctx->inputs[1]) >= s->nb_samples || ff_outlink_get_status(ctx->inputs[1])) { | |
| 670 | + s->xfade_status = 2; | |
| 671 | + } else { | |
| 672 | + FF_FILTER_FORWARD_WANTED(outlink, ctx->inputs[1]); | |
| 673 | + } | |
| 674 | + } | |
| 675 | + // Do crossfade | |
| 676 | + if (s->xfade_status == 2) { | |
| 677 | + s->xfade_status = 3; | |
| 678 | + // TODO: Do some partial crossfade if not all inputs have enough duration? | |
| 679 | + if (ff_inlink_queued_samples(ctx->inputs[0]) >= s->nb_samples && | |
| 680 | + ff_inlink_queued_samples(ctx->inputs[1]) >= s->nb_samples) | |
| 681 | + return pass_crossfade(ctx); | |
| 682 | + } | |
| 683 | + // Read second input until EOF | |
| 684 | + if (s->xfade_status == 3) { | |
| 656 | 685 | if (ff_inlink_queued_frames(ctx->inputs[1])) |
| 657 | 686 | return pass_frame(ctx->inputs[1], outlink, &s->pts); |
| 658 | 687 | FF_FILTER_FORWARD_STATUS(ctx->inputs[1], outlink); |
| 659 | 688 | FF_FILTER_FORWARD_WANTED(outlink, ctx->inputs[1]); |
| 660 | 689 | } |
| 661 | 690 | |
| 662 | − nb_samples = ff_inlink_queued_samples(ctx->inputs[0]); | |
| 663 | − if (nb_samples > s->nb_samples) { | |
| 664 | − nb_samples -= s->nb_samples; | |
| 665 | − s->passthrough = 1; | |
| 666 | − return pass_samples(ctx->inputs[0], outlink, nb_samples, &s->pts); | |
| 667 | − } else if (s->status[0] && nb_samples >= s->nb_samples && | |
| 668 | − ff_inlink_queued_samples(ctx->inputs[1]) >= s->nb_samples) { | |
| 669 | − return pass_crossfade(ctx); | |
| 670 | − } else if (ff_outlink_frame_wanted(outlink)) { | |
| 671 | − if (!s->status[0] && ff_outlink_get_status(ctx->inputs[0])) | |
| 672 | − s->status[0] = AVERROR_EOF; | |
| 673 | − s->passthrough = !s->status[0]; | |
| 674 | − if (ff_outlink_get_status(ctx->inputs[1])) { | |
| 675 | − s->status[1] = AVERROR_EOF; | |
| 676 | − ff_outlink_set_status(outlink, AVERROR_EOF, AV_NOPTS_VALUE); | |
| 677 | − return 0; | |
| 678 | − } | |
| 679 | − if (!s->status[0]) | |
| 680 | − ff_inlink_request_frame(ctx->inputs[0]); | |
| 681 | − else | |
| 682 | − ff_inlink_request_frame(ctx->inputs[1]); | |
| 683 | − return 0; | |
| 684 | − } | |
| 685 | − | |
| 686 | − return ret; | |
| 691 | + return FFERROR_NOT_READY; | |
| 687 | 692 | } |
| 688 | 693 | |
| 689 | 694 | static int acrossfade_config_output(AVFilterLink *outlink) |
| @@ -709,26 +714,14 @@ static int acrossfade_config_output(AVFilterLink *outlink) · 19 unmodified lines | ||
| 709 | 714 | return 0; |
| 710 | 715 | } |
| 711 | 716 | |
| 712 | −static AVFrame *get_audio_buffer(AVFilterLink *inlink, int nb_samples) | |
| 713 | −{ | |
| 714 | − AVFilterContext *ctx = inlink->dst; | |
| 715 | − AudioFadeContext *s = ctx->priv; | |
| 716 | − | |
| 717 | − return s->passthrough ? | |
| 718 | − ff_null_get_audio_buffer (inlink, nb_samples) : | |
| 719 | − ff_default_get_audio_buffer(inlink, nb_samples); | |
| 720 | −} | |
| 721 | − | |
| 722 | 717 | static const AVFilterPad avfilter_af_acrossfade_inputs[] = { |
| 723 | 718 | { |
| 724 | 719 | .name = "crossfade0", |
| 725 | 720 | .type = AVMEDIA_TYPE_AUDIO, |
| 726 | − .get_buffer.audio = get_audio_buffer, | |
| 727 | 721 | }, |
| 728 | 722 | { |
| 729 | 723 | .name = "crossfade1", |
| 730 | 724 | .type = AVMEDIA_TYPE_AUDIO, |
| 731 | − .get_buffer.audio = get_audio_buffer, | |
| 732 | 725 | }, |
| 733 | 726 | }; |
| 734 | 727 | |