f_lavfi: add gross workaround for af_dynaudnorm bug

Better do this here than deal with the moronic project we unfortunately
depend on.

The workaround is generic; unknown whether it works correctly with
multi-input/output filters or filter graphs. It assumes that if all
inputs are EOF, and all outputs are EAGAIN, the bug happened.

This is pretty tricky, because anything could happen. Any time some form
of progress is made, the got_eagain state needs to be reset, because the
filter pad's state could have changed.
This commit is contained in:
wm4 2019-12-18 01:37:03 +01:00
parent 0b9bc6f180
commit 06c9c38199
1 changed files with 35 additions and 0 deletions

View File

@ -117,6 +117,7 @@ struct lavfi_pad {
AVFilterContext *buffer;
AVRational timebase;
bool buffer_is_eof; // received/sent EOF to the buffer
bool got_eagain;
struct mp_tags *metadata;
@ -140,6 +141,7 @@ static void free_graph(struct lavfi *c)
pad->buffer = NULL;
mp_frame_unref(&pad->in_fmt);
pad->buffer_is_eof = false;
pad->got_eagain = false;
}
c->initialized = false;
c->draining_recover = false;
@ -643,6 +645,9 @@ static bool feed_input_pads(struct lavfi *c)
MP_FATAL(c, "could not pass frame to filter\n");
av_frame_free(&frame);
for (int i = 0; i < c->num_out_pads; i++)
c->out_pads[i]->got_eagain = false;
progress = true;
}
@ -652,6 +657,26 @@ static bool feed_input_pads(struct lavfi *c)
return progress;
}
// Some filters get stuck and return EAGAIN forever if they did not get any
// input (i.e. we send only EOF as input). "dynaudnorm" is known to be affected.
static bool check_stuck_eagain_on_eof_bug(struct lavfi *c)
{
for (int n = 0; n < c->num_in_pads; n++) {
if (!c->in_pads[n]->buffer_is_eof)
return false;
}
for (int n = 0; n < c->num_out_pads; n++) {
struct lavfi_pad *pad = c->out_pads[n];
if (!pad->buffer_is_eof && !pad->got_eagain)
return false;
}
MP_WARN(c, "Filter is stuck. This is a FFmpeg bug. Treating as EOF.\n");
return true;
}
static bool read_output_pads(struct lavfi *c)
{
bool progress = false;
@ -669,6 +694,16 @@ static bool read_output_pads(struct lavfi *c)
int r = AVERROR_EOF;
if (!pad->buffer_is_eof)
r = av_buffersink_get_frame_flags(pad->buffer, c->tmp_frame, 0);
pad->got_eagain = r == AVERROR(EAGAIN);
if (pad->got_eagain) {
if (check_stuck_eagain_on_eof_bug(c))
r = AVERROR_EOF;
} else {
for (int i = 0; i < c->num_out_pads; i++)
c->out_pads[i]->got_eagain = false;
}
if (r >= 0) {
#if LIBAVUTIL_VERSION_MICRO >= 100
mp_tags_copy_from_av_dictionary(pad->metadata, c->tmp_frame->metadata);