From 06033df715b433d41b1a0855cf7805ff8f66d664 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 9 Jul 2020 12:29:22 +0200 Subject: demux_lavf: workaround reading gif from unseekable streams FFmpeg, being the pile of trash as usual, recently broke this. Add our own trash hack to trashily workaround this shit. Fixes: #7893 --- demux/demux_lavf.c | 19 +++++++++++++++++++ stream/stream.c | 10 +++++++++- stream/stream.h | 1 + 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index 50b9e044e4..e3ebcbfdc6 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -148,6 +148,7 @@ struct format_hack { bool no_seek : 1; bool no_pcm_seek : 1; bool no_seek_on_no_duration : 1; + bool readall_on_no_streamseek : 1; }; #define BLACKLIST(fmt) {fmt, .ignore = true} @@ -186,6 +187,10 @@ static const struct format_hack format_hacks[] = { // reset timestamps, which causes all sorts of problems. {"ogg", .linearize_audio_ts = true, .use_stream_ids = true}, + // At some point, FFmpeg lost the ability to read gif from unseekable + // streams. + {"gif", .readall_on_no_streamseek = true}, + TEXTSUB("aqtitle"), TEXTSUB("jacosub"), TEXTSUB("microdvd"), TEXTSUB("mpl2"), TEXTSUB("mpsub"), TEXTSUB("pjs"), TEXTSUB("realtext"), TEXTSUB("sami"), TEXTSUB("srt"), TEXTSUB("stl"), TEXTSUB("subviewer"), @@ -1020,6 +1025,20 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) return -1; } + if (priv->format_hack.readall_on_no_streamseek && priv->pb && + !priv->pb->seekable) + { + MP_VERBOSE(demuxer, "Non-seekable demuxer pre-read hack...\n"); + // Read incremental to avoid unnecessary large buffer sizes. + int r = 0; + for (int n = 16; n < 29; n++) { + r = stream_peek(priv->stream, 1 << n); + if (r < (1 << n)) + break; + } + MP_VERBOSE(demuxer, "...did read %d bytes.\n", r); + } + if (avformat_open_input(&avfc, priv->filename, priv->avif, &dopts) < 0) { MP_ERR(demuxer, "avformat_open_input() failed\n"); av_dict_free(&dopts); diff --git a/stream/stream.c b/stream/stream.c index 8361cd8748..3c728eacac 100644 --- a/stream/stream.c +++ b/stream/stream.c @@ -611,11 +611,19 @@ int stream_read(stream_t *s, void *mem, int total) return total; } +// Read ahead so that at least forward_size bytes are readable ahead. Returns +// the actual forward amount available (restricted by EOF or buffer limits). +int stream_peek(stream_t *s, int forward_size) +{ + while (stream_read_more(s, forward_size)) {} + return s->buf_end - s->buf_cur; +} + // Like stream_read(), but do not advance the current position. This may resize // the buffer to satisfy the read request. int stream_read_peek(stream_t *s, void *buf, int buf_size) { - while (stream_read_more(s, buf_size)) {} + stream_peek(s, buf_size); return ring_copy(s, buf, buf_size, s->buf_cur); } diff --git a/stream/stream.h b/stream/stream.h index c127860ceb..2116fdde27 100644 --- a/stream/stream.h +++ b/stream/stream.h @@ -212,6 +212,7 @@ bool stream_seek_skip(stream_t *s, int64_t pos); bool stream_seek(stream_t *s, int64_t pos); int stream_read(stream_t *s, void *mem, int total); int stream_read_partial(stream_t *s, void *buf, int buf_size); +int stream_peek(stream_t *s, int forward_size); int stream_read_peek(stream_t *s, void *buf, int buf_size); void stream_drop_buffers(stream_t *s); int64_t stream_get_size(stream_t *s); -- cgit v1.2.3