yt-dlp / yt-dlp

A feature-rich command-line audio/video downloader
https://discord.gg/H5MNcFW63r
The Unlicense
91.67k stars 7.13k forks source link

Need help with embed-subs UNFORCED #2799

Open Spirograph12 opened 2 years ago

Spirograph12 commented 2 years ago

Checklist

Question

yt-dlp is great! Thanks so much guys. I have a 2-part question about subs. The 2 parts are closely related.

PART 1

I have a command I use on sites which employ .m3u8 master and .vtt subs. The command is:

yt-dlp "long m3u8 master link in quotes" -f best --remux-video mkv --convert-subs srt --embed-subs

This single command works perfectly, and gives me embedded srt subs which are OFF by default (not forced), which is exactly what I want. But my command is a bit brute force and disk intensive. Leaving out minor steps, it seems to do 4 full disk writes of the video:

  1. initial download
  2. fix .ts in .mp4
  3. remux to .mkv
  4. embed srt subs

This is NOT a bug. I just wonder whether there's a more elegant way to get the same result in a single command, but with fewer disk writes. Thanks in advance for any suggestions.

PART 2

If I use this command,

yt-dlp "long m3u8 master link in quotes" -f best --embed-subs

I get an .mp4 with embedded subs in mov_text format but they are ON by default. Is there a way to modify this command so that subs are OFF? My research suggests that in .mp4 ffmpeg sets the subs flag to ON by default. Supposedly, this behavior can be changed, maybe with something like:

--postprocessor-args "-default_mode infer_no_subs"

I've read the yt-dlp docs, but couldn't quite get my head around the syntax or positioning for this particular use case. Any help would be appreciated.

The most frequent use case is for embedded subs to be optional rather than forced. It would be a great convenience to end users if your Subtitle Options could include:

--subs-forced --subs-unforced

Thanks.

Verbose log

No response

pukkandan commented 2 years ago

Please provide an example link and verbose log so I can test your issue and suggestion

--postprocessor-args "-default_mode infer_no_subs"

I've read the yt-dlp docs, but couldn't quite get my head around the syntax or positioning for this particular use case. Any help would be appreciated.

You will need to refer ffmpeg docs for the positioning of the argument

Spirograph12 commented 2 years ago

Thanks for your help. Verbose logs are below. I learned more by using mediainfo to examine the mkv and mp4 files produced by yt-dlp. There are two parameters of interest here:

  1. Are subs flagged as "default"? (yes/no)
  2. Are subs flagged as "forced"? (yes/no)

Example HLS link: "https://video-2.hatchfarmstudios.com/d033564f-eb18-4945-937b-7d2fe013b4b5/master.m3u8?d=1&b=5"

-f 260 is smallest so let's use that.

Part 1: --embed-subs in mkv command:

yt-dlp --verbose "https://video-2.hatchfarmstudios.com/d033564f-eb18-4945-937b-7d2fe013b4b5/master.m3u8?d=1&b=5" -f 260 --remux-video mkv --convert-subs srt --embed-subs

Result: mkv file with embedded srt subs. Subs status (mediainfo): Default: No. Forced: No.

Log:

yt-dlp --verbose "https://video-2.hatchfarmstudios.com/d033564f-eb18-4945-937b-7d2fe013b4b5/master.m3u8?d=1&b=5" -f 260 --remux-video mkv --convert-subs srt --embed-subs
[debug] Command-line config: ['--verbose', 'https://video-2.hatchfarmstudios.com/d033564f-eb18-4945-937b-7d2fe013b4b5/master.m3u8?d=1&b=5', '-f', '260', '--remux-video', 'mkv', '--convert-subs', 'srt', '--embed-subs']
[debug] User config "/home/user/.config/yt-dlp/config": ['-o', '/media/user/ext120-f21/%(title)s-%(id)s.%(ext)s']
[debug] Encodings: locale UTF-8, fs utf-8, out utf-8, err utf-8, pref UTF-8
[debug] yt-dlp version 2022.02.04 [c1653e9ef] (zip)
[debug] Python version 3.8.10 (CPython 64bit) - Linux-5.4.0-99-generic-x86_64-with-glibc2.29
[debug] exe versions: ffmpeg 4.2.4, ffprobe 4.2.4, phantomjs 5, rtmpdump 2.4
[debug] Optional libraries: Cryptodome, secretstorage, mutagen, sqlite
[debug] Proxy map: {}
[debug] [generic] Extracting URL: https://video-2.hatchfarmstudios.com/d033564f-eb18-4945-937b-7d2fe013b4b5/master.m3u8?d=1&b=5
[generic] master: Requesting header
[debug] Identified a direct video link
[generic] master: Downloading m3u8 information
[debug] Formats sorted by: hasvid, ie_pref, lang, quality, res, fps, hdr:12(7), vcodec:vp9.2(10), acodec, filesize, fs_approx, tbr, vbr, abr, asr, proto, vext, aext, hasaud, source, id
[debug] Downloading subtitles: en
[info] master: Downloading 1 format(s): 260
[info] Writing video subtitles to: /media/user/ext120-f21/master-master.en.vtt
[debug] Invoking downloader on "https://video-2.hatchfarmstudios.com/d033564f-eb18-4945-937b-7d2fe013b4b5/subs/playlist.m3u8"
[hlsnative] Downloading m3u8 manifest
[hlsnative] Total fragments: 1
[download] Destination: /media/user/ext120-f21/master-master.en.vtt
[download] 100% of 33.88KiB in 00:00
[SubtitlesConvertor] Converting subtitles
[debug] ffmpeg command line: ffmpeg -y -loglevel repeat+info -i file:/media/user/ext120-f21/master-master.en.vtt -f srt -movflags +faststart file:/media/user/ext120-f21/master-master.en.srt
Deleting original file /media/user/ext120-f21/master-master.en.vtt (pass -k to keep)
[debug] Invoking downloader on "https://video-2.hatchfarmstudios.com/d033564f-eb18-4945-937b-7d2fe013b4b5/media-3/playlist.m3u8"
[hlsnative] Downloading m3u8 manifest
[hlsnative] Total fragments: 248
[download] Destination: /media/user/ext120-f21/master-master.mp4
[download] 100% of 46.24MiB in 00:43
[debug] ffprobe command line: ffprobe -hide_banner -show_format -show_streams -print_format json file:/media/user/ext120-f21/master-master.mp4
[FixupM3u8] Fixing MPEG-TS in MP4 container of "/media/user/ext120-f21/master-master.mp4"
[debug] ffmpeg command line: ffmpeg -y -loglevel repeat+info -i file:/media/user/ext120-f21/master-master.mp4 -map 0 -dn -ignore_unknown -c copy -f mp4 -bsf:a aac_adtstoasc -movflags +faststart file:/media/user/ext120-f21/master-master.temp.mp4
[VideoRemuxer] Remuxing video from mp4 to mkv; Destination: /media/user/ext120-f21/master-master.mkv
[debug] ffmpeg command line: ffmpeg -y -loglevel repeat+info -i file:/media/user/ext120-f21/master-master.mp4 -map 0 -dn -ignore_unknown -c copy -movflags +faststart file:/media/user/ext120-f21/master-master.mkv
Deleting original file /media/user/ext120-f21/master-master.mp4 (pass -k to keep)
[EmbedSubtitle] Embedding subtitles in "/media/user/ext120-f21/master-master.mkv"
[debug] ffmpeg command line: ffmpeg -y -loglevel repeat+info -i file:/media/user/ext120-f21/master-master.mkv -i file:/media/user/ext120-f21/master-master.en.srt -map 0 -dn -ignore_unknown -c copy -map -0:s -map 1:0 -metadata:s:s:0 language=eng -movflags +faststart file:/media/user/ext120-f21/master-master.temp.mkv
Deleting original file /media/user/ext120-f21/master-master.en.srt (pass -k to keep)

Part 2: --embed-subs in mp4 command:

yt-dlp --verbose "https://video-2.hatchfarmstudios.com/d033564f-eb18-4945-937b-7d2fe013b4b5/master.m3u8?d=1&b=5" -f 260 --embed-subs

Result: mp4 file with embedded mov_text subs. Subs status (mediainfo): Default: YES. Forced: No.

Log:

yt-dlp --verbose "https://video-2.hatchfarmstudios.com/d033564f-eb18-4945-937b-7d2fe013b4b5/master.m3u8?d=1&b=5" -f 260 --embed-subs
[debug] Command-line config: ['--verbose', 'https://video-2.hatchfarmstudios.com/d033564f-eb18-4945-937b-7d2fe013b4b5/master.m3u8?d=1&b=5', '-f', '260', '--embed-subs']
[debug] User config "/home/user/.config/yt-dlp/config": ['-o', '/media/user/ext120-f21/%(title)s-%(id)s.%(ext)s']
[debug] Encodings: locale UTF-8, fs utf-8, out utf-8, err utf-8, pref UTF-8
[debug] yt-dlp version 2022.02.04 [c1653e9ef] (zip)
[debug] Python version 3.8.10 (CPython 64bit) - Linux-5.4.0-99-generic-x86_64-with-glibc2.29
[debug] exe versions: ffmpeg 4.2.4, ffprobe 4.2.4, phantomjs 5, rtmpdump 2.4
[debug] Optional libraries: Cryptodome, secretstorage, mutagen, sqlite
[debug] Proxy map: {}
[debug] [generic] Extracting URL: https://video-2.hatchfarmstudios.com/d033564f-eb18-4945-937b-7d2fe013b4b5/master.m3u8?d=1&b=5
[generic] master: Requesting header
[debug] Identified a direct video link
[generic] master: Downloading m3u8 information
[debug] Formats sorted by: hasvid, ie_pref, lang, quality, res, fps, hdr:12(7), vcodec:vp9.2(10), acodec, filesize, fs_approx, tbr, vbr, abr, asr, proto, vext, aext, hasaud, source, id
[debug] Downloading subtitles: en
[info] master: Downloading 1 format(s): 260
[info] Writing video subtitles to: /media/user/ext120-f21/master-master.en.vtt
[debug] Invoking downloader on "https://video-2.hatchfarmstudios.com/d033564f-eb18-4945-937b-7d2fe013b4b5/subs/playlist.m3u8"
[hlsnative] Downloading m3u8 manifest
[hlsnative] Total fragments: 1
[download] Destination: /media/user/ext120-f21/master-master.en.vtt
[download] 100% of 33.88KiB in 00:00
[debug] Invoking downloader on "https://video-2.hatchfarmstudios.com/d033564f-eb18-4945-937b-7d2fe013b4b5/media-3/playlist.m3u8"
[hlsnative] Downloading m3u8 manifest
[hlsnative] Total fragments: 248
[download] Destination: /media/user/ext120-f21/master-master.mp4
[download] 100% of 46.24MiB in 00:21
[debug] ffprobe command line: ffprobe -hide_banner -show_format -show_streams -print_format json file:/media/user/ext120-f21/master-master.mp4
[FixupM3u8] Fixing MPEG-TS in MP4 container of "/media/user/ext120-f21/master-master.mp4"
[debug] ffmpeg command line: ffmpeg -y -loglevel repeat+info -i file:/media/user/ext120-f21/master-master.mp4 -map 0 -dn -ignore_unknown -c copy -f mp4 -bsf:a aac_adtstoasc -movflags +faststart file:/media/user/ext120-f21/master-master.temp.mp4
[EmbedSubtitle] Embedding subtitles in "/media/user/ext120-f21/master-master.mp4"
[debug] ffmpeg command line: ffmpeg -y -loglevel repeat+info -i file:/media/user/ext120-f21/master-master.mp4 -i file:/media/user/ext120-f21/master-master.en.vtt -map 0 -dn -ignore_unknown -c copy -c:s mov_text -map -0:s -map 1:0 -metadata:s:s:0 language=eng -movflags +faststart file:/media/user/ext120-f21/master-master.temp.mp4
Deleting original file /media/user/ext120-f21/master-master.en.vtt (pass -k to keep)

 -----

I had suggested a feature like:

--subs-forced --subs-unforced

With the parameters "default" and "forced" there are technically 4 possibilities. But for simplicity, maybe just 2 choices:

--subs-forced = Default: Yes & Forced: Yes. --subs-unforced = Default: No & Forced: No.

(Some media players will always play subs tagged as "default" even if not tagged as "forced".)

Thanks again for your time.

the-blank-x commented 2 years ago

What about adding another option, for example: --sub-state POLICY: Mark subtitles' default visibility. One of forced, default, or none (default: default).. There's no option for forced but not default since that wouldn't make much sense.

christoph-heinrich commented 2 years ago

~~According what I've found, this should work --ppa "EmbedSubtitle:-disposition:s:0 0 -default_mode infer_no_subs", but it doesn't. I'm sure the syntax is correct, because I can change it to disposition:s:1 1 to make the second subtitle track the default, but it's like the default_mode argument just gets ignored.~~

~~Edit: Right after writing this, I had the idea to apply those parameter to all post processing stages after EmbedSubtitle just to make sure that it doesn't end up getting set later on. Turns out that was the problem. --ppa "EmbedSubtitle:-disposition:s:0 0 -default_mode infer_no_subs" --ppa "Metadata:-disposition:s:0 0 -default_mode infer_no_subs" --ppa "EmbedThumbnail:-disposition:s:0 0 -default_mode infer_no_subs" This works. It's not pretty, and there has got to be a better way of doing this, but after trying to get this to work for way too long I'm just glad that it works.~~

Edit2: After a bit more experimenting I've found that using --ppa "EmbedThumbnail:-disposition:s 0 -default_mode infer_no_subs" is sufficient, because embedding thumbnails is the last stage in my test case, but that's not a good general solution as not all videos have thumbnails. What I don't understand is why only adding it to EmbedSubtitle doesn't work, as the default for default_mode should be passthrough, and as such it should leave the default flags as they were (specifying passthrough for all later stages also doesn't work). If someone knows why that is, please let me know.

Edit3: This seems like a ffmpeg bug to me. The ffmpeg documentation says about -default_mode passthrough

In this mode the FlagDefault is set if and only if the AV_DISPOSITION_DEFAULT flag is set in the disposition of the corresponding stream.

~~And so based on that one would assume that if no stream has the default flag set in the input, none of them would have it set on the output. And yet this command: --ppa "EmbedSubtitle:-disposition:s 0 -default_mode infer_no_subs" --ppa "Metadata:-default_mode passthrough" --ppa "EmbedThumbnail:-default_mode passthrough" results in one subtitle track being set to default. None of the ffmpeg commands after the subtitle one contain -disposition, so it doesn't get explicitly set either.~~

Now one could make the argument that this is intended behavior because the doc also says:

If no -disposition options were specified for an output file, ffmpeg will automatically set the ’default’ disposition on the first stream of each type, when there are multiple streams of this type in the output file and no stream of that type is already marked as default.

But that means there is no way of just leaving the default flags as they were, independent of if one was set or not.

Edit4: I realize this is getting ridiculous, but here I go again. So either I am stupid, or the way that option works is. If one doesn't want the default flag changed by ffmpeg, pass -disposition:s -0 or -disposition:s +0. Anything else will modify the default flag, at least in some circumstances. Makes me wonder if yt-dlp should maybe pass that by default, just to leave things the way they were if not specified otherwise.

So to not have any subtitles to be set to default, use --ppa "EmbedSubtitle:-disposition:s 0 -default_mode infer_no_subs" --ppa "Metadata:-disposition:s +0" --ppa "EmbedThumbnail:-disposition:s +0". If you have any another post processing steps calling ffmpeg after the subtitle one, you have to add -disposition:s +0 to those too.

Hopefully this will be of help to someone.