summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2019-11-16 13:15:45 +0100
committerwm4 <wm4@nowhere>2019-11-16 13:15:45 +0100
commitb6413f82b22b5c3bd7b0a4fec28fdd2625feaf94 (patch)
tree9947c7ca0acc90c15655503853cbaa0130016ec1
parent8d4e012bfa622c2ec0cb9972c49c51f525edb744 (diff)
downloadmpv-b6413f82b22b5c3bd7b0a4fec28fdd2625feaf94.tar.bz2
mpv-b6413f82b22b5c3bd7b0a4fec28fdd2625feaf94.tar.xz
demux_lavf: fight ffmpeg API some more and get the timeout set
It sometimes happens that HLS streams freeze because the HTTP server is not responding for a fragment (or something similar, the exact circumstances are unknown). The --timeout option didn't affect this, because it's never set on HLS recursive connections (these download the fragments, while the main connection likely nothing and just wastes a TCP socket). Apply an elaborate hack on top of an existing elaborate hack to somehow get these options set. Of course this could still break easily, but hey, it's ffmpeg, it can't not try to fuck you over. I'm so fucking sick of ffmpeg's API bullshit, especially wrt. HLS. Of course the change is sort of pointless. For HLS, GET requests should just aggressively retried (because they're not "streamed", they're just actual files on a CDN), while normal HTTP connections should probably not be made this fragile (they could be streamed, i.e. they are backed by some sort of real time encoder, and block if there is no data yet). The 1 minute default timeout is too high to save playback if this happens with HLS. Vaguely related to #5793.
-rw-r--r--DOCS/man/options.rst12
-rw-r--r--demux/demux_lavf.c31
2 files changed, 41 insertions, 2 deletions
diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst
index 6a73ac7a85..aaabed7696 100644
--- a/DOCS/man/options.rst
+++ b/DOCS/man/options.rst
@@ -3127,6 +3127,18 @@ Demuxer
the first song in the stream. Well, you won't get anything useful either
way if the seek is outside of mpv's cache.
+``--demuxer-lavf-propagate-opts=<yes|no>``
+ Propagate FFmpeg-level options to recursively opened connections (default:
+ yes). This is needed because FFmpeg will apply these settings to nested
+ AVIO contexts automatically. On the other hand, this could break in certain
+ situations - it's the FFmpeg API, you just can't win.
+
+ This affects in particular the ``--timeout`` option and anything passed
+ with ``--demuxer-lavf-o``.
+
+ If this option is deemed unnecessary at some point in the future, it will
+ be removed without notice.
+
``--demuxer-mkv-subtitle-preroll=<yes|index|no>``, ``--mkv-subtitle-preroll``
Try harder to show embedded soft subtitles when seeking somewhere. Normally,
it can happen that the subtitle at the seek target is not shown due to how
diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c
index 5153bfe42f..5f9d5a3781 100644
--- a/demux/demux_lavf.c
+++ b/demux/demux_lavf.c
@@ -79,6 +79,7 @@ struct demux_lavf_opts {
char *sub_cp;
int rtsp_transport;
int linearize_ts;
+ int propagate_opts;
};
const struct m_sub_options demux_lavf_conf = {
@@ -104,6 +105,7 @@ const struct m_sub_options demux_lavf_conf = {
{"http", 3})),
OPT_CHOICE("demuxer-lavf-linearize-timestamps", linearize_ts, 0,
({"no", 0}, {"auto", -1}, {"yes", 1})),
+ OPT_FLAG("demuxer-lavf-propagate-opts", propagate_opts, 0),
{0}
},
.size = sizeof(struct demux_lavf_opts),
@@ -118,6 +120,7 @@ const struct m_sub_options demux_lavf_conf = {
.sub_cp = "auto",
.rtsp_transport = 2,
.linearize_ts = -1,
+ .propagate_opts = 1,
},
};
@@ -232,6 +235,8 @@ typedef struct lavf_priv {
int linearize_ts;
bool any_ts_fixed;
+ AVDictionary *av_opts;
+
// Proxying nested streams.
struct nested_stream *nested;
int num_nested;
@@ -851,8 +856,27 @@ static int nested_io_open(struct AVFormatContext *s, AVIOContext **pb,
struct demuxer *demuxer = s->opaque;
lavf_priv_t *priv = demuxer->priv;
+ if (priv->opts->propagate_opts) {
+ // Copy av_opts to options, but only entries that are not present in
+ // options. (Hope this will break less by not overwriting important
+ // settings.)
+ AVDictionaryEntry *cur = NULL;
+ while ((cur = av_dict_get(priv->av_opts, "", cur, AV_DICT_IGNORE_SUFFIX)))
+ {
+ if (!*options || !av_dict_get(*options, cur->key, NULL, 0)) {
+ MP_TRACE(demuxer, "Nested option: '%s'='%s'\n",
+ cur->key, cur->value);
+ av_dict_set(options, cur->key, cur->value, 0);
+ } else {
+ MP_TRACE(demuxer, "Skipping nested option: '%s'\n", cur->key);
+ }
+ }
+ }
+
int r = priv->default_io_open(s, pb, url, flags, options);
if (r >= 0) {
+ if (options)
+ mp_avdict_print_unset(demuxer->log, MSGL_TRACE, *options);
struct nested_stream nest = {
.id = *pb,
};
@@ -972,16 +996,19 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
if (demuxer->access_references) {
priv->default_io_open = avfc->io_open;
priv->default_io_close = avfc->io_close;
-#if !HAVE_FFMPEG_STRICT_ABI
avfc->io_open = nested_io_open;
avfc->io_close = nested_io_close;
-#endif
} else {
avfc->io_open = block_io_open;
}
mp_set_avdict(&dopts, lavfdopts->avopts);
+ if (av_dict_copy(&priv->av_opts, dopts, 0) < 0) {
+ av_dict_free(&dopts);
+ return -1;
+ }
+
if (avformat_open_input(&avfc, priv->filename, priv->avif, &dopts) < 0) {
MP_ERR(demuxer, "avformat_open_input() failed\n");
av_dict_free(&dopts);