summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-09-01 23:47:27 +0200
committerwm4 <wm4@nowhere>2014-09-01 23:47:27 +0200
commit5f14543668f77b552b6b7690ff274736df02a9cc (patch)
tree722a8ff1ccc6f93d04a32318da5f544a7a082e42
parent8d92128f6b587095b9983b17c96b68125b038a27 (diff)
downloadmpv-5f14543668f77b552b6b7690ff274736df02a9cc.tar.bz2
mpv-5f14543668f77b552b6b7690ff274736df02a9cc.tar.xz
player: simplistic HLS bitrate selection
--hls-bitrate=min/max lets you select the min or max bitrate. That's it. Something more sophisticated might be possible, but is probably not even worth the effort.
-rw-r--r--DOCS/man/options.rst13
-rw-r--r--demux/demux_lavf.c24
-rw-r--r--demux/stheader.h1
-rw-r--r--options/options.c3
-rw-r--r--options/options.h1
-rw-r--r--player/loadfile.c15
6 files changed, 44 insertions, 13 deletions
diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst
index da033d8997..5125756457 100644
--- a/DOCS/man/options.rst
+++ b/DOCS/man/options.rst
@@ -2838,11 +2838,9 @@ Network
Use ``<string>`` as user agent for HTTP streaming.
``--cookies``, ``--no-cookies``
- (network only)
Support cookies when making HTTP requests. Disabled by default.
``--cookies-file=<filename>``
- (network only)
Read HTTP cookies from <filename>. The file is assumed to be in Netscape
format.
@@ -2882,6 +2880,17 @@ Network
network transport when playing ``rtsp://...`` URLs. The value ``lavf``
leaves the decision to libavformat.
+``--hls-bitrate=<no|min|max>``
+ If HLS streams are played, this option controls what streams are selected
+ by default. The option allows the following parameters:
+
+ :no: Don't do anything special. Typically, this will simply pick the
+ first audio/video streams it can find. (Default.)
+ :min: Pick the streams with the lowest bitrate.
+ :max: Same, but highest bitrate.
+
+ The bitrate as used is sent by the server, and there's no guarantee it's
+ actually meaningful.
DVB
---
diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c
index 65a5264705..fda0698b9c 100644
--- a/demux/demux_lavf.c
+++ b/demux/demux_lavf.c
@@ -429,6 +429,19 @@ static void export_replaygain(demuxer_t *demuxer, sh_audio_t *sh, AVStream *st)
#endif
}
+// Return a dictionary entry as (decimal) integer.
+static int dict_get_decimal(AVDictionary *dict, const char *entry, int def)
+{
+ AVDictionaryEntry *e = av_dict_get(dict, entry, NULL, 0);
+ if (e && e->value) {
+ char *end = NULL;
+ long int r = strtol(e->value, &end, 10);
+ if (end && !end[0] && r >= INT_MIN && r <= INT_MAX)
+ return r;
+ }
+ return def;
+}
+
static void handle_stream(demuxer_t *demuxer, int i)
{
lavf_priv_t *priv = demuxer->priv;
@@ -505,13 +518,9 @@ static void handle_stream(demuxer_t *demuxer, int i)
if (sd)
sh_video->rotate = -av_display_rotation_get((uint32_t *)sd);
#else
- AVDictionaryEntry *rot = av_dict_get(st->metadata, "rotate", NULL, 0);
- if (rot && rot->value) {
- char *end = NULL;
- long int r = strtol(rot->value, &end, 10);
- if (end && !end[0])
- sh_video->rotate = r;
- }
+ int rot = dict_get_decimal(st->metadata, "rotate", -1);
+ if (rot >= 0)
+ sh_video->rotate = rot;
#endif
sh_video->rotate = ((sh_video->rotate % 360) + 360) % 360;
@@ -589,6 +598,7 @@ static void handle_stream(demuxer_t *demuxer, int i)
AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0);
if (lang && lang->value)
sh->lang = talloc_strdup(sh, lang->value);
+ sh->hls_bitrate = dict_get_decimal(st->metadata, "variant_bitrate", 0);
}
select_tracks(demuxer, i);
diff --git a/demux/stheader.h b/demux/stheader.h
index 3fc8c999d4..af1e7bb44a 100644
--- a/demux/stheader.h
+++ b/demux/stheader.h
@@ -55,6 +55,7 @@ struct sh_stream {
char *title;
char *lang; // language code
bool default_track; // container default track flag
+ int hls_bitrate;
// stream is a picture (such as album art)
struct demux_packet *attached_picture;
diff --git a/options/options.c b/options/options.c
index 00c8c0fbb5..d436cb7535 100644
--- a/options/options.c
+++ b/options/options.c
@@ -202,6 +202,9 @@ const m_option_t mp_opts[] = {
OPT_STRING("quvi-format", quvi_format, 0),
OPT_FLAG("quvi-fetch-subtitles", quvi_fetch_subtitles, 0),
+ OPT_CHOICE("hls-bitrate", hls_bitrate, M_OPT_FIXED,
+ ({"no", 0}, {"min", 1}, {"max", 2})),
+
#if HAVE_CDDA
OPT_SUBSTRUCT("cdda", stream_cdda_opts, stream_cdda_conf, 0),
OPT_STRING("cdrom-device", cdrom_device, 0),
diff --git a/options/options.h b/options/options.h
index 701c9e236b..83593c837a 100644
--- a/options/options.h
+++ b/options/options.h
@@ -123,6 +123,7 @@ typedef struct MPOpts {
char *force_configdir;
int use_filedir_conf;
int network_rtsp_transport;
+ int hls_bitrate;
struct mp_cache_opts stream_cache;
int chapterrange[2];
int edition_id;
diff --git a/player/loadfile.c b/player/loadfile.c
index a8b61b749f..46a7067a9f 100644
--- a/player/loadfile.c
+++ b/player/loadfile.c
@@ -464,13 +464,15 @@ static int match_lang(char **langs, char *lang)
* 1b) track was passed explicitly (is not an auto-loaded subtitle)
* 2) earlier match in lang list
* 3) track is marked default
- * 4) lower track number
- * If select_fallback is not set, 4) is only used to determine whether a
+ * 4) attached picture, HLS bitrate
+ * 5) lower track number
+ * If select_fallback is not set, 5) is only used to determine whether a
* matching track is preferred over another track. Otherwise, always pick a
* track (if nothing else matches, return the track with lowest ID).
*/
// Return whether t1 is preferred over t2
-static bool compare_track(struct track *t1, struct track *t2, char **langs)
+static bool compare_track(struct track *t1, struct track *t2, char **langs,
+ struct MPOpts *opts)
{
bool ext1 = t1->is_external && !t1->no_default;
bool ext2 = t2->is_external && !t2->no_default;
@@ -485,6 +487,11 @@ static bool compare_track(struct track *t1, struct track *t2, char **langs)
return t1->default_track;
if (t1->attached_picture != t2->attached_picture)
return !t1->attached_picture;
+ if (t1->stream && t2->stream && opts->hls_bitrate) {
+ int d = t1->stream->hls_bitrate - t2->stream->hls_bitrate;
+ if (d)
+ return opts->hls_bitrate == 1 ? d < 0 : d > 0;
+ }
return t1->user_tid <= t2->user_tid;
}
static struct track *select_track(struct MPContext *mpctx,
@@ -500,7 +507,7 @@ static struct track *select_track(struct MPContext *mpctx,
continue;
if (track->user_tid == tid)
return track;
- if (!pick || compare_track(track, pick, langs))
+ if (!pick || compare_track(track, pick, langs, mpctx->opts))
pick = track;
}
if (pick && !select_fallback && !(pick->is_external && !pick->no_default)