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
This commit is contained in:
wm4 2020-07-09 12:29:22 +02:00
parent adbd28b1db
commit 06033df715
3 changed files with 29 additions and 1 deletions

View File

@ -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);

View File

@ -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);
}

View File

@ -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);