# dovi_tool

Canonical URL: https://encode.wiki/tools/utilities/dovi_tool/
Content version: ca42e61ede0a24f789d7287a0001244ad22f4abf
Status: current
License: CC BY-SA 4.0
Checksum (SHA-256): 9a1d153355744b0b080577ff2dd179328d57d84f8d8c2985069217ef9361ff39

> **Repository:** [quietvoid/dovi_tool](https://github.com/quietvoid/dovi_tool). dovitool is a CLI tool combining multiple utilities for working with Dolby Vision. Latest release: [2.3.4](https://github.com/quietvoid/dovi_tool/releases/tag/2.3.4), Sep 10, 2026. Last commit: Sep 9, 2026. License: MIT. Stars: 1,023.

dovi_tool is a command-line tool by quietvoid for working with Dolby Vision. Its main job in an encoding workflow is moving the RPU — the per-frame Dolby Vision metadata — from a source to a new encode, converting the profile on the way when needed. It also inspects, edits, plots and generates RPUs. It works on HEVC (raw Annex B streams, or Matroska files with an HEVC track); it doesn't decode or encode video.

The same repository contains the `dolby_vision` Rust crate, also built as the C library `libdovi`, which other tools use for RPU parsing. See [HDR formats](/hdr/#dolby-vision) for what the profiles mean.

## Install

Download a binary from the [GitHub releases](https://github.com/quietvoid/dovi_tool/releases): builds are provided for x86-64 and ARM64 Linux (static musl), x64 and ARM64 Windows, and universal macOS. To build from source you need Rust 1.88 or newer and, on Linux, fontconfig (or build with `--no-default-features --features internal-font`):

```sh
git clone https://github.com/quietvoid/dovi_tool.git
cd dovi_tool
cargo build --release
```

## Keep Dolby Vision through a re-encode

1. Extract the RPU. dovi_tool reads Matroska directly:

   ```sh
   dovi_tool extract-rpu input.mkv -o RPU.bin
   ```

   For a profile 7 source (UHD Blu-ray), convert to 8.1 while extracting, since single-layer 8.1 is what you are going to encode:

   ```sh
   dovi_tool -m 2 extract-rpu input.mkv -o RPU.bin
   ```

   For MP4 or other containers, pipe the stream through FFmpeg:

   ```sh
   ffmpeg -i input.mp4 -c:v copy -f hevc - | dovi_tool extract-rpu - -o RPU.bin
   ```

2. Check what you have: `dovi_tool info -i RPU.bin --summary` prints the frame count, profile, scene count, L5 offsets and L6 values.

3. Encode the HDR10 base layer at the same frame count. x265 can write the RPU itself:

   ```sh
   x265 --input video.y4m --output-depth 10 --crf 18 --preset slow --colorprim bt2020 --transfer smpte2084 --colormatrix bt2020nc \
     --master-display "G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,1)" --max-cll "1000,400" \
     --vbv-maxrate 40000 --vbv-bufsize 50000 --dolby-vision-profile 8.1 --dolby-vision-rpu RPU.bin -o output.hevc
   ```

   x265 refuses Dolby Vision without VBV settings (it needs them to write HRD information); pick values that suit the level you target. Take the mastering-display and MaxCLL values from the source.

4. Or encode with anything that outputs HEVC and inject the RPU afterwards:

   ```sh
   dovi_tool inject-rpu -i output.hevc --rpu-in RPU.bin -o injected.hevc
   ```

5. Mux. `mkvmerge -o final.mkv injected.hevc` writes the Dolby Vision configuration record automatically. For MP4 with FFmpeg add `-strict unofficial`, or the configuration box is left out and players treat the file as plain HDR10.

The RPU must line up with the new video frame for frame. If you cut, trim or drop frames, edit the RPU the same way first (see [edit an RPU](#edit-an-rpu)). If you crop away letterbox bars, add the global `--crop` option when extracting, which sets the L5 active-area offsets to zero.

## Conversion modes

The global `-m`/`--mode` option rewrites the RPU during `extract-rpu`, `convert`, `demux` and `mux`. `inject-rpu` ignores global options.

| Mode | Result |
| --- | --- |
| none | RPU copied untouched |
| `0` | Parsed and rewritten without changes |
| `1` | Profile 7 FEL converted to MEL |
| `2` | Profile 8.1; luma/chroma mapping removed for profile 7 FEL |
| `3` | Profile 5 converted to 8.1 |
| `4` | Profile 8.4 |
| `5` | Profile 8.1, mapping preserved (the old mode 2) |

Mode 2 is the usual choice for profile 7. With a FEL source the enhancement layer carries real picture data, so dropping it and using a converted RPU gives a result that is close to, but not the same as, the full dual-layer image; with MEL nothing visible is lost. Mode 3 changes only the RPU: a profile 5 base layer is in Dolby's IPTPQc2 color space, not HDR10, so the video itself must also be converted (for example decoded through libplacebo) for the result to be valid 8.1.

## Other commands

| Command | What it does |
| --- | --- |
| `info -i RPU.bin --summary` / `--frame N` | Summary, or one frame's RPU as JSON (frames count from 0) |
| `export -i RPU.bin -d all=RPU.json` | Export all RPUs as JSON; `-d scenes=scenes.txt` exports scene-cut frames, `level5=L5.json` the active-area edits |
| `plot RPU.bin -o L1.png` | Plot L1 brightness; `-p l2` or `-p l8` plots trims |
| `editor -i RPU.bin -j edits.json -o out.bin` | Remove or duplicate frames, change active areas, scene cuts or L6 values |
| `generate -j config.json -o RPU.bin` | Generate a profile 8.1 or 8.4 RPU from a JSON config, a Dolby Vision XML, an HDR10+ JSON (`--hdr10plus-json`) or a madVR measurement file |
| `convert`, `demux`, `mux` | Convert the RPU in place, split a dual-layer stream into `BL.hevc` and `EL.hevc`, or interleave them again |
| `remove` | Strip the RPU and enhancement layer, leaving the HDR10 base layer in `BL.hevc` |

Other global options: `--drop-hdr10plus` removes HDR10+ SEI messages when writing HEVC, and `--start-code annex-b` writes variable-length start codes like x265 instead of always four bytes. `extract-rpu` accepts `-l N` to stop after N frames and `-t N` to pick a Matroska track. `convert`, `demux` and `remove` on Matroska input are experimental in 2.3.4.

## Edit an RPU

The editor takes a JSON file. Frame ranges are inclusive and count from 0; removals run before duplications. To drop the first 40 frames of metadata, for example after trimming 40 frames from the start of the video:

```json
{
  "remove": ["0-39"]
}
```

To repeat metadata for inserted frames, use `"duplicate": [{ "source": 100, "offset": 100, "length": 24 }]`. The full schema, including active-area presets and L6 replacement, is in [editor.md](https://github.com/quietvoid/dovi_tool/blob/2.3.4/docs/editor.md).
