From 5f14543668f77b552b6b7690ff274736df02a9cc Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 1 Sep 2014 23:47:27 +0200 Subject: 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. --- DOCS/man/options.rst | 13 +++++++++++-- demux/demux_lavf.c | 24 +++++++++++++++++------- demux/stheader.h | 1 + options/options.c | 3 +++ options/options.h | 1 + player/loadfile.c | 15 +++++++++++---- 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 ```` as user agent for HTTP streaming. ``--cookies``, ``--no-cookies`` - (network only) Support cookies when making HTTP requests. Disabled by default. ``--cookies-file=`` - (network only) Read HTTP cookies from . 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=`` + 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) -- cgit v1.2.3