mirror of https://github.com/mpv-player/mpv
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).
This commit is contained in:
parent
8fa036b3a0
commit
775a02aab5
|
@ -61,6 +61,8 @@ struct priv {
|
||||||
|
|
||||||
AVRational timebase_out;
|
AVRational timebase_out;
|
||||||
|
|
||||||
|
bool eof;
|
||||||
|
|
||||||
// options
|
// options
|
||||||
char *cfg_graph;
|
char *cfg_graph;
|
||||||
char **cfg_avopts;
|
char **cfg_avopts;
|
||||||
|
@ -71,6 +73,8 @@ static void destroy_graph(struct af_instance *af)
|
||||||
struct priv *p = af->priv;
|
struct priv *p = af->priv;
|
||||||
avfilter_graph_free(&p->graph);
|
avfilter_graph_free(&p->graph);
|
||||||
p->in = p->out = NULL;
|
p->in = p->out = NULL;
|
||||||
|
p->samples_in = 0;
|
||||||
|
p->eof = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool recreate_graph(struct af_instance *af, struct mp_audio *config)
|
static bool recreate_graph(struct af_instance *af, struct mp_audio *config)
|
||||||
|
@ -167,6 +171,12 @@ error:
|
||||||
return false;
|
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)
|
static int control(struct af_instance *af, int cmd, void *arg)
|
||||||
{
|
{
|
||||||
struct priv *p = af->priv;
|
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;
|
return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
|
||||||
}
|
}
|
||||||
|
case AF_CONTROL_RESET:
|
||||||
|
reset(af);
|
||||||
|
return AF_OK;
|
||||||
}
|
}
|
||||||
return AF_UNKNOWN;
|
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)
|
static int filter_frame(struct af_instance *af, struct mp_audio *data)
|
||||||
{
|
{
|
||||||
struct priv *p = af->priv;
|
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];
|
AVFilterLink *l_in = p->in->outputs[0];
|
||||||
|
|
||||||
AVFrame *frame = NULL;
|
|
||||||
if (data) {
|
if (data) {
|
||||||
frame = av_frame_alloc();
|
frame = av_frame_alloc();
|
||||||
if (!frame)
|
if (!frame)
|
||||||
|
@ -255,6 +275,9 @@ static int filter_out(struct af_instance *af)
|
||||||
{
|
{
|
||||||
struct priv *p = af->priv;
|
struct priv *p = af->priv;
|
||||||
|
|
||||||
|
if (!p->graph)
|
||||||
|
goto error;
|
||||||
|
|
||||||
AVFrame *frame = av_frame_alloc();
|
AVFrame *frame = av_frame_alloc();
|
||||||
if (!frame)
|
if (!frame)
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -262,7 +285,10 @@ static int filter_out(struct af_instance *af)
|
||||||
int err = av_buffersink_get_frame(p->out, frame);
|
int err = av_buffersink_get_frame(p->out, frame);
|
||||||
if (err == AVERROR(EAGAIN) || err == AVERROR_EOF) {
|
if (err == AVERROR(EAGAIN) || err == AVERROR_EOF) {
|
||||||
// Not an error situation - no more output buffers in queue.
|
// 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);
|
av_frame_free(&frame);
|
||||||
|
p->eof |= err == AVERROR_EOF;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue