summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2020-02-19 16:33:48 +0100
committerwm4 <wm4@nowhere>2020-02-19 16:33:48 +0100
commit6d8b4ca742d931634be19fb01d4310d7b7fb8de0 (patch)
tree9c97db4e42a8c181992b2172b08dbd339d3de61b
parent43c13e5ea23230edca38426d4a9eed049a70890e (diff)
downloadmpv-6d8b4ca742d931634be19fb01d4310d7b7fb8de0.tar.bz2
mpv-6d8b4ca742d931634be19fb01d4310d7b7fb8de0.tar.xz
ytdl_hook: add all_formats option
Pretty worthless I guess. I only tested one site (and 2 videos), it's somewhat likely that it will break with other sites. Even if you leave the option disabled (the default). Slightly related to #3548. This will allows you to use the bitrate stream selection mechanism, that was added for HLS, with normal videos.
-rw-r--r--DOCS/man/options.rst17
-rw-r--r--player/lua/ytdl_hook.lua103
2 files changed, 102 insertions, 18 deletions
diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst
index f0543c7275..6ef710137f 100644
--- a/DOCS/man/options.rst
+++ b/DOCS/man/options.rst
@@ -823,6 +823,19 @@ Program Behavior
should use ``%`` before any of the characters ``^$()%|,.[]*+-?`` to match
that character.
+ The ``all_formats`` script option accepts a boolean 'yes' or 'no',
+ and if 'yes' will attempt to add all formats found reported by youtube-dl
+ (default: no). Each format is added as a separate track. In addition, they
+ are delay-loaded, and actually opened only when a track is selected (this
+ should keep load times as low as without this option). It also adds average
+ bitrate metadata, if available, which means ``--hls-bitrate`` will decide
+ which track to select. (HLS used to be the only format whose alternative
+ quality streams were exposed in a similar way, thus the option name.) The
+ ``--ytdl-format`` option is essentially ignored. Although this mechanism
+ makes it possible to switch streams at runtime, it's not suitable for this
+ purpose for various technical reasons. In general, this option is not
+ useful, and was only added to show that it's possible.
+
.. admonition:: Examples
- ``--script-opts=ytdl_hook-exclude='^youtube%.com'``
@@ -837,6 +850,10 @@ Program Behavior
formats like HLS and DASH, if available, allowing for video/audio selection
in runtime. It's disabled ("no") by default for performance reasons.
+ .. admonition:: Why do the option names mix ``_`` and ``-``?
+
+ I have no idea.
+
``--ytdl-format=<ytdl|best|worst|mp4|webm|...>``
Video format/quality that is directly passed to youtube-dl. The possible
values are specific to the website and the video, for a given url the
diff --git a/player/lua/ytdl_hook.lua b/player/lua/ytdl_hook.lua
index 3526d907ea..37136dc8d5 100644
--- a/player/lua/ytdl_hook.lua
+++ b/player/lua/ytdl_hook.lua
@@ -5,7 +5,8 @@ local options = require 'mp.options'
local o = {
exclude = "",
try_ytdl_first = false,
- use_manifests = false
+ use_manifests = false,
+ all_formats = false,
}
options.read_options(o)
@@ -29,11 +30,38 @@ local safe_protos = Set {
"data"
}
--- Codec name as reported by youtube-dl mapped to mpv internal codec names.
-local map_codec_to_mpv = {
- ["vtt"] = "webvtt",
+local codec_map = {
+ ["vtt"] = "webvtt",
+ ["opus"] = "opus",
+ ["vp9"] = "vp9",
}
+-- Codec name as reported by youtube-dl mapped to mpv internal codec names.
+-- Fun fact: mpv will not really use the codec, but will still try to initialize
+-- the codec on track selection (just to scrap it), meaning it's only a hint,
+-- but one that may make initialization fail. On the other hand, if the codec
+-- is valid but completely different from the actual media, nothing bad happens.
+local function map_codec_to_mpv(codec)
+ if codec == nil then
+ return nil
+ end
+ local mc = codec_map[codec]
+ if mc then
+ return mc
+ end
+ if codec:sub(1, 5) == "avc1." then
+ return "h264"
+ end
+ if codec:sub(1, 5) == "av01." then
+ return "av1"
+ end
+ if codec:sub(1, 5) == "mp4a." then
+ return "aac"
+ end
+ print("unknoiwn codec " .. codec)
+ return nil
+end
+
local function exec(args)
local ret = mp.command_native({name = "subprocess",
args = args,
@@ -288,10 +316,26 @@ local function valid_manifest(json)
proto:find("^m3u8")
end
+local function as_integer(v, def)
+ def = def or 0
+ local num = math.floor(tonumber(v) or def)
+ if num > -math.huge and num < math.huge then
+ return num
+ end
+ return def
+end
+
local function add_single_video(json)
local streamurl = ""
local max_bitrate = 0
- local reqfmts = json["requested_formats"]
+ local formats = json["requested_formats"]
+ local duration = as_integer(json["duration"])
+
+ local use_all_formats = o.all_formats
+ local all_formats = json["formats"]
+ if use_all_formats and all_formats and (#all_formats > 0) then
+ formats = all_formats
+ end
-- prefer manifest_url if present
if o.use_manifests and valid_manifest(json) then
@@ -316,10 +360,11 @@ local function add_single_video(json)
end
-- DASH/split tracks
- elseif reqfmts then
+ elseif formats then
local streams = {}
+ local single_url = nil
- for _, track in pairs(reqfmts) do
+ for _, track in pairs(formats) do
local edl_track = nil
edl_track = edl_track_joined(track.fragments,
track.protocol, json.is_live,
@@ -327,24 +372,46 @@ local function add_single_video(json)
if not edl_track and not url_is_safe(track.url) then
return
end
+ local media_type = nil
+ local codec = nil
if track.vcodec and track.vcodec ~= "none" then
- -- video track
- streams[#streams + 1] = edl_track or track.url
+ media_type = "video"
+ codec = track.vcodec
elseif track.vcodec == "none" then
- -- audio track
- streams[#streams + 1] = edl_track or track.url
+ media_type = "audio"
+ codec = track.acodec
end
+ if not media_type then
+ return
+ end
+ local url = edl_track or track.url
+ local hdr = {"!new_stream", "!no_clip", "!no_chapters"}
+ if use_all_formats then
+ local codec = map_codec_to_mpv(codec)
+ hdr[#hdr + 1] = "!delay_open,media_type=" .. media_type ..
+ ",codec=" .. (codec or "null") .. ",w=" ..
+ as_integer(track.width) .. ",h=" .. as_integer(track.height)
+ local size = as_integer(track["filesize"])
+ local byterate = 0
+ if size > 0 and duration > 0 then
+ byterate = as_integer(size / duration)
+ end
+ hdr[#hdr + 1] = "!track_meta,title=" ..
+ edl_escape(track.format_note or "") ..
+ ",byterate=" .. byterate
+ end
+ hdr[#hdr + 1] = edl_escape(url)
+ streams[#streams + 1] = table.concat(hdr, ";")
+ -- In case there is only 1 of these streams.
+ -- Note: assumes it has no important EDL headers
+ single_url = url
end
if #streams > 1 then
-- merge them via EDL
- for i = 1, #streams do
- streams[i] = "!no_clip;!no_chapters;" .. edl_escape(streams[i])
- end
- streamurl = "edl://" ..
- table.concat(streams, ";!new_stream;") .. ";"
+ streamurl = "edl://" .. table.concat(streams, ";")
else
- streamurl = streams[1]
+ streamurl = single_url
end
elseif not (json.url == nil) then
@@ -392,7 +459,7 @@ local function add_single_video(json)
if not (sub == nil) then
local edl = "edl://!no_clip;!delay_open,media_type=sub"
- local codec = map_codec_to_mpv[sub_info.ext]
+ local codec = map_codec_to_mpv(sub_info.ext)
if codec then
edl = edl .. ",codec=" .. codec
end