Skip to content

Add hdr_mode option: raw code-value decode for HDR sources - #6

Merged
ksindi merged 4 commits into
mainfrom
ksindi/hdr-raw-mode
Aug 3, 2026
Merged

Add hdr_mode option: raw code-value decode for HDR sources#6
ksindi merged 4 commits into
mainfrom
ksindi/hdr-raw-mode

Conversation

@ksindi

@ksindi ksindi commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

HDR and wide-gamut sources, such as PQ, HLG, or BT.2020 content, are currently always passed through a tone-mapping pipeline before decoding: linearize with zscale, apply Hable tone mapping, then convert to BT.709. As a result, float32 output from HDR sources is an SDR preview intended for display, not a faithful representation of the original signal.

That is a problem for use cases that need the original HDR code values, such as training on PQ masters or performing colorimetric measurements. Until now, there was no way to disable tone mapping. On a PQ BT.2020 mezzanine file, for example, the tone-mapped output showed 2.34 times more chroma and higher luminance than the true source values.

The new hdr_mode="raw" option skips the HDR tone-mapping stage. YUV-to-RGB conversion still respects the stream’s tagged matrix and range, but the transfer function is left unchanged. The default, "tonemap", remains byte-for-byte identical to the current behavior.

HDR/wide-gamut sources (PQ/HLG transfer or BT.2020 primaries) are
unconditionally routed through a tone-mapping pipeline (zscale linear ->
hable -> BT.709), so float32 output for HDR content is a display-oriented
SDR preview, not the source signal. Consumers that need the actual HDR
code values (training on PQ masters, colorimetric measurement) had no way
to opt out — measured on a PQ BT.2020 mezzanine, the tone-mapped output
carries 2.34x the chroma and inflated luminance vs the true code values.

hdr_mode="raw" skips the HDR block: YUV->RGB uses the stream's tagged
matrix and range only, and the transfer function is left untouched. The
default ("tonemap") is byte-identical to current behavior.
@upwind-code-us

Copy link
Copy Markdown

Upwind Upwind IaC Scan - 🔍 Scan in progress…

Upwind is scanning this PR. Results will appear here when the scan completes.

@upwind-code-us

Copy link
Copy Markdown

Upwind Upwind Code Scan - 🔍 Scan in progress…

Upwind is scanning this PR. Results will appear here when the scan completes.

@ksindi

ksindi commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

Runtime verification with the built wheel, on the PQ BT.2020 12-bit mezzanine (frame-0 float32 RGB vs an ffmpeg format=gbrpf32le tag-honoring reference of the same file):

mode mean abs diff vs PQ code values chroma ratio frame max
default (tonemap) 0.07059 2.362× 0.833
hdr_mode="raw" 0.00000 1.000× 0.598

raw reproduces the source code values exactly; the default is unchanged. Invalid values error with the accepted set (hdr_mode must be "tonemap" or "raw").

Comment thread avtensor.pyi Outdated
Comment thread src/decoder/mod.rs Outdated

@RikHeijdens RikHeijdens left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a few nits

ksindi added 3 commits July 21, 2026 14:23
A decoder should hand back the signal it decoded. The tone-mapped
default silently corrupted signal-domain consumers (training targets,
measurements), and its failure mode is invisible — plausible tensors
with wrong values — while raw's failure mode in display pipelines is
immediately visible (flat frames). Display consumers opt in with
hdr_mode="tonemap". SDR sources are unaffected by either mode.
@ksindi

ksindi commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

Note on the last two commits: we briefly considered making raw the default, then reverted to keep tonemap as the default after weighing usage: most Runway corpora are SDR with occasional stray HDR files, and for those pipelines tone-mapping strays into the display-referred domain is the correct normalization — a raw default would silently feed washed-out PQ frames to headless SDR pipelines. Signal-domain consumers (HDR training/measurement) are few and deliberate, and opt in explicitly with hdr_mode="raw". Net: the PR remains purely additive with byte-identical default behavior, as approved.

@ksindi
ksindi merged commit f6a1b19 into main Aug 3, 2026
4 checks passed
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