From: Marton Balint <cus@passwd.hu> To: ffmpeg-devel@ffmpeg.org Cc: Marton Balint <cus@passwd.hu> Subject: [FFmpeg-devel] [PATCH 4/4] avfilter/af_afade: rework crossfade activate logic Date: Thu, 24 Jul 2025 01:36:00 +0200 Message-ID: <20250723233604.29380-4-cus@passwd.hu> (raw) In-Reply-To: <20250723233604.29380-1-cus@passwd.hu> 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. Signed-off-by: Marton Balint <cus@passwd.hu> --- libavfilter/af_afade.c | 79 +++++++++++++--------------- tests/ref/fate/filter-acrossfade | 88 ++++++++++++++++---------------- 2 files changed, 80 insertions(+), 87 deletions(-) diff --git a/libavfilter/af_afade.c b/libavfilter/af_afade.c index baf972d17d..d4ea1a7bab 100644 --- a/libavfilter/af_afade.c +++ b/libavfilter/af_afade.c @@ -42,9 +42,8 @@ typedef struct AudioFadeContext { double silence; double unity; int overlap; - int status[2]; - int passthrough; int64_t pts; + int xfade_status; void (*fade_samples)(uint8_t **dst, uint8_t * const *src, int nb_samples, int channels, int direction, @@ -598,7 +597,6 @@ static int pass_crossfade(AVFilterContext *ctx) out->pts = s->pts; s->pts += av_rescale_q(s->nb_samples, (AVRational){ 1, outlink->sample_rate }, outlink->time_base); - s->passthrough = 1; av_frame_free(&cf[0]); av_frame_free(&cf[1]); return ff_filter_frame(outlink, out); @@ -638,7 +636,6 @@ static int pass_crossfade(AVFilterContext *ctx) out->pts = s->pts; s->pts += av_rescale_q(s->nb_samples, (AVRational){ 1, outlink->sample_rate }, outlink->time_base); - s->passthrough = 1; av_frame_free(&cf[1]); return ff_filter_frame(outlink, out); } @@ -648,42 +645,50 @@ static int activate(AVFilterContext *ctx) { AudioFadeContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; - int ret = 0, nb_samples; FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx); - if (s->passthrough && s->status[0]) { + // Read first input until EOF + if (s->xfade_status == 0) { + int queued_samples = ff_inlink_queued_samples(ctx->inputs[0]); + if (queued_samples > s->nb_samples) { + AVFrame *frame = ff_inlink_peek_frame(ctx->inputs[0], 0); + if (queued_samples - s->nb_samples >= frame->nb_samples) + return pass_frame(ctx->inputs[0], outlink, &s->pts); + } + if (ff_outlink_get_status(ctx->inputs[0])) { + if (queued_samples > s->nb_samples) + return pass_samples(ctx->inputs[0], outlink, queued_samples - s->nb_samples, &s->pts); + s->xfade_status = 1; + } else { + FF_FILTER_FORWARD_WANTED(outlink, ctx->inputs[0]); + } + } + // Read second input until enough data is ready or EOF + if (s->xfade_status == 1) { + if (ff_inlink_queued_samples(ctx->inputs[1]) >= s->nb_samples || ff_outlink_get_status(ctx->inputs[1])) { + s->xfade_status = 2; + } else { + FF_FILTER_FORWARD_WANTED(outlink, ctx->inputs[1]); + } + } + // Do crossfade + if (s->xfade_status == 2) { + s->xfade_status = 3; + // TODO: Do some partial crossfade if not all inputs have enough duration? + if (ff_inlink_queued_samples(ctx->inputs[0]) >= s->nb_samples && + ff_inlink_queued_samples(ctx->inputs[1]) >= s->nb_samples) + return pass_crossfade(ctx); + } + // Read second input until EOF + if (s->xfade_status == 3) { if (ff_inlink_queued_frames(ctx->inputs[1])) return pass_frame(ctx->inputs[1], outlink, &s->pts); FF_FILTER_FORWARD_STATUS(ctx->inputs[1], outlink); FF_FILTER_FORWARD_WANTED(outlink, ctx->inputs[1]); } - nb_samples = ff_inlink_queued_samples(ctx->inputs[0]); - if (nb_samples > s->nb_samples) { - nb_samples -= s->nb_samples; - s->passthrough = 1; - return pass_samples(ctx->inputs[0], outlink, nb_samples, &s->pts); - } else if (s->status[0] && nb_samples >= s->nb_samples && - ff_inlink_queued_samples(ctx->inputs[1]) >= s->nb_samples) { - return pass_crossfade(ctx); - } else if (ff_outlink_frame_wanted(outlink)) { - if (!s->status[0] && ff_outlink_get_status(ctx->inputs[0])) - s->status[0] = AVERROR_EOF; - s->passthrough = !s->status[0]; - if (ff_outlink_get_status(ctx->inputs[1])) { - s->status[1] = AVERROR_EOF; - ff_outlink_set_status(outlink, AVERROR_EOF, AV_NOPTS_VALUE); - return 0; - } - if (!s->status[0]) - ff_inlink_request_frame(ctx->inputs[0]); - else - ff_inlink_request_frame(ctx->inputs[1]); - return 0; - } - - return ret; + return FFERROR_NOT_READY; } static int acrossfade_config_output(AVFilterLink *outlink) @@ -709,26 +714,14 @@ static int acrossfade_config_output(AVFilterLink *outlink) return 0; } -static AVFrame *get_audio_buffer(AVFilterLink *inlink, int nb_samples) -{ - AVFilterContext *ctx = inlink->dst; - AudioFadeContext *s = ctx->priv; - - return s->passthrough ? - ff_null_get_audio_buffer (inlink, nb_samples) : - ff_default_get_audio_buffer(inlink, nb_samples); -} - static const AVFilterPad avfilter_af_acrossfade_inputs[] = { { .name = "crossfade0", .type = AVMEDIA_TYPE_AUDIO, - .get_buffer.audio = get_audio_buffer, }, { .name = "crossfade1", .type = AVMEDIA_TYPE_AUDIO, - .get_buffer.audio = get_audio_buffer, }, }; diff --git a/tests/ref/fate/filter-acrossfade b/tests/ref/fate/filter-acrossfade index f80aa10b55..92231bec7d 100644 --- a/tests/ref/fate/filter-acrossfade +++ b/tests/ref/fate/filter-acrossfade @@ -3,50 +3,50 @@ #codec_id 0: pcm_s16le #sample_rate 0: 44100 #channel_layout_name 0: stereo -0, 0, 0, 1912, 7648, 0x1294dd84 -0, 1912, 1912, 4096, 16384, 0x8d5eec9b -0, 6008, 6008, 4096, 16384, 0x9f15e8a9 -0, 10104, 10104, 4096, 16384, 0x5594dd9d -0, 14200, 14200, 4096, 16384, 0x5115d9bb -0, 18296, 18296, 4096, 16384, 0x0511d717 -0, 22392, 22392, 4096, 16384, 0x9cbdd713 -0, 26488, 26488, 4096, 16384, 0x2f13e615 -0, 30584, 30584, 4096, 16384, 0x415ae9f7 -0, 34680, 34680, 4096, 16384, 0x8d5eec9b -0, 38776, 38776, 4096, 16384, 0x9f15e8a9 -0, 42872, 42872, 4096, 16384, 0xd9809dcd -0, 46968, 46968, 4096, 16384, 0x7b60ec15 -0, 51064, 51064, 4096, 16384, 0xe92de3eb -0, 55160, 55160, 4096, 16384, 0x063d2c76 -0, 59256, 59256, 4096, 16384, 0xacbed331 -0, 63352, 63352, 4096, 16384, 0x1137d0c7 -0, 67448, 67448, 4096, 16384, 0xafbad1d7 -0, 71544, 71544, 4096, 16384, 0xb2a0040c -0, 75640, 75640, 4096, 16384, 0x83222d0c -0, 79736, 79736, 4096, 16384, 0x97993592 -0, 83832, 83832, 4096, 16384, 0x9e4200b2 -0, 87928, 87928, 4096, 16384, 0xf24c2685 -0, 92024, 92024, 4096, 16384, 0x0b23a4c8 -0, 96120, 96120, 4096, 16384, 0x9105fcde -0, 100216, 100216, 4096, 16384, 0xd4b64a6f -0, 104312, 104312, 4096, 16384, 0xef56c48a -0, 108408, 108408, 4096, 16384, 0xb12b9599 -0, 112504, 112504, 4096, 16384, 0x18bbeefd -0, 116600, 116600, 4096, 16384, 0x3fe2d14b -0, 120696, 120696, 4096, 16384, 0xf6d6fdff -0, 124792, 124792, 4096, 16384, 0x2e538447 -0, 128888, 128888, 4096, 16384, 0xd8251663 -0, 132984, 132984, 4096, 16384, 0xd783c943 -0, 137080, 137080, 4096, 16384, 0x3d64f7cf -0, 141176, 141176, 4096, 16384, 0x80e2c034 -0, 145272, 145272, 4096, 16384, 0x69a7e254 -0, 149368, 149368, 4096, 16384, 0xb3f5efb9 -0, 153464, 153464, 4096, 16384, 0x3975dea3 -0, 157560, 157560, 4096, 16384, 0x7ff7d2c5 -0, 161656, 161656, 4096, 16384, 0x5476e599 -0, 165752, 165752, 4096, 16384, 0x30e4f37a -0, 169848, 169848, 4096, 16384, 0x57c1a83c -0, 173944, 173944, 2456, 9824, 0x498532b3 +0, 0, 0, 4096, 16384, 0x02ebe66b +0, 4096, 4096, 4096, 16384, 0x35bfe081 +0, 8192, 8192, 4096, 16384, 0x3f90e0a9 +0, 12288, 12288, 4096, 16384, 0xd389dc43 +0, 16384, 16384, 4096, 16384, 0x9d5add49 +0, 20480, 20480, 4096, 16384, 0x378ee333 +0, 24576, 24576, 4096, 16384, 0xabf6df0f +0, 28672, 28672, 4096, 16384, 0xedefe76f +0, 32768, 32768, 4096, 16384, 0x02ebe66b +0, 36864, 36864, 4096, 16384, 0x35bfe081 +0, 40960, 40960, 4096, 16384, 0xdbc2b3b9 +0, 45056, 45056, 4096, 16384, 0xe92bd835 +0, 49152, 49152, 4096, 16384, 0x1126dca3 +0, 53248, 53248, 4096, 16384, 0x9647edcf +0, 57344, 57344, 4096, 16384, 0x5cc345aa +0, 61440, 61440, 4096, 16384, 0x19d7bd51 +0, 65536, 65536, 4096, 16384, 0x19eccef7 +0, 69632, 69632, 4096, 16384, 0x4b68eeed +0, 73728, 73728, 4096, 16384, 0x0b3d1bfc +0, 77824, 77824, 4096, 16384, 0xe9b2e069 +0, 81920, 81920, 4096, 16384, 0xcaa5590e +0, 86016, 86016, 4096, 16384, 0x47d0b227 +0, 90112, 90112, 4096, 16384, 0x446ba7a4 +0, 94208, 94208, 4096, 16384, 0x299b2e17 +0, 98304, 98304, 4096, 16384, 0xc51affa2 +0, 102400, 102400, 4096, 16384, 0xb4970fcf +0, 106496, 106496, 4096, 16384, 0xe48af9fc +0, 110592, 110592, 4096, 16384, 0xc2beffbb +0, 114688, 114688, 4096, 16384, 0xb9d99627 +0, 118784, 118784, 4096, 16384, 0xb65a2086 +0, 122880, 122880, 4096, 16384, 0x6386714b +0, 126976, 126976, 4096, 16384, 0x92a3171e +0, 131072, 131072, 4096, 16384, 0x78bad1e2 +0, 135168, 135168, 4096, 16384, 0x63301330 +0, 139264, 139264, 4096, 16384, 0xd663b943 +0, 143360, 143360, 4096, 16384, 0xdcafe377 +0, 147456, 147456, 4096, 16384, 0xfb2cd701 +0, 151552, 151552, 4096, 16384, 0x91c30201 +0, 155648, 155648, 4096, 16384, 0xf23da341 +0, 159744, 159744, 4096, 16384, 0xe8d5fa0a +0, 163840, 163840, 4096, 16384, 0x519bdfef +0, 167936, 167936, 4096, 16384, 0xf2fcd803 +0, 172032, 172032, 4096, 16384, 0xd5ceccbc +0, 176128, 176128, 272, 1088, 0xa8bc282b 0, 176400, 176400, 88200, 352800, 0x4fb492af 0, 264600, 264600, 1912, 7648, 0xf0c93a5a 0, 266512, 266512, 4096, 16384, 0x85454449 -- 2.43.0 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
prev parent reply other threads:[~2025-07-23 23:36 UTC|newest] Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top 2025-07-23 23:35 [FFmpeg-devel] [PATCH 1/4] avfilter/trim: consume all available frames and avoid activate reschedule Marton Balint 2025-07-23 23:35 ` [FFmpeg-devel] [PATCH 2/4] avfilter/af_afade: factorize functions generating frames Marton Balint 2025-07-23 23:35 ` [FFmpeg-devel] [PATCH 3/4] avfilter/af_afade: fix check_input for empty streams Marton Balint 2025-07-23 23:36 ` Marton Balint [this message]
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20250723233604.29380-4-cus@passwd.hu \ --to=cus@passwd.hu \ --cc=ffmpeg-devel@ffmpeg.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git