summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2016-09-26 14:45:55 +0200
committerwm4 <wm4@nowhere>2016-09-26 16:49:35 +0200
commit0f110ad0e27583c5161cf27a3c17d1563253b368 (patch)
tree104289fc48d70a2d482851c31e9c3f30a566d699
parent41002c46f5256c170160aab5d45f2983c5bcf600 (diff)
downloadmpv-0f110ad0e27583c5161cf27a3c17d1563253b368.tar.bz2
mpv-0f110ad0e27583c5161cf27a3c17d1563253b368.tar.xz
stream_lavf: fix determining seekability
demux_lavf.c forces seek to being determined as supported if STREAM_CTRL_HAS_AVSEEK is returned as success. But it always succeeds with current FFmpeg versions. (Seems like Libav commit cae448cf broke this in early 2016.) Now we can't determine via private API whether the underlying protocol supports read_seek anymore. The affected protocols (mostly rtmp) also set seekable=0, meaning they signal they're not seekable, even though read_seek would work. (My guess is that this can't be fixed because even though seekable is in theory a combination of elaborate flags [of which only 1 is defined, AVIO_SEEKABLE_NORMAL], a seekable!=0 always means it's byte-seekable in some way.) So the FFmpeg API is being garbage _again_, and all what we can do is determining this via protocol name and a whitelist. Should fix the behavior reported in #1701.
-rw-r--r--stream/stream_lavf.c26
1 files changed, 23 insertions, 3 deletions
diff --git a/stream/stream_lavf.c b/stream/stream_lavf.c
index bd4e629136..67681d3c43 100644
--- a/stream/stream_lavf.c
+++ b/stream/stream_lavf.c
@@ -141,10 +141,30 @@ static int control(stream_t *s, int cmd, void *arg)
}
break;
}
- case STREAM_CTRL_HAS_AVSEEK:
- if (avio->read_seek)
- return 1;
+ case STREAM_CTRL_HAS_AVSEEK: {
+ // Starting at some point, read_seek is always available, and runtime
+ // behavior decides whether it exists or not. FFmpeg's API doesn't
+ // return anything helpful to determine seekability upfront, so here's
+ // a hardcoded whitelist. Not our fault.
+ // In addition we also have to jump through ridiculous hoops just to
+ // get the fucking protocol name.
+ const char *proto = NULL;
+ if (avio->av_class && avio->av_class->child_next) {
+ // This usually yields the URLContext (why does it even exist?),
+ // which holds the name of the actual protocol implementation.
+ void *child = avio->av_class->child_next(avio, NULL);
+ AVClass *cl = *(AVClass **)child;
+ if (cl && cl->item_name)
+ proto = cl->item_name(child);
+ }
+ static const char *const has_read_seek[] = {
+ "rtmp", "rtmpt", "rtmpe", "rtmpte", "rtmps", "rtmpts", "mmsh", 0};
+ for (int n = 0; has_read_seek[n]; n++) {
+ if (avio->read_seek && proto && strcmp(proto, has_read_seek[n]) == 0)
+ return 1;
+ }
break;
+ }
case STREAM_CTRL_GET_METADATA: {
*(struct mp_tags **)arg = read_icy(s);
if (!*(struct mp_tags **)arg)