mirror of
https://github.com/mpv-player/mpv
synced 2025-04-24 12:24:21 +00:00
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.
This commit is contained in:
parent
8d92128f6b
commit
5f14543668
@ -2838,11 +2838,9 @@ Network
|
|||||||
Use ``<string>`` as user agent for HTTP streaming.
|
Use ``<string>`` as user agent for HTTP streaming.
|
||||||
|
|
||||||
``--cookies``, ``--no-cookies``
|
``--cookies``, ``--no-cookies``
|
||||||
(network only)
|
|
||||||
Support cookies when making HTTP requests. Disabled by default.
|
Support cookies when making HTTP requests. Disabled by default.
|
||||||
|
|
||||||
``--cookies-file=<filename>``
|
``--cookies-file=<filename>``
|
||||||
(network only)
|
|
||||||
Read HTTP cookies from <filename>. The file is assumed to be in Netscape
|
Read HTTP cookies from <filename>. The file is assumed to be in Netscape
|
||||||
format.
|
format.
|
||||||
|
|
||||||
@ -2882,6 +2880,17 @@ Network
|
|||||||
network transport when playing ``rtsp://...`` URLs. The value ``lavf``
|
network transport when playing ``rtsp://...`` URLs. The value ``lavf``
|
||||||
leaves the decision to libavformat.
|
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
|
DVB
|
||||||
---
|
---
|
||||||
|
@ -429,6 +429,19 @@ static void export_replaygain(demuxer_t *demuxer, sh_audio_t *sh, AVStream *st)
|
|||||||
#endif
|
#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)
|
static void handle_stream(demuxer_t *demuxer, int i)
|
||||||
{
|
{
|
||||||
lavf_priv_t *priv = demuxer->priv;
|
lavf_priv_t *priv = demuxer->priv;
|
||||||
@ -505,13 +518,9 @@ static void handle_stream(demuxer_t *demuxer, int i)
|
|||||||
if (sd)
|
if (sd)
|
||||||
sh_video->rotate = -av_display_rotation_get((uint32_t *)sd);
|
sh_video->rotate = -av_display_rotation_get((uint32_t *)sd);
|
||||||
#else
|
#else
|
||||||
AVDictionaryEntry *rot = av_dict_get(st->metadata, "rotate", NULL, 0);
|
int rot = dict_get_decimal(st->metadata, "rotate", -1);
|
||||||
if (rot && rot->value) {
|
if (rot >= 0)
|
||||||
char *end = NULL;
|
sh_video->rotate = rot;
|
||||||
long int r = strtol(rot->value, &end, 10);
|
|
||||||
if (end && !end[0])
|
|
||||||
sh_video->rotate = r;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
sh_video->rotate = ((sh_video->rotate % 360) + 360) % 360;
|
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);
|
AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0);
|
||||||
if (lang && lang->value)
|
if (lang && lang->value)
|
||||||
sh->lang = talloc_strdup(sh, lang->value);
|
sh->lang = talloc_strdup(sh, lang->value);
|
||||||
|
sh->hls_bitrate = dict_get_decimal(st->metadata, "variant_bitrate", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
select_tracks(demuxer, i);
|
select_tracks(demuxer, i);
|
||||||
|
@ -55,6 +55,7 @@ struct sh_stream {
|
|||||||
char *title;
|
char *title;
|
||||||
char *lang; // language code
|
char *lang; // language code
|
||||||
bool default_track; // container default track flag
|
bool default_track; // container default track flag
|
||||||
|
int hls_bitrate;
|
||||||
|
|
||||||
// stream is a picture (such as album art)
|
// stream is a picture (such as album art)
|
||||||
struct demux_packet *attached_picture;
|
struct demux_packet *attached_picture;
|
||||||
|
@ -202,6 +202,9 @@ const m_option_t mp_opts[] = {
|
|||||||
OPT_STRING("quvi-format", quvi_format, 0),
|
OPT_STRING("quvi-format", quvi_format, 0),
|
||||||
OPT_FLAG("quvi-fetch-subtitles", quvi_fetch_subtitles, 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
|
#if HAVE_CDDA
|
||||||
OPT_SUBSTRUCT("cdda", stream_cdda_opts, stream_cdda_conf, 0),
|
OPT_SUBSTRUCT("cdda", stream_cdda_opts, stream_cdda_conf, 0),
|
||||||
OPT_STRING("cdrom-device", cdrom_device, 0),
|
OPT_STRING("cdrom-device", cdrom_device, 0),
|
||||||
|
@ -123,6 +123,7 @@ typedef struct MPOpts {
|
|||||||
char *force_configdir;
|
char *force_configdir;
|
||||||
int use_filedir_conf;
|
int use_filedir_conf;
|
||||||
int network_rtsp_transport;
|
int network_rtsp_transport;
|
||||||
|
int hls_bitrate;
|
||||||
struct mp_cache_opts stream_cache;
|
struct mp_cache_opts stream_cache;
|
||||||
int chapterrange[2];
|
int chapterrange[2];
|
||||||
int edition_id;
|
int edition_id;
|
||||||
|
@ -464,13 +464,15 @@ static int match_lang(char **langs, char *lang)
|
|||||||
* 1b) track was passed explicitly (is not an auto-loaded subtitle)
|
* 1b) track was passed explicitly (is not an auto-loaded subtitle)
|
||||||
* 2) earlier match in lang list
|
* 2) earlier match in lang list
|
||||||
* 3) track is marked default
|
* 3) track is marked default
|
||||||
* 4) lower track number
|
* 4) attached picture, HLS bitrate
|
||||||
* If select_fallback is not set, 4) is only used to determine whether a
|
* 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
|
* matching track is preferred over another track. Otherwise, always pick a
|
||||||
* track (if nothing else matches, return the track with lowest ID).
|
* track (if nothing else matches, return the track with lowest ID).
|
||||||
*/
|
*/
|
||||||
// Return whether t1 is preferred over t2
|
// 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 ext1 = t1->is_external && !t1->no_default;
|
||||||
bool ext2 = t2->is_external && !t2->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;
|
return t1->default_track;
|
||||||
if (t1->attached_picture != t2->attached_picture)
|
if (t1->attached_picture != t2->attached_picture)
|
||||||
return !t1->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;
|
return t1->user_tid <= t2->user_tid;
|
||||||
}
|
}
|
||||||
static struct track *select_track(struct MPContext *mpctx,
|
static struct track *select_track(struct MPContext *mpctx,
|
||||||
@ -500,7 +507,7 @@ static struct track *select_track(struct MPContext *mpctx,
|
|||||||
continue;
|
continue;
|
||||||
if (track->user_tid == tid)
|
if (track->user_tid == tid)
|
||||||
return track;
|
return track;
|
||||||
if (!pick || compare_track(track, pick, langs))
|
if (!pick || compare_track(track, pick, langs, mpctx->opts))
|
||||||
pick = track;
|
pick = track;
|
||||||
}
|
}
|
||||||
if (pick && !select_fallback && !(pick->is_external && !pick->no_default)
|
if (pick && !select_fallback && !(pick->is_external && !pick->no_default)
|
||||||
|
Loading…
Reference in New Issue
Block a user