From 775a02aab56c8ca01e497517dad8a7526fe0c3ce Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 17 Mar 2015 22:31:05 +0100 Subject: af_lavfi: handle seeking To handle seeking correctly, we need to flush the filter. libavfilter does not support flushing, so we destroy and recreate it. We also need to handle resume-after-EOF, because the mpv audio code sends an EOF before and after seeking (the latter happens because the player drains the filter chain in a generic way, which "causes" EOF). --- audio/filter/af_lavfi.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'audio') diff --git a/audio/filter/af_lavfi.c b/audio/filter/af_lavfi.c index 902fe76e3a..249a560fb6 100644 --- a/audio/filter/af_lavfi.c +++ b/audio/filter/af_lavfi.c @@ -61,6 +61,8 @@ struct priv { AVRational timebase_out; + bool eof; + // options char *cfg_graph; char **cfg_avopts; @@ -71,6 +73,8 @@ static void destroy_graph(struct af_instance *af) struct priv *p = af->priv; avfilter_graph_free(&p->graph); p->in = p->out = NULL; + p->samples_in = 0; + p->eof = false; } static bool recreate_graph(struct af_instance *af, struct mp_audio *config) @@ -167,6 +171,12 @@ error: return false; } +static void reset(struct af_instance *af) +{ + if (!recreate_graph(af, &af->fmt_in)) + MP_FATAL(af, "Can't recreate libavfilter filter after a seek reset.\n"); +} + static int control(struct af_instance *af, int cmd, void *arg) { struct priv *p = af->priv; @@ -203,6 +213,9 @@ static int control(struct af_instance *af, int cmd, void *arg) return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE; } + case AF_CONTROL_RESET: + reset(af); + return AF_OK; } return AF_UNKNOWN; } @@ -210,9 +223,16 @@ static int control(struct af_instance *af, int cmd, void *arg) static int filter_frame(struct af_instance *af, struct mp_audio *data) { struct priv *p = af->priv; + AVFrame *frame = NULL; + + if (p->eof && data) + reset(af); + + if (!p->graph) + goto error; + AVFilterLink *l_in = p->in->outputs[0]; - AVFrame *frame = NULL; if (data) { frame = av_frame_alloc(); if (!frame) @@ -255,6 +275,9 @@ static int filter_out(struct af_instance *af) { struct priv *p = af->priv; + if (!p->graph) + goto error; + AVFrame *frame = av_frame_alloc(); if (!frame) goto error; @@ -262,7 +285,10 @@ static int filter_out(struct af_instance *af) int err = av_buffersink_get_frame(p->out, frame); if (err == AVERROR(EAGAIN) || err == AVERROR_EOF) { // Not an error situation - no more output buffers in queue. + // AVERROR_EOF means we shouldn't even give the filter more + // input, but we don't handle that completely correctly. av_frame_free(&frame); + p->eof |= err == AVERROR_EOF; return 0; } -- cgit v1.2.3