Skip to content

feat(probe): validate HDR10+ and add probe limits and cancellation - #583

Merged
superuser404notfound merged 5 commits into
superuser404notfound:mainfrom
brandomoore:brandomoore-aether-probe-safeguards
Sep 21, 2026
Merged

superuser404notfound merged 5 commits into
superuser404notfound:mainfrom
brandomoore:brandomoore-aether-probe-safeguards

Conversation

@brandomoore

@brandomoore brandomoore commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Summary

The HDR10+ scan currently accepts a marker anywhere in packet bytes, so compressed picture data can be mistaken for metadata. The existing HDR10+/Atmos scan budgets do not cover opening, stream analysis or seeking, and cancelling an awaiting Swift task does not stop synchronous probe I/O.

This PR validates actual HDR10+ metadata and adds optional probe-wide limits and cancellation, shared by both detail passes.

What changed

  • Validate HEVC/H.264 SEI, AV1 metadata OBUs and FFmpeg HDR10+ packet side data, including identifiers, lengths and the complete ST 2094-40 payload. Playback and probing use the same validator; Dolby Vision remains the primary format.
  • Add ProbeLimits and ProbeCancellation to URL and custom-reader probes. Input and time budgets cover opening, stream analysis, seeks and both passes; inspection packets share packet-count and packet-size limits.
  • Interrupt HTTP reads and cooperating custom readers. A whole-probe limit or cancellation throws rather than returning partial or late results. Cancelled HTTP requests finish their callbacks before releasing origin slots or returning. Custom readers remain caller-owned and are never closed by the probe.
  • Preserve existing calls' opening policy when neither control is supplied. No changes to normal playback's redirect, cookie or authentication policies.

Limits are cooperative, not hard network or memory caps. Input accounting measures bytes delivered by the reader, not wire traffic; packet-size checks happen after FFmpeg allocation. Custom readers must implement cancellation to unblock I/O, and the probe waits for native work and cleanup before returning. An unconfirmed detail is not proof of absence. Atmos detection remains E-AC-3 JOC, not TrueHD Atmos.

Test plan

  • Local: Apple Silicon, macOS 27, Swift 6.4. swift build and the full test suite passed after incorporating current upstream main. Four HTTP callback-drain regression cases pass with the fix and fail without it. The Xcode 26.3 fixture simplification passed all 41 targeted HDR tests and byte-equivalence checks.
  • Fixtures: synthetic HEVC HDR10/HDR10+ MP4, H.264/AV1 metadata, VP9/AV1 side data, AAC/E-AC-3 and combined tracks; custom readers and local HTTP origins exercise blocked reads, cancellation, budgets and cleanup.
  • All seven CI checks passed on a1d9529b: Xcode 26.3 macOS tests and iOS/tvOS/visionOS Simulator builds, Xcode 27 macOS/tvOS builds, and documentation links. Full CI tests: 3,296 Swift Testing tests and 642 XCTest cases passed; the existing live AES-128 test was skipped because AETHER_LIVE_URL was unset.
  • No physical-device or HDMI verification; this validates source metadata, not display output.

Checklist

  • CHANGELOG.md updated
  • Commit messages follow Conventional Commits
  • The fix lives in the engine, not a host-side workaround
  • Public API changes and limitations documented

brandomoore and others added 3 commits September 20, 2026 22:23
Add opt-in whole-probe input, packet and deadline limits with caller cancellation for URL and custom readers. Validate codec metadata framing and ST 2094-40 payloads before confirming HDR10+, preserving Dolby Vision precedence and positive-only detail semantics.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Exercise oversized read results through real media and assert the exact clamped read and caller ownership. Snapshot completed native seek results outside testing macros.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@brandomoore brandomoore changed the title feat(probe): validate HDR10+ metadata and add shared probe controls feat(probe): validate HDR10+ and add probe limits and cancellation Sep 21, 2026
brandomoore and others added 2 commits September 21, 2026 00:01
Wait for size and finite-range request callbacks before releasing probe origin slots. Cover cancellation and deadlines with isolated callback-queue gates.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Preserve upstream's request-target credential filtering alongside the controlled probe request session and cancellation drain.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@superuser404notfound
superuser404notfound merged commit f55789d into superuser404notfound:main Sep 21, 2026
7 checks passed
@superuser404notfound

Copy link
Copy Markdown
Owner

Merged as f55789d. Thank you for this one, it is a substantial piece of work and the two ideas in it are both right: the validator belongs in the engine and shared by playback and probing, and a probe that reads a hostile source needs bounds the caller sets rather than bounds the engine assumes.

Two things verified here before merging, for the record. The bit accounting in validatedBitCount matches FFmpeg's own av_dynamic_hdr_plus_to_t35 size_bits computation field for field, so the exact-length requirement is the length a conforming ST 2094-40 payload must have and not an extra rule. And the full suite is green locally at real exit code 0, both runners, 3296 swift-testing plus 642 XCTest.

Four follow-ups are in #586, all of the same shape: a bound meant to limit what the probe SPENDS was also deciding what it may REPORT.

  1. The validator discarded a message it had already parsed in full whenever anything later in the same packet failed the structural walk. A valid ST 2094-40 SEI followed by a NAL with its forbidden bit set, or by an SEI missing rbsp_trailing_bits, came back negative, where the byte scan this replaces said yes. That shape is ordinary on real media, and it reaches the playback path through HLSSegmentProducer. The walks now stop at the damage and report what they validated; only validT35 ever sets a positive, so nothing there can invent one.
  2. The HDR10+ and Atmos passes retracted a detection they had already made when the soft wall-clock budget expired mid-pass. On the existing API with no opt-in, an overrun on a slow origin became a silent "no Atmos", which a caller cannot tell apart from a source that carries none. The whole-probe deadline is untouched, since that one throws.
  3. limits also switched the open to the still extractor's profile, so a controlled probe read 2 MiB / 2 s where an uncontrolled one reads 50 MiB / 60 s. It now builds from .playback with probesize clamped to maxInputBytes, so the caller's own numbers are the only thing that binds. The recordless Dolby Vision point was correct and stays as it was; docs/api.md states it in terms of what a host observes.
  4. The origin slot is taken with a wait bounded by the probe's own deadline rather than with tryAcquire, so a probe that merely arrived while another request held the origin no longer fails on the spot.

Tests that encoded the old contracts were rewritten rather than dropped: every case where nothing was validated still fails closed, and the cases where a confirmed message precedes the damage moved to a test that pins the new answer.

@superuser404notfound

Copy link
Copy Markdown
Owner

Released in 7.10.0, together with the #586 follow-ups: https://github.com/superuser404notfound/AetherEngine/releases/tag/7.10.0

Both downstream consumers are already pinned to it. Thanks again for the contribution.

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