Skip to content

Dolby Vision: Parse CMv4.0 extension metadata blocks L15, L16, L18 (stacked on #2392) - #2655

Open
MeeeetRain wants to merge 1 commit into
MediaArea:masterfrom
MeeeetRain:dv2-l15-18-cmv4
Open

Dolby Vision: Parse CMv4.0 extension metadata blocks L15, L16, L18 (stacked on #2392)#2655
MeeeetRain wants to merge 1 commit into
MediaArea:masterfrom
MeeeetRain:dv2-l15-18-cmv4

Conversation

@MeeeetRain

Copy link
Copy Markdown

Summary

Implements proper bitstream parsing for the three DV2 (CMv4.0) extension metadata blocks that PR #2392 currently leaves as Skip_BS stubs (L15, L16) or does not handle at all (L18).

Stacked on top of #2392 (@cjee21's "Dolby Vision: Parse RPU in HEVC and AV1"). Commit 1 (f64e3d4) is an unmodified import of cjee21's DV branch so the history is reviewable; commit 2 (1c8ca23) is the only actual change — please review just that one. It should be rebased onto master once #2392 lands.

Per @JeromeMartinez's request in #2392 to split FFmpeg-derived parsing from other-source additions: the L15/L16/L18 layouts here come from the Dolby Vision Metadata Spec v1.5.1, not FFmpeg, so they belong in the "separate PR" bucket Jérôme asked for.

What changed

In File__Analyze_Streams.cpp, Get_DolbyVision_ReferenceProcessingUnit(), the CMv4.0 switch (ext_block_level):

  • L15 (11 B) — stub → parsed: confidence, precision_rendering_strength, d_local_contrast, d_brightness, d_saturation_plus_one, d_contrast_plus_one, {confidence,d_brightness,d_saturation,d_contrast}_no_pr, revision, reserved.
  • L16 (variable) — stub → parsed: revision, count, then count × Level16Params[contrast_target, precision_rendering_strength, d_local_contrast, max_d_brightness, max_d_saturation_plus_one].
  • L18 (7 B) — was missing entirely → added case 18: surround_luminance_PQ, min_preserved_luminance_PQ, adaptation_luminance_PQ, max_preserved_luminance_PQ, revision, reserved (4×12-bit + 4b + 4b).
  • L17 intentionally left as Skip_BS — Spec v1.5.1 removed the L17 grammar (superseded by L18); it should be skipped for forward compatibility, not parsed.
  • Fixes a missing break in case 17 (it was falling through to case 254).

Validation — three independent sources agree

The field layouts are cross-validated against:

  1. Dolby Vision Metadata Spec v1.5.1
  2. quietvoid/dovi_tool — PR quietvoid/dovi_tool#412 (independent Rust implementation)
  3. Official Dolby Vision TV SDK v6.0 test vectorsMFV-L15, MFV-L16, MFV-L18, CST-DV2 (Profile 5 HEVC VES)

This C++ implementation and the Rust dovi_tool produce bit-identical values on the official samples, e.g. CST-DV2 frame 0:

Block.field MediaInfo (this PR) dovi_tool (#412)
L15.confidence 255 255
L15.precision_rendering_strength 253 253
L15.d_local_contrast 99 99
L16.count 1 1
L16.contrast_target 64 64
L16.precision_rendering_strength 191 191
L18.adaptation_luminance_PQ 1741 1741
L18.max_preserved_luminance_PQ 4095 4095

Built and verified on macOS arm64 with MEDIAINFO_HEVC=ON MEDIAINFO_AV1=ON; the CLI surfaces the fields in --Details=1 (Trace) output.

Out of scope (future work)

  • Wiring the parsed L15/L16/L18 values into normal Fill() output (currently Trace-only, same as the rest of Dolby Vision: Parse RPU in HEVC and AV1 #2392).
  • L11 byte 3 FRC (Authentic Motion) sub-fields — handled separately in dovi_tool#412.

cc @cjee21 @JeromeMartinez

@cjee21

cjee21 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor
  • Fixes a missing break in case 17 (it was falling through to case 254).

There is no missing break right? A new case 18 is added here and exactly one new break is added for case 18.


So no one has info on the remaining bits of L11 yet...


By the way, #2392 is now affected by #2541 since RPU in AV1 is in the T.35 part.

Adds Dolby Vision RPU (Reference Processing Unit, NAL type 62) parsing
for HEVC streams, including the DV2 / CMv4.0 extension metadata blocks
L15, L16 and L18 that are not yet handled anywhere.

## Provenance

A focused slice of cjee21's PR MediaArea#2392 ('Dolby Vision: Parse RPU in HEVC
and AV1'), restricted to the HEVC path, plus L15/L16/L18 field parsing
that MediaArea#2392 leaves as Skip_BS stubs (L15, L16) or misses (L18).

The AV1/EMDF portion of MediaArea#2392 is intentionally omitted, per
@JeromeMartinez's request in MediaArea#2392 to defer AV1 until a File_T35.cpp
parser exists. Once MediaArea#2392 lands, this PR should be rebased onto it and
reduced to just the L15/L16/L18 delta.

## Files (5, source only — no CI/CMake/project changes)

- File__Analyze.h / File__Analyze_MinimizeSize.h: DV_RPU struct + parser decl
- File__Analyze_Streams.cpp: Get_DolbyVision_ReferenceProcessingUnit() —
  the RPU parser, with the CMv4.0 ext_metadata_block switch handling:
    - L15 (11 B): confidence, precision_rendering_strength, d_local_contrast,
      d_brightness, d_saturation_plus_one, d_contrast_plus_one,
      {confidence,d_brightness,d_saturation,d_contrast}_no_pr,
      revision, reserved
    - L16 (variable): revision, count, count x Level16Params
    - L18 (7 B): surround/min/adaptation/max_preserved_luminance_PQ,
      revision, reserved
  (L17 stays Skip_BS: Spec v1.5.1 removed its grammar, superseded by L18.
  Each new case has its own break; the existing case 17 already had one.)
- File_Hevc.cpp / File_Hevc.h: HEVC NAL type 62 dispatch + member

Also fixes signed/unsigned comparison warnings (C4018) in the imported
DV code so it passes the current -warnaserror CI standard.

## Validation — three independent sources agree

Field layouts cross-validated against Dolby Vision Metadata Spec v1.5.1,
quietvoid/dovi_tool (PR quietvoid/dovi_tool#412), and the official
Dolby Vision TV SDK v6.0 test vectors (MFV-L15/L16/L18, CST-DV2).
This C++ impl and the Rust dovi_tool produce bit-identical values, e.g.
CST-DV2 frame 0: L15 confidence=255, L16 contrast_target=64,
L18 adaptation_luminance_PQ=1741.

cc @cjee21 @JeromeMartinez
@MeeeetRain MeeeetRain reopened this Aug 6, 2026
@MeeeetRain

MeeeetRain commented Aug 6, 2026

Copy link
Copy Markdown
Author

Thanks @cjee21 — you're right about the break, I was mistaken. I misread the diff: case 17 already had its break, and the new break I added is just for the new case 18. Corrected the commit message accordingly (removed that claim).

So no one has info on the remaining bits of L11 yet...

There is authoritative info on L11 byte 3 from the Dolby Vision Metadata Spec v1.5.1 (Level 11 definition). Byte 3 is not reserved — it carries the DV2 Max Authentic Motion fields frc_strength and frc_type (only meaningful when DV2_Motion_Control is set in byte 1; otherwise it reads as 0). I won't paste the bit layout here, but it is documented in the spec and easy to find.

This is corroborated by the official DV2 TV SDK v6.0 test vectors: the CST-DV2 sample (Profile 5) carries a non-zero byte 3 there, while the MFV-L11 vectors carry 0 — consistent with motion metadata being present in one and absent in the other.

I implemented this in dovi_tool (PR quietvoid/dovi_tool#412) — relaxed the reserved_byte3 == 0 validation. Happy to bring the same into MediaInfo (separate from this PR, or here if preferred).


For this PR: I've restructured it to a single commit on master containing only the 5 HEVC source files (no AV1/EMDF, no CI/CMake/project changes), plus the L15/L16/L18 parsing and the C4018 signed/unsigned casts needed for the current -warnaserror standard. Once #2392 lands this can be rebased down to just the L15/L16/L18 delta.

@cjee21

cjee21 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

There is authoritative info on L11 byte 3

Any info on byte 2?

@MeeeetRain

Copy link
Copy Markdown
Author

@ cjee21 — per the Dolby Vision Metadata Spec v1.5.1 (Level 11), byte 2 is reserved and expected to be 0x00 (no defined semantics there; the motion/FRC bits live in byte 3, as noted above).

The official DV2 TV SDK v6.0 test vectors confirm this: across CST-DV2, MFV-L11, MFV-L15, MFV-L16, MFV-L18, L11 byte 2 reads 0 in every frame I checked.

That said, in the wild there are streams from third-party encoders (notably some iPhone recordings) where byte 2 is non-zero. quietvoid/dovi_tool relaxed its reserved_byte2 == 0 validation for that reason (PR #384 there), flagging it "TODO: figure out what it means" — no spec-defined meaning has surfaced, and Dolby's own samples don't exercise it, so the conservative read is "reserved per spec, but tolerate non-zero for interoperability."

For MediaInfo I'd suggest: keep byte 2 as a skip today (matching the spec), but don't enforce == 0 either, so real-world files parse cleanly. Happy to do that adjustment here if useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants