X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavfilter%2Faf_adelay.c;h=6ac81c2a3e04cf77b8fd8af577f5b3cccf8a8d14;hb=4217e091fefe540a0aab767e4a0a2454808cb4aa;hp=d6d81ba7d803f4d9709b91188961e2730bac8bc7;hpb=8e789d244cc946bc350672eeb02453918b21a09f;p=ffmpeg diff --git a/libavfilter/af_adelay.c b/libavfilter/af_adelay.c index d6d81ba7d80..6ac81c2a3e0 100644 --- a/libavfilter/af_adelay.c +++ b/libavfilter/af_adelay.c @@ -19,10 +19,12 @@ */ #include "libavutil/avstring.h" +#include "libavutil/eval.h" #include "libavutil/opt.h" #include "libavutil/samplefmt.h" #include "avfilter.h" #include "audio.h" +#include "filters.h" #include "internal.h" typedef struct ChanDelay { @@ -34,12 +36,15 @@ typedef struct ChanDelay { typedef struct AudioDelayContext { const AVClass *class; + int all; char *delays; ChanDelay *chandelay; int nb_delays; int block_align; - unsigned max_delay; + int64_t padding; + int64_t max_delay; int64_t next_pts; + int eof; void (*delay_channel)(ChanDelay *d, int nb_samples, const uint8_t *src, uint8_t *dst); @@ -50,6 +55,7 @@ typedef struct AudioDelayContext { static const AVOption adelay_options[] = { { "delays", "set list of delays for each channel", OFFSET(delays), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, A }, + { "all", "use last available delay for remained channels", OFFSET(all), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, A }, { NULL } }; @@ -137,7 +143,7 @@ static int config_input(AVFilterLink *inlink) p = s->delays; for (i = 0; i < s->nb_delays; i++) { ChanDelay *d = &s->chandelay[i]; - float delay; + float delay, div; char type = 0; int ret; @@ -146,10 +152,14 @@ static int config_input(AVFilterLink *inlink) p = NULL; - ret = sscanf(arg, "%d%c", &d->delay, &type); + ret = av_sscanf(arg, "%d%c", &d->delay, &type); if (ret != 2 || type != 'S') { - sscanf(arg, "%f", &delay); - d->delay = delay * inlink->sample_rate / 1000.0; + div = type == 's' ? 1.0 : 1000.0; + if (av_sscanf(arg, "%f", &delay) != 1) { + av_log(ctx, AV_LOG_ERROR, "Invalid syntax for delay.\n"); + return AVERROR(EINVAL); + } + d->delay = delay * inlink->sample_rate / div; } if (d->delay < 0) { @@ -158,6 +168,26 @@ static int config_input(AVFilterLink *inlink) } } + if (s->all && i) { + for (int j = i; j < s->nb_delays; j++) + s->chandelay[j].delay = s->chandelay[i-1].delay; + } + + s->padding = s->chandelay[0].delay; + for (i = 1; i < s->nb_delays; i++) { + ChanDelay *d = &s->chandelay[i]; + + s->padding = FFMIN(s->padding, d->delay); + } + + if (s->padding) { + for (i = 0; i < s->nb_delays; i++) { + ChanDelay *d = &s->chandelay[i]; + + d->delay -= s->padding; + } + } + for (i = 0; i < s->nb_delays; i++) { ChanDelay *d = &s->chandelay[i]; @@ -210,26 +240,30 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) s->delay_channel(d, frame->nb_samples, src, dst); } - s->next_pts = frame->pts + av_rescale_q(frame->nb_samples, (AVRational){1, inlink->sample_rate}, inlink->time_base); + out_frame->pts = s->next_pts; + s->next_pts += av_rescale_q(frame->nb_samples, (AVRational){1, inlink->sample_rate}, inlink->time_base); av_frame_free(&frame); return ff_filter_frame(ctx->outputs[0], out_frame); } -static int request_frame(AVFilterLink *outlink) +static int activate(AVFilterContext *ctx) { - AVFilterContext *ctx = outlink->src; + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; AudioDelayContext *s = ctx->priv; - int ret; + AVFrame *frame = NULL; + int ret, status; + int64_t pts; - ret = ff_request_frame(ctx->inputs[0]); - if (ret == AVERROR_EOF && !ctx->is_disabled && s->max_delay) { - int nb_samples = FFMIN(s->max_delay, 2048); - AVFrame *frame; + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + if (s->padding) { + int nb_samples = FFMIN(s->padding, 2048); frame = ff_get_audio_buffer(outlink, nb_samples); if (!frame) return AVERROR(ENOMEM); - s->max_delay -= nb_samples; + s->padding -= nb_samples; av_samples_set_silence(frame->extended_data, 0, frame->nb_samples, @@ -240,19 +274,57 @@ static int request_frame(AVFilterLink *outlink) if (s->next_pts != AV_NOPTS_VALUE) s->next_pts += av_rescale_q(nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base); - ret = filter_frame(ctx->inputs[0], frame); + return ff_filter_frame(outlink, frame); + } + + ret = ff_inlink_consume_frame(inlink, &frame); + if (ret < 0) + return ret; + + if (ret > 0) + return filter_frame(inlink, frame); + + if (ff_inlink_acknowledge_status(inlink, &status, &pts)) { + if (status == AVERROR_EOF) + s->eof = 1; } - return ret; + if (s->eof && s->max_delay) { + int nb_samples = FFMIN(s->max_delay, 2048); + + frame = ff_get_audio_buffer(outlink, nb_samples); + if (!frame) + return AVERROR(ENOMEM); + s->max_delay -= nb_samples; + + av_samples_set_silence(frame->extended_data, 0, + frame->nb_samples, + outlink->channels, + frame->format); + + frame->pts = s->next_pts; + return filter_frame(inlink, frame); + } + + if (s->eof && s->max_delay == 0) { + ff_outlink_set_status(outlink, AVERROR_EOF, s->next_pts); + return 0; + } + + if (!s->eof) + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; } static av_cold void uninit(AVFilterContext *ctx) { AudioDelayContext *s = ctx->priv; - int i; - for (i = 0; i < s->nb_delays; i++) - av_freep(&s->chandelay[i].samples); + if (s->chandelay) { + for (int i = 0; i < s->nb_delays; i++) + av_freep(&s->chandelay[i].samples); + } av_freep(&s->chandelay); } @@ -261,16 +333,14 @@ static const AVFilterPad adelay_inputs[] = { .name = "default", .type = AVMEDIA_TYPE_AUDIO, .config_props = config_input, - .filter_frame = filter_frame, }, { NULL } }; static const AVFilterPad adelay_outputs[] = { { - .name = "default", - .request_frame = request_frame, - .type = AVMEDIA_TYPE_AUDIO, + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, }, { NULL } }; @@ -281,6 +351,7 @@ AVFilter ff_af_adelay = { .query_formats = query_formats, .priv_size = sizeof(AudioDelayContext), .priv_class = &adelay_class, + .activate = activate, .uninit = uninit, .inputs = adelay_inputs, .outputs = adelay_outputs,