HDR dovi_tool
Context: $ARGUMENTS
Quick start
- Extract RPU from HEVC: → Step 3 (
dovi.py extract-rpu) - Inject RPU back: → Step 4 (
dovi.py inject-rpu) - Convert profile 7 (BL+EL) → 8.1 (single-layer): → Step 5 (
dovi.py convert) - Edit RPU with JSON script: → Step 6 (
dovi.py editor) - End-to-end pipeline (MKV → edited RPU → MKV): → Step 7 (
dovi.py pipeline)
When to use
- User wants to strip, edit, or repackage Dolby Vision metadata.
- User wants to convert a profile-7 dual-layer source to single-layer 8.1 MKV/MP4.
- User wants a plot of per-frame brightness metadata.
- For the doc side (subcommand discovery, flag lookup), use
hdr-dynmeta-docs. - For HDR10+ (not Dolby Vision), use
hdr-hdr10plus-tool.
Step 1 — Install
cargo install --locked --git https://github.com/quietvoid/dovi_tool
# OR: grab a pre-built binary from the repo's Releases tab
Needs Rust (MSRV tracks recent — see hdr-dynmeta-docs fetch --page dovi-releases). Also needs ffmpeg on PATH for the pipeline subcommand; mkvmerge (from MKVToolNix) or MP4Box (from GPAC) for remuxing.
Verify:
uv run ${CLAUDE_SKILL_DIR}/scripts/dovi.py info --help
Step 2 — Parse an existing RPU
uv run ${CLAUDE_SKILL_DIR}/scripts/dovi.py info --input source.hevc --summary
Output: RPU header + per-frame L1/L2/L5/L6/L8/L9/L11 metadata.
Step 3 — Extract RPU from HEVC
uv run ${CLAUDE_SKILL_DIR}/scripts/dovi.py extract-rpu \
--input source.hevc --output rpu.bin
Input must be HEVC Annex-B, not muxed MP4/MKV. Use ffmpeg to unpack first, or use the pipeline subcommand for the full chain.
Step 4 — Inject RPU back
uv run ${CLAUDE_SKILL_DIR}/scripts/dovi.py inject-rpu \
--input source.hevc --rpu-in rpu.bin --output injected.hevc
Result is Annex-B HEVC with the RPU NAL units stitched back in. Remux to MKV/MP4 (Step 7).
Step 5 — Profile 7 → 8.1
Profile 7 is dual-layer (BL+EL); profile 8.1 is single-layer. Most playback devices prefer 8.1.
uv run ${CLAUDE_SKILL_DIR}/scripts/dovi.py convert \
--input source.hevc --output converted.hevc --mode 2
Mode 2 = "convert to 8.1 for broader compatibility" (typical ask). See upstream README for the full mode table.
Step 6 — JSON-driven RPU edits
Author edit.json per the dovi_tool docs, then:
uv run ${CLAUDE_SKILL_DIR}/scripts/dovi.py editor \
--input rpu.bin --json edit.json --output edited.bin
Common edits: trim frame range, offset L1 brightness, inject scene-change markers.
Step 7 — End-to-end pipeline
Chains:
ffmpeg -bsf:v hevc_mp4toannexbto extract Annex-B HEVC from MKV/MP4dovi_tool extract-rpu- (optional)
dovi_tool editorwith a JSON dovi_tool convert(if--convert-profile-7-to-81)dovi_tool inject-rpumkvmergeORMP4Boxto repackage
uv run ${CLAUDE_SKILL_DIR}/scripts/dovi.py pipeline \
--input movie.mkv --output out.mkv --edit-json edit.json
Target container inferred from output extension (.mkv → mkvmerge, .mp4 → MP4Box). --strip-dv removes DV instead of re-injecting. --convert-profile-7-to-81 adds the convert step. --info-only runs info + plot without writing. Use --dry-run to preview without executing.
Step 8 — Plot brightness
uv run ${CLAUDE_SKILL_DIR}/scripts/dovi.py plot \
--input rpu.bin --output brightness.png
Step 9 — Export / Demux / Mux / Remove
# Export RPU to JSON
uv run ${CLAUDE_SKILL_DIR}/scripts/dovi.py export --input rpu.bin --output rpu.json
# Demux BL+EL dual-layer stream (profile 7)
uv run ${CLAUDE_SKILL_DIR}/scripts/dovi.py demux \
--input dual.hevc --bl-out bl.hevc --el-out el.hevc
# Remux them
uv run ${CLAUDE_SKILL_DIR}/scripts/dovi.py mux \
--bl bl.hevc --el el.hevc --output dual.hevc
# Strip all DV RPU from HEVC
uv run ${CLAUDE_SKILL_DIR}/scripts/dovi.py remove \
--input hasdv.hevc --output plain.hevc
Gotchas
- Input to extract-rpu MUST be HEVC Annex-B, not muxed MP4/MKV.
pipelinehandles the bsf step; standalone extract-rpu/inject-rpu do not. - Profile 8.2 is NOT documented as supported — don't promise it. Supported: 4, 5, 7, 8.1, 8.4.
- After inject-rpu you have a raw .hevc bytestream. You MUST remux it (pipeline handles this; manual chain needs
mkvmerge -o out.mkv injected.hevcorMP4Box -add injected.hevc:dvhe=hvcC out.mp4). - ffmpeg's MP4 muxer for HEVC+RPU is flaky. Prefer mkvmerge or MP4Box. If you must use ffmpeg, add
-tag:v dvh1(profile 5) or-tag:v dvhe(profile 8) manually. - Profile 7→8.1 convert MODE matters. Mode 2 is the common "give me 8.1 for compatibility" answer. Other modes preserve or diagnose. Consult README.
- Apple TV / iOS prefer profile 5 (IPT-C2 single-layer). Profile 8.1 (bt.2020 single-layer) may not be recognized on older Apple devices — you'd need a profile 5 re-encode, which dovi_tool alone cannot do.
- RPU NAL ordering is strict. inject-rpu places RPU NALs immediately before slice-layer NALs; hand-spliced streams silently drop DV. Always use dovi_tool.
- Editor JSON schema changes between versions. Check
dovi_tool --versionagainst the schema you're editing. Keep edit JSONs in VCS alongside tool version. - The script is stdlib-only. Non-interactive, prints every real
dovi_tool/ffmpeg/mkvmerge/MP4Boxcommand to stderr before running.--dry-runsupported on every subcommand.
Examples
Example 1 — Convert a profile-7 Blu-ray remux to 8.1 single-layer MKV
uv run ${CLAUDE_SKILL_DIR}/scripts/dovi.py pipeline \
--input BD.mkv --output out.mkv --convert-profile-7-to-81
Wrapper chains: ffmpeg bsf → extract RPU → convert → inject → mkvmerge.
Example 2 — Strip Dolby Vision from a file entirely
uv run ${CLAUDE_SKILL_DIR}/scripts/dovi.py pipeline \
--input dv.mkv --output plain.mkv --strip-dv
Example 3 — Inspect DV metadata
uv run ${CLAUDE_SKILL_DIR}/scripts/dovi.py pipeline --input dv.mkv --info-only
Example 4 — Plot L1 brightness
uv run ${CLAUDE_SKILL_DIR}/scripts/dovi.py plot --input rpu.bin --output l1.png
Example 5 — Apply a JSON edit to an RPU
uv run ${CLAUDE_SKILL_DIR}/scripts/dovi.py editor \
--input rpu.bin --json trim.json --output trimmed.bin
Troubleshooting
dovi_tool: command not found
Solution: cargo install --locked --git https://github.com/quietvoid/dovi_tool or download pre-built from Releases.
extract-rpu: Failed to parse HEVC stream
Cause: Input was MP4/MKV-muxed HEVC, not Annex-B.
Solution: Pipe through ffmpeg first: ffmpeg -i in.mkv -c:v copy -bsf:v hevc_mp4toannexb -f hevc - | dovi_tool extract-rpu -, or use the pipeline subcommand.
MKV plays SDR, not Dolby Vision
Cause: RPU wasn't injected, or the remux dropped the dvh* codec tag.
Solution: Use mkvmerge: mkvmerge -o out.mkv injected.hevc. For MP4: MP4Box -add injected.hevc:dvhe=hvcC out.mp4.
Profile 7 convert mode mystery
Solution: dovi_tool convert --help lists modes. Mode 2 = common "give me 8.1" answer. Or: hdr-dynmeta-docs section --page dovi-readme --id convert.
Reference docs
- Verified dovi_tool subcommand catalog + pipeline chain → see
hdr-dynmeta-docsskill'sreferences/subcommands.md. - RPU editor JSON schema cheat sheet →
references/edit-schema.mdin this skill.