summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2019-12-18 01:37:03 +0100
committerwm4 <wm4@nowhere>2019-12-18 01:44:20 +0100
commit06c9c3819959d6dc41602fb16063c019a37eaa72 (patch)
tree6c8db05646f2b3b5d59c4d5bf75a4e30e5910a1a
parent0b9bc6f1809750692a1c6ad2225677643a1c0376 (diff)
downloadmpv-06c9c3819959d6dc41602fb16063c019a37eaa72.tar.bz2
mpv-06c9c3819959d6dc41602fb16063c019a37eaa72.tar.xz
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.
-rw-r--r--filters/f_lavfi.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/filters/f_lavfi.c b/filters/f_lavfi.c
index 23af326c9b..db01e27e3e 100644
--- a/filters/f_lavfi.c
+++ b/filters/f_lavfi.c
@@ -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);