Skip to content

Identify HDR10+ before playback (AE#579) - #580

Merged
superuser404notfound merged 1 commit into
mainfrom
feat/hdr10plus-probe
Sep 20, 2026
Merged

superuser404notfound merged 1 commit into
mainfrom
feat/hdr10plus-probe

Conversation

@superuser404notfound

Copy link
Copy Markdown
Owner

Closes the probe half of #579.

The container declares HDR10+ nowhere. ST 2094-40 rides an in-band ITU-T T.35 SEI that no demuxer parses (only hevcdec surfaces it, post-decode), and the one demuxer that produces packet side data for it is matroskadec, from a BlockAdditional. So the engine only learned HDR10+ while playing, from the segment producer's per-packet scan, and a host badging a title had to wait for that mid-session upgrade or call it HDR10.

What this adds

  • probe(url:options:detecting:atmosDetection:hdr10PlusDetection:) taking a ProbeDetail option set, running the opt-in passes over one open handle. .hdr10Plus scans demuxed video packets for either carriage, .atmos is the bounded JOC decode probeDetectingAtmos already ran, which stays as a spelling of detecting: .atmos. Both at once cost one connection.
  • SourceProbe.carriesHDR10PlusMetadata, and .hdr10 upgrading to .hdr10Plus through the same rule the session applies, in one place so the two cannot drift.
  • The HDR10+ scan runs first and before any seek, so the common case is answered out of the packets find_stream_info already queued, with no further I/O. Bounded by HDR10PlusDetectionOptions (32 packets, 16 MiB, 2 s).
  • The signature scan moved out of HLSSegmentProducer into HDR10PlusMetadataScan; the producer picks up the Matroska side-data carriage it could not see before.
  • aetherctl probe --detect-hdr10plus / --detect-atmos.

Additive only: a cap leaves the base probe's answer untouched, and a negative means "not seen inside the budget", never "proven absent".

Verification

  • 3200 swift-testing tests and 17 XCTest tests green; -strict-concurrency=complete clean; Scripts/check-doc-links.py clean.
  • New coverage: the byte / side-data scan, the stop conditions and cap priority, and ten end-to-end tests against two ~1 KB HEVC / PQ fixtures that differ only in the injected SEI. The negative fixture is the load-bearing one.
  • The positive fixture's payload is built to libavutil/hdr_dynamic_metadata.c's bit layout and the generator only emits the file once ffprobe -show_frames reports HDR Dynamic Metadata SMPTE2094-40 on it.
  • Observed on the CLI: the same file reads format: hdr10 bare and format: hdr10Plus with --detect-hdr10plus, while the SEI-less encode reads not seen.

Not in here: the cdm4 supplemental-codec question, which stays open on #579 because it needs a measurement on a real panel before it gets a route.

🤖 Generated with Claude Code

https://claude.ai/code/session_015PM3xUJB6ZQyqnmGK1fp6F

The container declares HDR10+ nowhere. ST 2094-40 rides an in-band ITU-T T.35
SEI that no demuxer parses (only hevcdec surfaces it, post-decode, as
AV_FRAME_DATA_DYNAMIC_HDR_PLUS), and the one demuxer that produces packet side
data for it is matroskadec, from a BlockAdditional. So the engine only learned
HDR10+ while playing, from the segment producer's per-packet scan, and a host
badging a title had to wait for that mid-session upgrade or label it HDR10.

probe(url:detecting:) takes a ProbeDetail option set and runs the opt-in passes
it names over one open handle: .hdr10Plus scans demuxed video packets for either
carriage, .atmos is the bounded JOC decode probeDetectingAtmos already ran (kept,
now a spelling of detecting: .atmos). Asking for both costs one connection.
The HDR10+ scan runs first and before any seek, so the common case is answered
out of the packets find_stream_info already queued, with no further I/O.

SourceProbe gains carriesHDR10PlusMetadata, and .hdr10 upgrades to .hdr10Plus
through the same rule the session applies, in one place so the two cannot drift.
Both passes are additive: a cap leaves the base answer untouched, a negative
means "not seen inside the budget", never "proven absent".

The signature scan moved out of HLSSegmentProducer into HDR10PlusMetadataScan,
so probe and session agree by construction, and the producer picks up the
Matroska side-data carriage it could not see before.

Tests: two ~1 KB HEVC/PQ fixtures that differ only in the injected SEI, the
positive one carrying a payload ffprobe parses as SMPTE2094-40 (generator in
Scripts/make-hdr10plus-fixture.py verifies that before it emits the file).
aetherctl probe --detect-hdr10plus / --detect-atmos make both passes observable.

Suggested by Geordie.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015PM3xUJB6ZQyqnmGK1fp6F
@superuser404notfound
superuser404notfound merged commit bd6db34 into main Sep 20, 2026
7 checks passed
@superuser404notfound
superuser404notfound deleted the feat/hdr10plus-probe branch September 20, 2026 20:15
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.

1 participant