{
  "schemaVersion": 1,
  "contentVersion": "ca42e61ede0a24f789d7287a0001244ad22f4abf",
  "id": "docs/guides/preserve-color-and-hdr",
  "collection": "docs",
  "title": "Preserve color and HDR",
  "description": "How to keep, fix or convert color tags and HDR metadata with FFmpeg, VapourSynth, x264, x265, SVT-AV1 and aomenc.",
  "canonicalUrl": "https://encode.wiki/guides/preserve-color-and-hdr/",
  "apiUrl": "https://encode.wiki/api/v1/documents/docs/guides/preserve-color-and-hdr.json",
  "markdownUrl": "https://encode.wiki/api/v1/markdown/docs/guides/preserve-color-and-hdr.md",
  "status": "current",
  "tags": [
    "color",
    "hdr",
    "ffmpeg"
  ],
  "license": "CC BY-SA 4.0",
  "dates": {
    "lastVerified": "2026-10-08T00:00:00.000Z"
  },
  "authors": [],
  "sources": [
    {
      "title": "FFmpeg n9.0.2 encoder color handling (fftools/ffmpeg_enc.c)",
      "url": "https://github.com/FFmpeg/FFmpeg/blob/n9.0.2/fftools/ffmpeg_enc.c",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "FFmpeg n9.0.2 Changelog (HDR10 metadata passthrough for libx264, libx265, libsvtav1)",
      "url": "https://github.com/FFmpeg/FFmpeg/blob/n9.0.2/Changelog",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "FFmpeg filters documentation (setparams, scale, zscale, sidedata)",
      "url": "https://ffmpeg.org/ffmpeg-filters.html",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "FFmpeg bitstream filters (h264_metadata, hevc_metadata, av1_metadata)",
      "url": "https://ffmpeg.org/ffmpeg-bitstream-filters.html",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "x265 command-line options",
      "url": "https://github.com/Multicorewareinc/x265/blob/4.3/doc/reST/cli.rst",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "SVT-AV1 v4.2.0 parameters (Appendix A.2, AV1 metadata)",
      "url": "https://gitlab.com/AOMediaCodec/SVT-AV1/-/blob/v4.2.0/Docs/Parameters.md",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "VapourSynth R81 resize documentation",
      "url": "https://github.com/vapoursynth/vapoursynth/blob/R81/doc/functions/video/resize.rst",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "mkvpropedit documentation",
      "url": "https://mkvtoolnix.download/doc/mkvpropedit.html",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    }
  ],
  "headings": [
    {
      "depth": 2,
      "text": "Find out what the source is",
      "anchor": "find-out-what-the-source-is"
    },
    {
      "depth": 2,
      "text": "Preserve: let FFmpeg carry the tags",
      "anchor": "preserve-let-ffmpeg-carry-the-tags"
    },
    {
      "depth": 2,
      "text": "Retag: fix missing or wrong tags",
      "anchor": "retag-fix-missing-or-wrong-tags"
    },
    {
      "depth": 2,
      "text": "Convert: change the samples, then tag",
      "anchor": "convert-change-the-samples-then-tag"
    },
    {
      "depth": 3,
      "text": "SD BT.601 to HD BT.709",
      "anchor": "sd-bt601-to-hd-bt709"
    },
    {
      "depth": 3,
      "text": "Full range to limited range",
      "anchor": "full-range-to-limited-range"
    },
    {
      "depth": 3,
      "text": "HDR to SDR",
      "anchor": "hdr-to-sdr"
    },
    {
      "depth": 2,
      "text": "Standalone encoders: tag everything yourself",
      "anchor": "standalone-encoders-tag-everything-yourself"
    },
    {
      "depth": 2,
      "text": "HDR10 static metadata",
      "anchor": "hdr10-static-metadata"
    },
    {
      "depth": 2,
      "text": "HDR10+ and Dolby Vision",
      "anchor": "hdr10-and-dolby-vision"
    },
    {
      "depth": 2,
      "text": "Check the output",
      "anchor": "check-the-output"
    }
  ],
  "sections": [
    {
      "id": "_preamble",
      "title": "Page introduction",
      "depth": 0,
      "canonicalUrl": "https://encode.wiki/guides/preserve-color-and-hdr/",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/_preamble.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/_preamble.md",
      "checksum": "e4c40146a7952bc77cdfa1c1b97dc139d25d31799824b038d2c19f3b636682ad",
      "bytes": 279
    },
    {
      "id": "find-out-what-the-source-is",
      "title": "Find out what the source is",
      "depth": 2,
      "anchor": "find-out-what-the-source-is",
      "canonicalUrl": "https://encode.wiki/guides/preserve-color-and-hdr/#find-out-what-the-source-is",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/find-out-what-the-source-is.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/find-out-what-the-source-is.md",
      "checksum": "6781e6046133faac6226a3d1491e4ccc7836228fb2d18ed6ec5c0bbd42c30596",
      "bytes": 631
    },
    {
      "id": "preserve-let-ffmpeg-carry-the-tags",
      "title": "Preserve: let FFmpeg carry the tags",
      "depth": 2,
      "anchor": "preserve-let-ffmpeg-carry-the-tags",
      "canonicalUrl": "https://encode.wiki/guides/preserve-color-and-hdr/#preserve-let-ffmpeg-carry-the-tags",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/preserve-let-ffmpeg-carry-the-tags.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/preserve-let-ffmpeg-carry-the-tags.md",
      "checksum": "0540196a7377636ea763a4cfcc860b8aba881e6ccd5c8a2cd1f5d8be814c48e7",
      "bytes": 857
    },
    {
      "id": "retag-fix-missing-or-wrong-tags",
      "title": "Retag: fix missing or wrong tags",
      "depth": 2,
      "anchor": "retag-fix-missing-or-wrong-tags",
      "canonicalUrl": "https://encode.wiki/guides/preserve-color-and-hdr/#retag-fix-missing-or-wrong-tags",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/retag-fix-missing-or-wrong-tags.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/retag-fix-missing-or-wrong-tags.md",
      "checksum": "042e077b5df02602aeda1fbe3ce651bc3e2f7f796ff00fc10f9e960018c54bb9",
      "bytes": 2365
    },
    {
      "id": "convert-change-the-samples-then-tag",
      "title": "Convert: change the samples, then tag",
      "depth": 2,
      "anchor": "convert-change-the-samples-then-tag",
      "canonicalUrl": "https://encode.wiki/guides/preserve-color-and-hdr/#convert-change-the-samples-then-tag",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/convert-change-the-samples-then-tag.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/convert-change-the-samples-then-tag.md",
      "checksum": "7fe33e01ac986fa2a350f1ade19dda557f1e043ac806d9b70856fae4b02576b8",
      "bytes": 1944
    },
    {
      "id": "sd-bt601-to-hd-bt709",
      "title": "SD BT.601 to HD BT.709",
      "depth": 3,
      "anchor": "sd-bt601-to-hd-bt709",
      "canonicalUrl": "https://encode.wiki/guides/preserve-color-and-hdr/#sd-bt601-to-hd-bt709",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/sd-bt601-to-hd-bt709.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/sd-bt601-to-hd-bt709.md",
      "checksum": "960213d458bef69f022df07ec13b161b8326b8878f55d6d5e2fddbde400e6291",
      "bytes": 1316
    },
    {
      "id": "full-range-to-limited-range",
      "title": "Full range to limited range",
      "depth": 3,
      "anchor": "full-range-to-limited-range",
      "canonicalUrl": "https://encode.wiki/guides/preserve-color-and-hdr/#full-range-to-limited-range",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/full-range-to-limited-range.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/full-range-to-limited-range.md",
      "checksum": "af09de2eff0e422a95120db47599099d9ca851a7fdd9a8595d81a1f93fd1369b",
      "bytes": 474
    },
    {
      "id": "hdr-to-sdr",
      "title": "HDR to SDR",
      "depth": 3,
      "anchor": "hdr-to-sdr",
      "canonicalUrl": "https://encode.wiki/guides/preserve-color-and-hdr/#hdr-to-sdr",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/hdr-to-sdr.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/hdr-to-sdr.md",
      "checksum": "f6e9709fe9a5c1c8ce244d068bae43a04b13048ada10e65e1eb0841058297fc4",
      "bytes": 110
    },
    {
      "id": "standalone-encoders-tag-everything-yourself",
      "title": "Standalone encoders: tag everything yourself",
      "depth": 2,
      "anchor": "standalone-encoders-tag-everything-yourself",
      "canonicalUrl": "https://encode.wiki/guides/preserve-color-and-hdr/#standalone-encoders-tag-everything-yourself",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/standalone-encoders-tag-everything-yourself.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/standalone-encoders-tag-everything-yourself.md",
      "checksum": "e8be2984586e7b0f07e31529f73f52f9a3d828d1f311d2ec5f9da47dfeba1337",
      "bytes": 2455
    },
    {
      "id": "hdr10-static-metadata",
      "title": "HDR10 static metadata",
      "depth": 2,
      "anchor": "hdr10-static-metadata",
      "canonicalUrl": "https://encode.wiki/guides/preserve-color-and-hdr/#hdr10-static-metadata",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/hdr10-static-metadata.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/hdr10-static-metadata.md",
      "checksum": "6c51b5e9cf0df82114dce5b0cdea7b80f57eddcbeb10e16790fb898a78a0fbe3",
      "bytes": 2199
    },
    {
      "id": "hdr10-and-dolby-vision",
      "title": "HDR10+ and Dolby Vision",
      "depth": 2,
      "anchor": "hdr10-and-dolby-vision",
      "canonicalUrl": "https://encode.wiki/guides/preserve-color-and-hdr/#hdr10-and-dolby-vision",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/hdr10-and-dolby-vision.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/hdr10-and-dolby-vision.md",
      "checksum": "b34c24213dafc0cc27bb9e96e3ec574cbc4b337f00509c3b0272beadade92fff",
      "bytes": 2568
    },
    {
      "id": "check-the-output",
      "title": "Check the output",
      "depth": 2,
      "anchor": "check-the-output",
      "canonicalUrl": "https://encode.wiki/guides/preserve-color-and-hdr/#check-the-output",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/check-the-output.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/guides/preserve-color-and-hdr/check-the-output.md",
      "checksum": "3a9cb8f3080a7653ff461f0cf6d4db1316ca9851fb9747fa32ec816b70edee2c",
      "bytes": 413
    }
  ],
  "outboundReferences": [
    "#hdr10-and-dolby-vision",
    "#hdr10-static-metadata",
    "/hdr/",
    "/hdr/#tone-map-hdr-to-sdr",
    "/reference/colorimetry/intro/",
    "/reference/colorimetry/range/",
    "/tools/utilities/dovi_tool/",
    "/tools/utilities/hdr10plus_tool/"
  ],
  "checksum": "f85643670578eef8a3959c1d78f2f67019f90d2729225308158793744aaba11f",
  "contentFormat": "markdown",
  "markdown": "Color mistakes rarely make an encode fail. They make it look slightly wrong on some players, and\nnobody notices until later. The rule is simple: find out what the source really is, keep it that\nway through the pipeline, and tag the output to match the pixels you actually wrote.\n\n## Find out what the source is\n\n```sh\nffprobe -v error -select_streams v:0 -show_entries stream=pix_fmt,color_range,color_space,color_transfer,color_primaries,chroma_location -of default=nw=1 input.mkv\n```\n\nIf everything is filled in and plausible, preserve it. If fields are `unknown`, work out the truth\nfrom where the video came from: DVDs are BT.601 (`smpte170m` for NTSC, `bt470bg` for PAL), HD\nBlu-ray and HD broadcast are BT.709, UHD Blu-ray HDR is BT.2020 + PQ. A 1080p file that was\nupscaled from DVD can still carry BT.601 colors. See the [colorimetry\nreference](/reference/colorimetry/intro/) for what each field means.\n\n## Preserve: let FFmpeg carry the tags\n\nCurrent FFmpeg passes the decoded frames' primaries, transfer, matrix, range and chroma location\nto the encoder, and (since 7.0) passes HDR10 mastering-display and content-light metadata through\nto libx264, libx265 and libsvtav1; libaom-av1 also passes it. A plain transcode keeps them:\n\n```sh\nffmpeg -i input.mkv -c:v libsvtav1 -crf 30 -preset 6 -c:a copy output.mkv\n```\n\nWhat breaks preservation:\n\n- **Dropping bit depth.** `-pix_fmt yuv420p` on a 10-bit HDR source keeps the HDR tags but\n  quantizes PQ to 8 bits, which bands badly. Keep HDR at 10-bit.\n- **Filters that change color without retagging**, or third-party tools in the middle of the\n  pipeline (see standalone encoders below).\n- **Dynamic metadata.** HDR10+ and Dolby Vision need extra steps; see\n  [HDR10+ and Dolby Vision](#hdr10-and-dolby-vision).\n\n## Retag: fix missing or wrong tags\n\nUse `setparams` to change the tags on the frames without touching the samples. For an untagged\nNTSC DVD encode:\n\n```sh\nffmpeg -i input.mkv -vf setparams=color_primaries=smpte170m:color_trc=smpte170m:colorspace=smpte170m:range=tv -c:v libx264 -crf 18 output.mkv\n```\n\n> **Caution — Don't use the output options to tag when encoding.**\n>\n> In current FFmpeg (7.1 and later, including 9.0) the encoder's color properties are taken from the\n> filtered frames. When you re-encode, the output options behave differently from what most guides\n> assume:\n>\n> - `-color_primaries` and `-color_trc` are overwritten by the frame values, so they do nothing.\n> - `-colorspace` and `-color_range` are passed to filter negotiation, so FFmpeg auto-inserts a\n>   scaler and **converts** the samples (an untagged frame is treated as BT.601 when converting to\n>   `-colorspace bt709`). Depending on the pixel format they can also do nothing at all.\n>\n> Use `setparams` to tag and an explicit filter to convert. Encoder-private options such as\n> `-x265-params colorprim=…` do set the bitstream tags, but FFmpeg's muxer then writes no Matroska\n> color elements.\nTo retag without re-encoding, rewrite the bitstream's VUI or sequence header with a bitstream\nfilter, and pass the same values as output options so the container agrees:\n\n```sh\nffmpeg -i input.mkv -c copy -bsf:v h264_metadata=colour_primaries=1:transfer_characteristics=1:matrix_coefficients=1 -color_primaries bt709 -color_trc bt709 -colorspace bt709 output.mkv\n```\n\n`hevc_metadata` takes the same options and `av1_metadata` uses `color_primaries`,\n`transfer_characteristics`, `matrix_coefficients` and `color_range`; values are the H.273 numbers.\nThe bitstream filter doesn't touch the container: from a Matroska or MP4 input FFmpeg copies the old\ncolor fields (the Matroska `Colour` elements, the MP4 `colr` box), and ffprobe and other tools that\nread them keep reporting the old values. With `-c copy` the output options only set those fields.\n\nTo fix a Matroska file that already has stale values, edit it in place with `mkvpropedit`;\nremuxing with `mkvmerge` doesn't help, because it keeps the container values of a Matroska input:\n\n```sh\nmkvpropedit output.mkv --edit track:v1 --set color-transfer-characteristics=1 --set color-primaries=1 --set color-matrix-coefficients=1\n```\n\n## Convert: change the samples, then tag\n\n### SD BT.601 to HD BT.709\n\nUpscaling a DVD to 1080p and tagging it BT.709 without converting shifts the colors (greens and\nskin tones most visibly). Convert while you scale. `zscale` takes the input interpretation\nexplicitly, which is what you want for an untagged source:\n\n```sh\nffmpeg -i dvd.mkv -vf zscale=w=1440:h=1080:f=spline36:min=170m:pin=170m:tin=601:m=709:p=709:t=709 -c:v libx264 -crf 18 output.mkv\n```\n\nFor PAL use `min=470bg:pin=bt470bg`. The matrix is the part that visibly matters; the transfer\nfunction is the same and the primaries differ only slightly. The built-in `scale` filter converts\nonly the matrix, so keep the source's primaries and transfer tags when you use it:\n\n```sh\nffmpeg -i dvd.mkv -vf scale=1440:1080:in_color_matrix=bt601:out_color_matrix=bt709,setparams=color_primaries=smpte170m:color_trc=smpte170m -c:v libx264 -crf 18 output.mkv\n```\n\nIn VapourSynth, declare the source properties if the source filter didn't set them, then let\n`resize` convert:\n\n```py\nclip = core.std.SetFrameProps(clip, _Matrix=6, _Primaries=6, _Transfer=6, _Range=0)\nclip = core.resize.Spline36(clip, 1440, 1080, matrix_s=\"709\", primaries_s=\"709\", transfer_s=\"709\")\n```\n\n`_Range` uses 0 for limited and 1 for full, like H.273. The older `_ColorRange` property, now\ndeprecated, used the opposite numbering.\n\n### Full range to limited range\n\n```sh\nffmpeg -i full.mkv -vf scale=out_range=limited,format=yuv420p -c:v libx264 -crf 18 output.mkv\n```\n\nThe `format=yuv420p` matters: FFmpeg decodes full-range 8-bit H.264/HEVC as the legacy\n`yuvj420p` format, which cannot hold limited range. Without it `scale` silently does nothing, and\n`zscale` converts the samples but leaves the output tagged full range. See [color range](/reference/colorimetry/range/) for diagnosing range problems.\n\n### HDR to SDR\n\nThat is tone mapping, not a tag change. See [tone mapping to SDR](/hdr/#tone-map-hdr-to-sdr).\n\n## Standalone encoders: tag everything yourself\n\nY4M carries no primaries, transfer or matrix. When you pipe from FFmpeg or VapourSynth into\n`x264`, `x265`, `SvtAv1EncApp` or `aomenc`, the encoder knows nothing about the source's color\nunless you pass it. FFmpeg also needs `-strict -1` to write 10-bit or 12-bit Y4M.\n\n| Property        | x264 / x265                                   | SvtAv1EncApp                        | aomenc                              |\n| --------------- | --------------------------------------------- | ----------------------------------- | ----------------------------------- |\n| Primaries       | `--colorprim bt709`                           | `--color-primaries bt709`           | `--color-primaries=bt709`           |\n| Transfer        | `--transfer bt709`                            | `--transfer-characteristics bt709`  | `--transfer-characteristics=bt709`  |\n| Matrix          | `--colormatrix bt709`                         | `--matrix-coefficients bt709`       | `--matrix-coefficients=bt709`       |\n| Range           | `--range tv` (x264), `--range limited` (x265) | `--color-range studio`              | read from Y4M only                  |\n| Chroma location | `--chromaloc 0`                               | `--chroma-sample-position left`     | `--chroma-sample-position=vertical` |\n| HDR10 values    | `bt2020`, `smpte2084`, `bt2020nc`             | `bt2020`, `smpte2084`, `bt2020-ncl` | `bt2020`, `smpte2084`, `bt2020ncl`  |\n\nRange is the trap. FFmpeg writes `XCOLORRANGE=FULL` into the Y4M header for full-range video;\nx264 and aomenc read it, but x265 4.3 and SvtAv1EncApp 4.2 ignore it and tag the output as limited.\nPass the range explicitly to those two.\n\nA 10-bit HDR10 pipe into x265:\n\n```sh\nffmpeg -i input.mkv -strict -1 -f yuv4mpegpipe - | x265 --y4m --input - --output-depth 10 --crf 18 --preset slow \\\n  --colorprim bt2020 --transfer smpte2084 --colormatrix bt2020nc --range limited --chromaloc 2 \\\n  --master-display \"G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,1)\" \\\n  --max-cll \"1000,400\" -o output.hevc\n```\n\n`--output-depth 10` is needed because multi-bit-depth x265 builds encode at 8 bits unless told\notherwise, even when the input is 10-bit. Copy the mastering-display and MaxCLL values from the\nsource — see [HDR10 metadata](#hdr10-static-metadata). With `aomenc`, use `--passes=1` when reading\nfrom a pipe; its default two-pass mode tries to read the input twice.\n\n## HDR10 static metadata\n\nRead the source values from the first frame:\n\n```sh\nffprobe -v error -select_streams v:0 -read_intervals \"%+#1\" -show_frames input.mkv\n```\n\nffprobe prints chromaticities and luminances as fractions (`red_x=34000/50000`,\n`max_luminance=10000000/10000`, `max_content=1000`). Each encoder wants them in a different form:\n\n| Encoder                   | Mastering display (P3-D65, 1000 / 0.0001 nits)                                                                             | Content light (MaxCLL, MaxFALL) |\n| ------------------------- | -------------------------------------------------------------------------------------------------------------------------- | ------------------------------- |\n| x265, `-x265-params`      | `--master-display \"G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,1)\"` — x,y × 50000; luminance × 10000 | `--max-cll \"1000,400\"`          |\n| x264                      | `--mastering-display` with the same integer format as x265                                                                 | `--cll \"1000,400\"`              |\n| SVT-AV1, `-svtav1-params` | `--mastering-display \"G(0.265,0.690)B(0.150,0.060)R(0.680,0.320)WP(0.3127,0.3290)L(1000,0.0001)\"` — plain x,y and nits     | `--content-light 1000,400`      |\n| aomenc                    | no option; use FFmpeg's libaom-av1, which passes the source's metadata                                                     | —                               |\n\nIn `-x265-params` and `-svtav1-params`, drop the leading dashes and separate options with colons\n(`master-display=G(…)…:max-cll=1000,400`). The order is G, B, R, then white point. For a BT.2020 mastering display the x265 primaries are\n`G(8500,39850)B(6550,2300)R(35400,14600)`. Use the numbers from your source, not from an example:\nthe mastering display's peak is a property of the grade, and MaxCLL/MaxFALL are measured from the\ncontent. When a source has none, leave them out rather than inventing them.\n\nIn FFmpeg you usually don't need these options at all, because the metadata is passed through. Set\nthem via `-x265-params` or `-svtav1-params` only when the source lacks them or you are fixing them.\n\n## HDR10+ and Dolby Vision\n\nDynamic metadata is per frame, so it only survives if the encoder writes it for each frame and the\nframes still line up with the source.\n\n|                      | Re-encode with FFmpeg                                                                                                                   | Standalone workflow                                                                                                                                        |\n| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| HDR10+ to HEVC       | Dropped by libx265. Extract with [hdr10plus_tool](/tools/utilities/hdr10plus_tool/), then pass `-x265-params dhdr10-info=metadata.json` | `x265 --dhdr10-info metadata.json`, or inject into the encoded stream with `hdr10plus_tool inject`                                                         |\n| HDR10+ to AV1        | Passed through by libaom-av1 (FFmpeg 8.0 and later); dropped by libsvtav1                                                               | —                                                                                                                                                          |\n| Dolby Vision to HEVC | `-dolbyvision 1` with libx265 writes profile 8.x; x265 also needs VBV (`vbv-maxrate`, `vbv-bufsize`)                                    | Extract the RPU with [dovi_tool](/tools/utilities/dovi_tool/), then `x265 --dolby-vision-profile 8.1 --dolby-vision-rpu RPU.bin` or `dovi_tool inject-rpu` |\n| Dolby Vision to AV1  | `-dolbyvision 1` with libsvtav1 or libaom-av1 writes profile 10                                                                         | — (dovi_tool handles HEVC only)                                                                                                                            |\n\nProfile 7 (dual-layer) sources cannot be passed through by FFmpeg; convert the RPU to 8.1 with\ndovi_tool first. Any trim, crop, frame-rate change or frame drop must be applied to the metadata as\nwell. See [HDR formats](/hdr/) for what the profiles mean.\n\nWhen muxing Dolby Vision into MP4 with FFmpeg, add `-strict unofficial`; without it the Dolby\nVision configuration box is not written and players treat the file as plain HDR10. `mkvmerge`\nwrites it to Matroska by default.\n\n## Check the output\n\nRun the same two ffprobe commands on the finished file and compare them with the source. Then watch\nit in a player that honors the tags (mpv does) next to the source, paying attention to skin tones,\nsaturated reds and greens, and shadow detail. Tags that match the source plus pixels that look the\nsame are the goal: tags can match the source even when the samples were converted on the way.\n"
}
