mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-11-13 12:35:05 +00:00
feat(tracks): download and mux stereoscopic 3D (MV-HEVC) video to MP4
Mark 3D from REQ-VIDEO-LAYOUT, DV profile 20 codecs or an lhvC box; mux with MP4Box, decrypt with mp4decrypt, skip FFmpeg repack, sample cut and hybrid; add {3d} and env MP4Box.
This commit is contained in:
@@ -339,7 +339,7 @@ When you give both `season` and `episode`, the server combines them into a `"{se
|
||||
"bitrate": 8000, "bitrate_bps": 8000000, "width": 3840, "height": 2160,
|
||||
"resolution": "2160p", "fps": "24", "range": "HDR10",
|
||||
"range_display": "HDR", "scan_type": null, "closed_captions": [],
|
||||
"dv_compatible_bitstream": false, "hdr10plus": false, "hdr10_base": false, "language": "en",
|
||||
"dv_compatible_bitstream": false, "hdr10plus": false, "hdr10_base": false, "stereo": false, "language": "en",
|
||||
"is_original_lang": true,
|
||||
"name": null, "track_name": "English", "needs_repack": false, "edition": [], "note": null, "data": null,
|
||||
"drm": [], "descriptor": "DASH"
|
||||
|
||||
@@ -454,6 +454,7 @@ Two DV mechanisms sit on top of the track model. **DV fixup** re-exposes DV sign
|
||||
HLS and DASH streams that carry a valid DV RPU but advertise plain HEVC, with DV only in the
|
||||
supplemental codecs (`dv_compatible_bitstream`). `--list` shows such a track as `HDR10+DV` or `HDR10P+DV`.
|
||||
A service sets `hdr10_base` on a DV track that has an HDR10 base layer (DV profile 8.1), and `--list` shows it as `DV+HDR10`.
|
||||
The HLS and DASH parsers set `stereo` on a stereoscopic 3D (MV-HEVC) track: an HLS `REQ-VIDEO-LAYOUT` that names `CH-STEREO`, or a DV profile 20 codec. `--list` shows it as `3D`.
|
||||
**Hybrid** processing (`Video.Range.HYBRID`) selects an HDR10(+) base and a DV donor,
|
||||
extracts the RPU with `dovi_tool`, and injects it onto the base layer, to make a single
|
||||
track that carries both HDR10 metadata and the DV RPU. Both are automatic once the
|
||||
|
||||
@@ -268,7 +268,7 @@ download. For example, `dovi_tool` only matters if you download Dolby Vision vid
|
||||
| Tool | Binary looked up | Why it is needed |
|
||||
| --- | --- | --- |
|
||||
| Bento4 (`mp4decrypt`) | `mp4decrypt` | Alternative DRM decryptor to shaka-packager |
|
||||
| MP4Box (GPAC) | `MP4Box` | Muxing DTS:X Profile 2 (DTS-UHD) and MPEG-H audio |
|
||||
| MP4Box (GPAC) | `MP4Box` | Muxing DTS:X Profile 2 (DTS-UHD) and MPEG-H audio, and 3D video |
|
||||
| dovi_tool | `dovi_tool` | Dolby Vision metadata handling |
|
||||
| HDR10Plus_tool | `hdr10plus_tool` | HDR10+ metadata handling |
|
||||
| SubtitleEdit | `seconv`, `SubtitleEdit` | Subtitle conversion (the `SeConv` CLI from 5.x) |
|
||||
@@ -280,9 +280,9 @@ download. For example, `dovi_tool` only matters if you download Dolby Vision vid
|
||||
| Docker | `docker` | Gluetun VPN proxy support |
|
||||
| Git | `git` | Fetching and updating remote service repositories |
|
||||
|
||||
!!! info "MP4Box is only used for DTS:X Profile 2 and MPEG-H"
|
||||
Titles with DTS:X Profile 2 (DTS-UHD) or MPEG-H audio mux to MP4; everything else muxes to MKV
|
||||
with `mkvmerge`. Install with `apt install gpac`.
|
||||
!!! info "MP4Box is only used for DTS:X Profile 2, MPEG-H and 3D video"
|
||||
Titles with DTS:X Profile 2 (DTS-UHD) or MPEG-H audio, or a stereoscopic 3D video track, mux to
|
||||
MP4; everything else muxes to MKV with `mkvmerge`. Install with `apt install gpac`.
|
||||
|
||||
!!! tip "SubtitleEdit specifics"
|
||||
unshackle looks for `seconv` first, the batch CLI shipped with
|
||||
|
||||
@@ -164,6 +164,10 @@ unshackle dl -q 2160 -r HDR10,DV EXAMPLE '...'
|
||||
|
||||
The output file of a track with a Dolby Vision profile 8 RPU plays as Dolby Vision on a DV screen.
|
||||
|
||||
`--list` adds `3D` to a stereoscopic 3D (MV-HEVC) track, for example `[H.265, DV, 3D]`. When a title
|
||||
has a 2D and a 3D track at the same resolution, unshackle selects the 2D track. A 3D title muxes to
|
||||
MP4, see [3D output](output-and-naming.md#3d-output).
|
||||
|
||||
!!! warning "HYBRID requires dovi_tool"
|
||||
`-r HYBRID` makes a single hybrid track by injecting the Dolby Vision RPU
|
||||
metadata onto an HDR10/HDR10+ base layer with **dovi_tool**.
|
||||
|
||||
@@ -15,7 +15,7 @@ When a download finishes, unshackle builds the final path from three pieces:
|
||||
- **Output directory**: `directories.downloads` from your config, or whatever you pass to `-o/--output` on the command line for a single run.
|
||||
- **Folder template**: an optional per-title subfolder. unshackle **always** puts TV episodes and songs in a folder. Movies only get one if you define a `movies` folder template, or a single-string `folder` template that applies to all title kinds (see [Folder templates](#folder-templates)).
|
||||
- **Filename template**: the `output_template` for the title kind (movie, series, or song).
|
||||
- **Extension**: chosen by the muxer for a movie or an episode: `.mkv` for video, `.mka` for audio-only, `.mks` for subtitle-only, `.mp4` for [DTS:X Profile 2 and MPEG-H audio](#dtsx-profile-2-and-mpeg-h-output). unshackle does not mux a song. It remuxes a song into the container of its codec, such as `.flac`, `.opus`, or `.m4a`. Read [Music output files](#music-output-files).
|
||||
- **Extension**: chosen by the muxer for a movie or an episode: `.mkv` for video, `.mka` for audio-only, `.mks` for subtitle-only, `.mp4` for [DTS:X Profile 2 and MPEG-H audio](#dtsx-profile-2-and-mpeg-h-output) and [3D video](#3d-output). unshackle does not mux a song. It remuxes a song into the container of its codec, such as `.flac`, `.opus`, or `.m4a`. Read [Music output files](#music-output-files).
|
||||
|
||||
!!! example "A typical episode path"
|
||||
```text
|
||||
@@ -110,6 +110,7 @@ Every variable below is valid in both output and folder templates. unshackle tak
|
||||
| `video` | Video codec | `H.264`, `H.265` |
|
||||
| `hdr` | Dynamic-range label | `HDR`, `HDR10P`, `DV`, `DV.HDR`, `DV.HDR10P`, `HLG` |
|
||||
| `hfr` | High frame rate marker (frame rate > 30) | `HFR` |
|
||||
| `3d` | Stereoscopic 3D marker (MV-HEVC video) | `3D` |
|
||||
| `edition` | Edition label from the track, if any | `Directors Cut` |
|
||||
| `tag` | Release-group tag (from `config.tag` or `--tag`) | `TAG` |
|
||||
| `repack` | `REPACK` when the `--repack` flag is used | `REPACK` |
|
||||
@@ -429,6 +430,23 @@ An MP4 title loses:
|
||||
- SubStation Alpha (`.ass`) subtitles
|
||||
- container tags (`mkvpropedit`)
|
||||
|
||||
### 3D output
|
||||
|
||||
A stereoscopic 3D (MV-HEVC) video track also muxes to MP4 with MP4Box, because Matroska has no
|
||||
mapping for its second view and `mkvmerge` drops it. There is no 3D Matroska output. unshackle
|
||||
finds a 3D track from the manifest, or from a second video layer in the downloaded file. The MP4
|
||||
title loses the same items as above. For a 3D title, unshackle also:
|
||||
|
||||
- decrypts the track with mp4decrypt, whatever [`decryption`](../reference/configuration/drm.md#decryption) selects
|
||||
- writes QuickTime chapters
|
||||
- keeps the whole downloaded segments of a `--sample` run, because the MP4Box cut removes the 3D signalling
|
||||
- does not repack the track or rewrite its colour metadata with FFmpeg
|
||||
- writes no `--include-sample` sample, because `mkvmerge` cuts only Matroska files
|
||||
- never uses the track in a `HYBRID` merge
|
||||
|
||||
A Dolby Vision profile 20 track has no HDR10 base layer, so a player without Dolby Vision shows
|
||||
wrong colours.
|
||||
|
||||
You configure muxing (the combination of video, audio, subtitle, chapter and attachment tracks into a single Matroska file with `mkvmerge`) under the `muxing` config key. unshackle muxes only movies and episodes. Read [Music output files](#music-output-files) for what a music download does instead.
|
||||
|
||||
```yaml title="unshackle.yaml"
|
||||
@@ -475,6 +493,7 @@ The `--no-mux` flag skips muxing entirely and writes the individual track files,
|
||||
[`--sample`](cli-reference.md#output-muxing-files) and `--include-sample` write a sample into a
|
||||
`Sample` folder inside the output folder of the title. The sample keeps the filename of the
|
||||
title, with a `SAMPLE` tag at the end. The tag uses the separator of the output template.
|
||||
`--include-sample` cuts the sample with `mkvmerge`, so a title that muxes to MP4 gets no sample.
|
||||
|
||||
```text title="A movie with --include-sample"
|
||||
Some.Movie.2026.1080p.EXAMPLE.WEB-DL.H.264-TAG/
|
||||
|
||||
@@ -187,6 +187,10 @@ service tag case-insensitively and uses the `default` entry as the fallback.
|
||||
|
||||
unshackle decrypts HLS AES-128 ClearKey in-process and ignores this setting.
|
||||
|
||||
unshackle decrypts a stereoscopic 3D (MV-HEVC) track with mp4decrypt whatever this setting says.
|
||||
shaka-packager refuses its Dolby Vision configuration (version 3), and before v3.5.0 it also drops
|
||||
the boxes of the second view.
|
||||
|
||||
mp4decrypt finds a content key by the KID in the first `sinf` box of the track. When that box
|
||||
has no CENC `tenc` (for example, a PIFF `sinf` before the CENC one), unshackle also gives
|
||||
mp4decrypt the content key of that KID by track ID. When mp4decrypt copies a track through
|
||||
|
||||
@@ -40,7 +40,7 @@ folder-kind keys.
|
||||
`absolute`, `date`, `quality`, `resolution`, `source`, `tag`, `track_number`, `artist`,
|
||||
`album_artist`, `album`, `disc`, `track_total`, `disc_total`, `release_type`, `genre`,
|
||||
`explicit`, `isrc`, `upc`, `label`, `audio`, `audio_channels`, `audio_full`, `atmos`,
|
||||
`dual`, `multi`, `dubbed`, `video`, `hdr`, `hfr`, `edition`, `repack`, `lang_tag`,
|
||||
`dual`, `multi`, `dubbed`, `video`, `hdr`, `hfr`, `3d`, `edition`, `repack`, `lang_tag`,
|
||||
`title_type`.
|
||||
|
||||
!!! warning "`{part?}` is already inside `{season_episode}`"
|
||||
@@ -129,7 +129,7 @@ Rule semantics:
|
||||
- A value can be a scalar or a list. A list matches if **any** entry matches.
|
||||
- Comparison is case-insensitive string equality.
|
||||
- The keys of `when` are the filename template variables for the release itself:
|
||||
`title_type`, `quality`, `resolution`, `source`, `video`, `hdr`, `hfr`, `audio`,
|
||||
`title_type`, `quality`, `resolution`, `source`, `video`, `hdr`, `hfr`, `3d`, `audio`,
|
||||
`audio_channels`, `audio_full`, `atmos`, `dual`, `multi`, `dubbed`, `edition`, `repack`,
|
||||
and `lang_tag`. Only these are available. unshackle adds the title's own fields (`title`,
|
||||
`year`, `season`, `episode`, and so on) after it evaluates the rules, so a condition cannot
|
||||
|
||||
@@ -113,7 +113,7 @@ values.
|
||||
| `{year}` `{season}` `{episode}` `{episode_name}` | Season and episode are plain numbers (`1`, `5`) |
|
||||
| `{part}` | Part number of a split episode as a plain number (`1` for `Part.1`). Empty when the episode has no part |
|
||||
| `{season_episode}` `{absolute}` `{date}` | As in the filename template: `{season_episode}` keeps the part suffix (`S01E05.Part.1`) while `{episode}` drops it |
|
||||
| `{quality}` `{resolution}` `{hdr}` `{hfr}` `{vcodec}` `{acodec}` `{edition}` `{tag}` `{lang_tag}` | As in the filename template, for this file |
|
||||
| `{quality}` `{resolution}` `{hdr}` `{hfr}` `{3d}` `{vcodec}` `{acodec}` `{edition}` `{tag}` `{lang_tag}` | As in the filename template, for this file |
|
||||
| `{tmdb}` `{imdb}` `{tvdb}` | The tagging IDs in use, otherwise empty. See [Tagging IDs](#tagging-ids) |
|
||||
| `{error}` | Failure message. Empty on success |
|
||||
|
||||
@@ -132,7 +132,7 @@ Every variable from your `output_template` is available here as well, including
|
||||
music has none of them.
|
||||
- **The naming context renders it empty on purpose.** `{hdr}` is empty for an SDR
|
||||
file, because SDR is the absence of an HDR tag in a filename rather than a tag that
|
||||
reads `SDR`. `{edition}`, `{atmos}`, `{multi}`, `{dual}` and `{hfr}` behave the same
|
||||
reads `SDR`. `{edition}`, `{atmos}`, `{multi}`, `{dual}`, `{hfr}` and `{3d}` behave the same
|
||||
way. If your script needs the word `SDR`, derive it from an empty `{hdr}` yourself.
|
||||
- The post-script is a `failure` one. A failed download has no output file to read metadata
|
||||
from, so everything that comes from the output file is empty. See
|
||||
|
||||
Reference in New Issue
Block a user